Skip to main content
Every Signa API error follows a consistent structure inspired by RFC 9457. Errors are wrapped under an "error" key with machine-readable fields for programmatic handling.

Error Response Structure


Error Catalog

entity_too_large carries an error.reason discriminator so you can branch without parsing the message: member_owners_too_large means the entity or group resolved to more member owners than the cap (the error also carries member_count and member_count_limit), and family_graph_too_large means the GLEIF family-graph walk exceeded its node or depth bound before owners were counted, which only fires on ?entity_group= (the error carries related_entity_limit and depth_limit). Either way, narrow the query with additional filters, query a specific member directly, or use ?entity_id= for a single entity instead of ?entity_group=; the caps bound fan-out cost and are not retryable as-is.

Edge-generated errors

A small set of errors is generated at the edge (CDN and security layer), before the request reaches the API. They use the same JSON envelope, with three differences:
  • request_id is a static sentinel: the edge cannot mint per-request IDs. Security blocks, oversized payloads, and edge rate limits use req_unknown; the static 502/503 pages served when the API origin is unreachable use req_edge_static_502 and req_edge_static_503.
  • The instance and suggestion fields are omitted: the edge cannot know them for your specific request.
  • To correlate an edge error with support, quote the x-amz-cf-id response header and the timestamp of the request instead of a request_id.
Edge-generated errors you may see: edge_rejected (403), payload_too_large (413, for bodies over 8 KB on any endpoint except image upload), rate_limited (429, when the edge rate limit trips before the API’s own limiter), and static bad_gateway (502) / service_unavailable (503) pages when the API origin is unreachable.
A few edge cases return HTML, not JSON. A request URI longer than the CDN’s length cap returns 414 with an HTML body. Oversized or malformed request headers return 400 with an HTML body (from the load balancer), or 494 with an HTML body when they exceed the CDN’s larger header cap. These responses come from infrastructure request parsers and cannot be converted to the JSON envelope. If you hit one with a request you believe is valid, email support@signa.so with the x-amz-cf-id response header (when present) and the timestamp.

Handling Errors

Errors return non-2xx status codes. The response body contains a structured error object and a top-level request_id, with the HTML exceptions noted in Edge-generated errors above (oversized URIs return 414, and oversized or malformed headers return 400 or 494, all with HTML bodies). Robust clients check the Content-Type header before parsing the body as JSON.
The TypeScript SDK exposes typed error classes for each status code. See the TypeScript SDK reference for instanceof patterns and automatic retries.

Reporting a persistent server error

Server faults (500 internal_error, 502 upstream_error, 503 service_unavailable, 504 timeout) carry a suggestion that points you at the feedback channel. If retrying with backoff does not clear the error, submit it to POST /v1/feedback with the response’s request_id. Signa snapshots the matching request log onto the report, so the team can investigate exactly what you hit. Client errors (4xx) never carry this hint, they are fixed on your side by correcting the request. See Submit Feedback for the full flow.

Idempotency and 409 Conflict

Mutating requests (PATCH, DELETE, and non-exempt POST) require an Idempotency-Key header (1-255 characters of [A-Za-z0-9_-]):
A key is bound to the exact request it first executed: the request URL and the request body. Same key + same URL + same body = cached response replayed (safe to retry). Replays carry an Idempotent-Replayed: true response header and preserve the original request_id. Same key + different body, or the same key against a different URL = 409 conflict error. Reusing one key across DELETE /v1/watches/wat_1 and DELETE /v1/watches/wat_2 conflicts rather than replaying the first delete — generate a fresh key for each distinct request. Same key while the first request is still in flight = 409 idempotency_processing: wait for the original to finish, then retry. Idempotency keys are scoped to your organization and expire after 24 hours. Only successful (2xx) responses are cached, so a failed request never pins you to its error.
A handful of read-shaped POST endpoints are exempt by design: they exist as POSTs only because their query bodies are too large or complex for a URL, and they create nothing:
  • POST /v1/trademarks (search)
  • POST /v1/trademarks/batch (batch lookup)
  • POST /v1/suggest (and other suggest endpoints)
  • POST /v1/watches/preview (dry-run match count)
  • POST /v1/alerts/lookup (bulk read by IDs)
