Requests, responses and errors
Base URL
All endpoints live under
https://api.deepersignals.com/api/external
Paths in this documentation are shown relative to that base, so GET /users/{user_id} means GET https://api.deepersignals.com/api/external/users/{user_id}.
JSON
- Send request bodies as
application/jsonwithContent-Type: application/json, except the CSV upload endpoint which takesmultipart/form-data. - Responses are JSON, except PDF downloads which stream
application/pdf. - Identifiers (
id,user,team,campaign, library ids) are integers. - Booleans are real JSON booleans. Omitted optional fields are left unchanged on update endpoints (
PATCH/PUT) and take their default on create. - Timestamps are returned as
YYYY-MM-DD HH:MM:SSin UTC on the older user and team endpoints, and as ISO 8601 with offset (2026-10-01T09:12:00+00:00) on the campaign, assessment and report endpoints added in 2026.
Status codes
| Code | Meaning |
|---|---|
200 | Success. |
201 | Created, or a state switched on (for example a report made visible). |
202 | Accepted; work continues in the background (for example invitation e-mails are being sent). |
204 | Success with no body (deletes). |
400 | The request is not valid for this account: duplicate e-mail (exception.email.taken) or employee id (exception.user.employeeIdTaken, data.field: employee_id), invalid table query. |
401 | Missing or wrong API token. |
403 | The resource belongs to another account, or a feature is not enabled on yours. |
404 | Unknown resource. |
409 | The action conflicts with the current state (for example a PDF of a report whose assessments are not completed). |
422 | Validation failed; message names the first failing rule. |
429 | Rate limit exceeded, see Rate limits. |
5xx | Something went wrong on our side. Retry with backoff and contact support if it persists. |
Error envelope
Errors are JSON objects with a code (same as the HTTP status) and a human-readable message:
{ "code": 403, "message": "Not allowed, insufficient permissions." }
Some errors carry more detail:
trans_code— a stable machine-readable key (for exampleexception.report.notReady). Match on this, not onmessage.data— context for the error, such aspending_assessment_library_idsfor a report that is not ready.details— for invalid table queries, the constraints that were violated.
Validation errors (422) report the first rule that failed in message:
{ "code": 422, "message": "assigned_user_report is required." }
Pagination
List endpoints are table queries: a POST with a JSON body naming columns, filters, sort, pagination (limit up to 500, page from 1) and an optional search term q. They answer with items, total and pages:
{ "items": [ ... ], "total": 243, "pages": 3 }
This applies to users (/users/table), teams (/team/table, /team/{team_id}/members/table), campaigns (/campaigns/table) and campaign participants (/campaigns/{campaign_id}/users/table). Every page carries total and pages; team members also have a /count variant, and each table has a columns endpoint that lists what can be selected. See Table queries.
Catalog endpoints (/assessment_libraries, /reports, /playbook) and per-user lists (/users/{user_id}/assessments, /users/{user_id}/reports) return plain JSON arrays without pagination.
Locales
Reports and share links can be rendered in the user's language. Pass the locale as the {locale} path segment; en is the default. The same codes are accepted as locale when creating or updating a user.
GET /locales returns the locales currently enabled on the platform (code, name, right_to_left); use it rather than hard-coding the list. At the time of writing:
| Locale | Language |
|---|---|
en | English |
de | German |
fr | French |
it | Italian |
es-ES | Spanish (Spain) |
es-419 | Spanish (Latin America) |
pt-BR | Portuguese (Brazil) |
bg | Bulgarian |
Not every report exists in every language. A locale the report does not support falls back to English.
Idempotency and retries
GET and DELETE are safe to retry. PUT on a participant's assessment or report is idempotent (200 when nothing changed, 201 when it switched on). POST endpoints that create users, teams, campaigns or send invitations are not idempotent; retry them only after checking the state with the matching GET.