POST /v1/feedback
Submit a feedback report. Returns the persisted feedback id and its initial status.
POST
/v1/feedbackAuth: publicKey + optional userTokenHeaders
| Name | Type | Description |
|---|---|---|
| Authorization* | Bearer pub_… | App public key. |
| X-Userz-User-Token | JWT | Private-mode token (see Authentication on the API overview). Required if the App has publicSubmissionEnabled: false. |
| Origin | string | Browser Origin. Enforced server-side against the App's allowedOrigins list when that list is non-empty. |
| Content-Type* | application/json |
Body
| Name | Type | Description |
|---|---|---|
| text* | string | The report. 1–8192 characters. |
| severity | "low" | "medium" | "high" | null | Optional severity hint. |
| url | string (URL, ≤2048 chars) | Page the user reported from. |
| userAgent | string (≤512 chars) | Browser UA. Falls back to the request's User-Agent header if omitted. |
| viewport | { w: number; h: number; dpr: number } | Viewport size + device pixel ratio. |
| consoleLogs | ConsoleLogEntry[] | Up to 500 entries. Each: { level, message (≤1000 chars), ts (epoch ms) }. |
| attachments | AttachmentRef[] | Up to 10 references to objects you already uploaded via the upload-url endpoint. Each: { key, kind, contentType, byteSize, width?, height? }. |
| componentTarget | ComponentTarget | Optional targeted component: { name, meta?, bbox?, screenshotKey? }. |
| metadata | Record<string, unknown> | Customer-attached metadata (route, build SHA, feature flags, etc.). Total JSON size ≤4 KB. |
| identity | { email?, name?, externalUserId? } | Self-identifying fields for PUBLIC mode only. Private mode derives identity from the JWT. |
Response (201)
JSON
{
"id": "69e2f2d0ad2f5eef87449d83",
"status": "received"
}Status will progress asynchronously through received → sanitizing → sanitized → …. Subscribe to chat-ops for live progress, or poll the feedback record from your dashboard.
Errors
| Name | Type | Description |
|---|---|---|
| 400 | invalid_body | Zod validation failed; issues array attached. |
| 401 | missing_authorization | No Authorization header. |
| 401 | invalid_authorization | Authorization header malformed. |
| 401 | unknown_app | No App matches that public key (or the App was deleted). |
| 401 | invalid_user_token | X-Userz-User-Token failed signature/exp/app-id verification. |
| 403 | origin_not_allowed | Origin header missing or not on the App's allowedOrigins list (when that list is non-empty). |
| 403 | public_disabled | No X-Userz-User-Token AND publicSubmissionEnabled is false on this App. |
| 429 | rate_limited | Per-mode rate limit exceeded. Retry after the indicated ms. |
Example: public mode
Bash
curl -X POST https://api.userz.ai/v1/feedback \
-H "Authorization: Bearer pub_GLLHdYCLb2A2d9ieY2LmmwRJ" \
-H "Content-Type: application/json" \
-H "Origin: https://app.acme.com" \
-d '{
"text": "Mobile login is broken on iOS Safari",
"severity": "high",
"url": "https://app.acme.com/login",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)",
"viewport": { "w": 390, "h": 844, "dpr": 3 },
"identity": { "email": "[email protected]" }
}'Example: private mode
Bash
curl -X POST https://api.userz.ai/v1/feedback \
-H "Authorization: Bearer pub_GLLHdYCLb2A2d9ieY2LmmwRJ" \
-H "X-Userz-User-Token: eyJhbGciOiJIUzI1NiJ9..." \
-H "Content-Type: application/json" \
-H "Origin: https://app.acme.com" \
-d '{ "text": "Wishlist would be great" }'The end-user identity is derived from the JWT's
sub + ctx claims. Any identity field in the body is ignored in private mode.