Errors
The API reports errors as Problem Details (RFC 9457) with the media type application/problem+json.
Every error from the API has this shape, whatever its status.
HTTP/1.1 400 Bad RequestContent-Type: application/problem+jsonServer-Timing: trace;desc=00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
{ "type": "https://fedwright.com/problems/bad-request", "title": "Bad Request", "status": 400, "traceId": "4bf92f3577b34da6a3ce929d0e0e4736", "errors": { "Idempotency-Key": ["Idempotency-Key must be 8 to 255 characters"] }}Fields
Section titled “Fields”| Field | Always present | Meaning |
|---|---|---|
detail |
No | An explanation specific to this occurrence. Absent for server errors. |
errors |
No | Validation errors, by field path. Each value is a list of messages. |
instance |
No | A URI reference for this occurrence, when the API provides one. |
limit |
No | On a rate-limit error, the quota that is used up. See Rate limits. |
resetsAt |
No | On a rate-limit error, when that quota starts again, as an ISO 8601 time in UTC. |
status |
Yes | The HTTP status code, repeated. |
title |
Yes | A short summary. Don’t match on it; use type. |
traceId |
Yes | The trace ID of the failed request. Quote it when you ask for help. |
type |
Yes | https://fedwright.com/problems/ followed by a code, such as not-found. The same in every environment. |
Decide what to do from status and type. Treat title and detail as text for people. They can
change.
An unexpected failure (500) returns only type, title, status, and traceId.
Validation errors
Section titled “Validation errors”The keys of errors are field paths in the request, such as nested.note, or $ for the body as a
whole. A header has its own name as the key, such as Idempotency-Key. A request that doesn’t
satisfy the contract’s schema is refused with 400 (bad-request) before anything is read or
written. A request whose schema is satisfied but that breaks a further rule, such as an unknown
NAICS code, is refused with 422 (validation-failed).
Trace IDs
Section titled “Trace IDs”Every response, errors and successes alike, carries a Server-Timing header with a trace metric:
Server-Timing: trace;desc=00-{trace-id}-{span-id}-01The {trace-id} part is the error’s traceId. If a response has no Problem body, for example one
from a proxy in front of the API, read the trace ID from this header when it is there. Include the
trace ID, the time of the request, and the path when you ask for support. Don’t include tokens.
Problem types
Section titled “Problem types”| Type | Status | When |
|---|---|---|
ai-budget-exceeded |
429 | An ask that the organization’s AI spending budget can’t cover. Retry-After gives the wait. |
ai-unavailable |
503 | An ask can’t run now, and nothing was charged. Retry after Retry-After seconds. |
bad-request |
400 | The request is malformed or its schema refuses it. Also any other client mistake, such as an unsupported method or media type. |
billing-unavailable |
503 | Paid plans can’t be used now. Nothing was changed. |
client-not-allowed |
403 | The operation isn’t open to the caller’s kind of client, such as a machine client calling a user-only operation. |
conflict |
409 | The request conflicts with the resource’s current state, such as a slug that another organization has. |
email-unverified |
403 | Creating or joining an organization needs a verified email address. |
forbidden |
403 | Any other refusal. It says nothing more. |
idempotency-in-progress |
409 | The first request with this Idempotency-Key is still running. See Idempotency. |
idempotency-key-reused |
422 | The Idempotency-Key was already used for a different request. |
insufficient-role |
403 | A member’s roles don’t allow the action. |
insufficient-scope |
403 | The token’s client lacks the operation’s scope. WWW-Authenticate names the missing scopes. |
internal-error |
500 | An unexpected failure. |
invalid-cursor |
400 | The cursor was altered, expired, or was issued for a different query. See Pagination. |
invitation-email-mismatch |
403 | An invitation was sent to another address. |
last-owner |
409 | The change would leave an organization with no owner. |
mail-unavailable |
503 | An invitation can’t be sent now. Nothing was created. |
mfa-required |
403 | An owner or administrator sent no proof of a second factor. |
no-billing-account |
409 | The billing portal was requested for an organization that has never paid. |
not-found |
404 | The resource doesn’t exist, or belongs to another organization. |
organization-required |
403 | A session of Fedwright’s web or mobile app that acts for no organization yet. |
organization-suspended |
403 | Fedwright suspended the organization. |
payload-too-large |
413 | The request body is over 64 KiB. |
precondition-failed |
412 | If-Match is stale. See Conditional requests. |
premium-quota-exceeded |
429 | An ask that the organization’s premium units for the day can’t cover. See Rate limits. |
rate-limited |
429 | A rate limit is used up. See Rate limits. |
request-timeout |
503 | The request took longer than 10 seconds (90 for askOpportunities). |
search-unavailable |
503 | Search is temporarily unavailable. Retry after Retry-After seconds. |
subscription-exists |
409 | A checkout was started for an organization that already has a paid subscription. |
subscription-inactive |
403 | The operation needs an active subscription and the organization has none. |
unauthorized |
401 | The access token is missing, expired, or invalid, or the caller was disabled or revoked. WWW-Authenticate: Bearer is set. |
validation-failed |
422 | The request is well formed but breaks a rule beyond its schema. errors names each field. |
Another organization’s resource is 404, not 403, so a response never confirms that it exists.
Which errors to retry
Section titled “Which errors to retry”| Answer | Retry? |
|---|---|
429 |
Yes, after the wait the response gives. It is returned before the operation runs, so a retry can’t repeat an effect. See Rate limits. |
409 idempotency-in-progress |
Yes, with the same Idempotency-Key, after Retry-After. |
503 with Retry-After (search-unavailable, ai-unavailable) |
Yes, after the wait. Nothing was charged. |
503 request-timeout, 502, 504, a dropped connection |
Only if the call is safe to repeat: a GET, a PUT, a DELETE, or a POST with an Idempotency-Key. |
401 |
Once, with a new token. See Authentication. |
Any other 4xx |
No. Change the request. |
When a call is safe to repeat and the answer has no Retry-After, wait a short time that grows
with each attempt, with random jitter, and stop after a few attempts.