Transient vs. Permanent Failures
Before retrying, determine whether the failure is recoverable.Only retry on transient failures (4xx rate limits and 5xx server errors). Retrying permanent failures wastes your rate limit budget and will never succeed.
Exponential Backoff with Jitter
The standard retry strategy for transient errors. Each retry waits longer than the previous one, with random jitter to avoid thundering-herd problems when many clients retry simultaneously. Algorithm:TypeScript
Retry Backoff Schedule
With the default settings (base_delay=1s, max_retries=3), the schedule looks like this:
For
429 responses, the Retry-After header overrides the calculated base delay. Always respect this value.
Bulk Operation Retry
POST /v1/trademarks/batch does not return a per-item success or error status. A requested ID either resolves into the data array (as a full trademark) or, if it does not match anything, into the not_found array. There is no partial-item failure to retry inside a single batch call, since a lookup either finds a record or it does not.
What can still fail is the request as a whole: a 429 if you are over your rate limit, or a 5xx if the API is having trouble. In that case, retry the whole batch with the standard backoff strategy from the section above:
TypeScript
Circuit Breaker Pattern
For high-throughput integrations, wrap your API calls in a circuit breaker to stop sending requests when the API is consistently failing. This protects both your application and the API from cascading failures. The circuit has three states:- Closed (normal): Requests flow through. Failures are counted.
- Open (tripped): All requests fail immediately without contacting the API.
- Half-open (probing): A single test request is sent. If it succeeds, the circuit closes; if it fails, it re-opens.
Request Timeouts
Always set explicit timeouts on API calls. A reasonable default for Signa endpoints:Idempotent Requests
Mutation endpoints (PATCH, DELETE, and non-exempt POST, see Exempt Endpoints) require an Idempotency-Key header. This guarantees that if a request is retried, whether because of a network timeout, a dropped connection, or an ambiguous failure, the operation only executes once.
How It Works
- On the first request with a given key, the API processes the request normally and caches the response.
- If the same key is sent again with the same request body, the API returns the cached response without re-executing the operation. Replays carry an
Idempotent-Replayed: trueresponse header and preserve the originalrequest_id(in the body and onx-request-id), so you can tell a cached replay from a fresh execution. - If the same key is sent with a different body, the API returns
409 conflict, each key is bound to a specific request body. - If the same key is sent while the first request is still in flight, the API returns
409 idempotency_processing, wait for the original to complete, then retry with the same key to get its cached result.
Only successful (2xx) responses are cached. Client errors (4xx) and server errors (5xx) are never cached, so if a request fails, you can safely retry with the same idempotency key without being pinned to the error.
Key Format
- 1-255 characters
- Alphanumeric, dashes, and underscores only (
[a-zA-Z0-9_-]) - Must be unique per operation, use UUIDs, request identifiers, or a deterministic string derived from the operation (e.g.,
create-api-key-{name}-{timestamp})
Exempt Endpoints
Read-shaped POST endpoints are exempt by design from theIdempotency-Key requirement. They exist as POSTs only because their query bodies are too large or complex for a URL, and they create nothing. Sending a key is harmless (the value’s format is still validated, a malformed key returns 400 even here), but the middleware will not enforce or replay it.
Every other mutating endpoint (
PATCH, DELETE, and any non-exempt POST) requires Idempotency-Key and will return 400 validation_error if it is missing.
Example: Safe Retry Pattern
The example below demonstrates a retry loop againstPATCH /v1/organization/api-keys/{id} (renaming a key), which is enforced by the idempotency middleware.
TypeScript