API reference
API reference: POST /api/feedback
Create one feedback item. This is the same endpoint the widget uses, and it is open to direct calls from any language.
Request
Endpoint
POST https://usero.io/api/feedback
Content-Type: application/json- CORS:
Access-Control-Allow-Origin: *. Call it straight from browsers, mobile apps, desktop apps, or servers. - Auth: the
clientIdin the body identifies your project. No API key, no auth header. - Abuse control: if your client has a domain allowlist configured in Settings, requests from other origins get a
403. New clients have no allowlist, so everything is accepted.
Required fields
clientId is always required. rating and comment are each optional, but every submission must include at least one of them: a
rating (1 to 4), a non-empty comment, or both. Everything else is optional.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
clientId |
string | yes | Your project id, starts with client_. See Find your clientId. |
rating |
integer | one of rating / comment | 1 to 4: 1 Terrible, 2 Bad, 3 Good, 4 Amazing. |
comment |
string | one of rating / comment | Free-text feedback. Must be non-empty if no rating is sent. |
userEmail |
string | no | The submitter's email, must be a valid address. Lets you reply and groups feedback by person in the dashboard. An empty string is treated as absent. |
pageUrl |
string | no | URL the feedback was given on. If omitted, the server falls back to the Referer header. |
pageTitle |
string | no | Title of the page the feedback was given on. |
referrer |
string | no | The page the user arrived from. |
environment |
string | no | Optional. Omit it unless you separate environments like production and staging; feedback without it lands in your default inbox. |
screenshots |
array | no | Screenshot objects returned by POST /api/screenshots. Each item: fileName (string), url (string), fileSize (number), mimeType (string), width (number, optional), height (number, optional). |
metadata |
object | no | Arbitrary JSON attached to the feedback, 10KB max when serialized. Good place for app version, OS, build number, or feature flags. |
sessionReplayId |
string | no | 1 to 128 characters. Links the feedback to a session replay recorded by @usero/sdk session replay. |
replayOffsetMs |
integer | no | Non-negative millisecond offset into the linked replay at which the feedback was given. |
Examples
Minimal submission:
curl -X POST https://usero.io/api/feedback \
-H "Content-Type: application/json" \
-d '{"clientId": "YOUR_CLIENT_ID", "rating": 3}'Full-field submission:
curl -X POST https://usero.io/api/feedback \
-H "Content-Type: application/json" \
-d '{
"clientId": "YOUR_CLIENT_ID",
"rating": 2,
"comment": "Export to CSV times out on large projects",
"userEmail": "jamie@example.com",
"pageUrl": "https://yourapp.com/projects/42/export",
"pageTitle": "Export project",
"referrer": "https://yourapp.com/projects/42",
"environment": "staging",
"metadata": {
"appVersion": "2.4.1",
"os": "macOS 15.2",
"build": 1842
}
}'For native apps, metadata is the place for app version, OS version, and build number, so every report arrives with the context
you need to reproduce it.
Response
Success:
json
{ "success": true, "feedbackId": "abc123" }Errors
| Status | Body | Meaning and fix |
|---|---|---|
| 400 | {"error": "Invalid data provided", "issues": {"rating": ["..."]}} |
Validation failed. issues names each failing field. The most common cause: neither rating nor a non-empty comment was sent. |
| 400 | {"error": "Metadata too large (max 10KB)"} |
Serialized metadata exceeds 10KB. Trim it. |
| 403 | {"error": "Domain not allowed"} |
Your client has a domain allowlist and this request's origin is not on it. Add the origin in Settings, or clear the allowlist. |
| 500 | {"error": "Internal server error"} |
Something broke on our side. Safe to retry. |
Related
- Screenshot uploads: two-step flow to attach images
- Session replay: where
sessionReplayIdcomes from - Find your clientId