On exempt endpoints the header is optional and not replayed, but if you do send one, its format is still validated (1-255 characters of [A-Za-z0-9_-]); a malformed value returns 400 even there.
POST /v1/organization/api-keys and POST /v1/organization/api-keys/{id}/rotate are not exempt. Replay is the correct semantic for endpoints that mint one-time secrets: retrying the same Idempotency-Key returns the same secret instead of minting a second credential.
See Resilience and Retries → Idempotent Requests for the full exemption list and a worked retry example.

Troubleshooting by Symptom

Check your Authorization header format. It must be Authorization: Bearer sig_YOUR_KEY (with the Bearer prefix). Common mistakes:
  • Missing Bearer prefix: Authorization: sig_YOUR_KEY
  • Wrong key prefix: only keys of the form sig_{48 hex chars} are accepted. Any other prefix is rejected with 401 before any database lookup.
  • Expired key: check expires_at on your API key
  • Revoked key: check the API key status in your dashboard
Your API key is valid but does not have the required scope for this endpoint. Each endpoint requires specific scopes:
  • Trademark search, list, and entity GET endpoints need trademarks:read
  • The event feed (/v1/events) needs events:read
  • Watches, alerts, webhooks, and portfolios need portfolios:manage
  • API key management needs api-keys:manage
  • Usage, plan, and log endpoints need billing:read
Create a new key with the needed scopes or update your existing key.
Common causes:
  • Missing required filter: GET /v1/trademarks requires at least one filter (no unscoped list queries).
  • Wrong date format: Use ISO 8601 (2026-03-24 or 2026-03-24T12:00:00Z).
  • Array syntax: Bracketed keys (e.g. offices[]=US) are not accepted; repeated keys (e.g. offices=US&offices=EM) are accepted as a fallback, but the canonical form is comma-separated (offices=US,EM).
  • Date range syntax: Use flat underscore operators, not brackets: ?filing_date_gte=2020-01-01&filing_date_lt=2025-01-01.
  • Boolean values: Only the literal strings true and false are accepted. 1, 0, yes, no, and TRUE all return a validation error.
  • application_number without office: When filtering by application_number or registration_number, you must also specify office.
  • Missing Idempotency-Key: Mutating requests (PATCH, DELETE, and non-exempt POSTs) require this header. Read-shaped POSTs (search, batch, suggest, watch preview, alert lookup) do not.
Entity resolution runs periodically. When two owner records are identified as the same entity, one is merged into the other. The 410 response includes a merged_into field pointing to the canonical record.Update your cached ID to the new one. All trademarks previously associated with the old owner are now under the canonical record.Resolved entities (ent_*) can also 410. When two resolved entities are fused, the loser’s ent_ id returns 410 entity_merged with the successor in merged_into: follow that field to the canonical record. An entity id for an owner that has since been linked to a company profile does not 410; it transparently resolves to the real entity (the returned id may differ from the one you requested).
This is expected behavior due to the eventual consistency model. Search results are eventually consistent (typically under 30 seconds lag after a write), while detail endpoints are immediately consistent.If you just updated a record, wait a few seconds and retry the search. For time-sensitive workflows, use the detail endpoint as the source of truth.
For bulk lookups, use Batch Retrieve (up to 100 IDs per request) instead of individual GET requests. This counts as one request against your rate limit.For search-heavy workloads, consider caching results on your side, using cursor pagination instead of re-executing searches, or upgrading your plan.
This indicates a transient backend issue. The error is retryable: wait for the retry_after period and retry with exponential backoff. If 503 errors persist for more than a few minutes, email support@signa.so with a request_id from one of the failed calls.