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
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. On top of that, every submission needs 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 | Tags the feedback with an environment (for example staging). See the warning below before sending this. |
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 the session replay plugin. |
replayOffsetMs |
integer | no | Non-negative millisecond offset into the linked replay at which the feedback was given. |
Warning
Omit environment for your default environment. Do not send a placeholder like "no-env" or "default". The
dashboard treats an absent environment as the default; a literal placeholder string creates a separate environment and your
feedback will not appear in the default inbox.
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:
{ "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 plugin: where
sessionReplayIdcomes from - Find your clientId