Errors
Every error has the same shape. Branch on code, show detail to a person, and quote request_id to support.
{
"detail": "A sentence a person can read.",
"code": "ERR_VALIDATION",
"request_id": "the id to quote to support",
"errors": [{ "field": "name", "code": "...", "message": "..." }]
} errors appears on validation errors, with one entry per field. Every response also carries X-Request-Id. Codes are stable; new ones may be added, so treat an unknown code by its HTTP status.
Codes
| Code | Status | When | What to do |
|---|---|---|---|
ERR_TENANT_HEADER | 400 | X-Tenant-Id is missing or not a UUID. | Send the account id given with the key, or use a Bearer credential, which does not need it. |
ERR_ACTOR_INACTIVE | 401 | The user this credential acts as is no longer active. | An admin assigns the key to another user in Settings, Integrations. |
ERR_AUTH_INVALID_KEY | 401 | The key or token is malformed, unknown or wrong. | Check the value was copied whole from Settings, Integrations. |
ERR_AUTH_KEY_REVOKED | 401 | The key was revoked or switched off. | Create a new key in Settings, Integrations. |
ERR_AUTH_MISSING_KEY | 401 | No credential was sent. | Send X-Api-Key or Authorization: Bearer. |
ERR_WRONG_ENVIRONMENT | 401 | A sandbox key was sent to the live API, or a live key to the sandbox. | Use the base URL that matches the key: api.woodsystems.com for wsk_live_, api-sandbox.woodsystems.com for wsk_test_. |
ERR_QUOTA_EXCEEDED | 402 | The month's calls are used up and no more can be billed. | Add a payment method or raise the cap under Settings, Billing. |
ERR_ACCOUNT_SUSPENDED | 403 | The account is suspended. | The account owner settles billing under Settings, Billing. |
ERR_FORBIDDEN | 403 | The account service refused the call. | Read detail. |
ERR_NOT_ENTITLED | 403 | The account does not include the API. | The account owner adds API & Integrations under Settings, Billing. |
ERR_OAUTH_NOT_ALLOWED | 403 | Connected apps cannot do this. | Use the WoodSystems web app, or an API key for this call. |
ERR_ROLE_REQUIRED | 403 | The user the credential acts as has a role below what this call needs. | Ask an admin to raise their role, or assign the key to a user with the role. |
ERR_SANDBOX_ONLY | 403 | This call exists only in the sandbox. | Use the sandbox base URL. |
ERR_SCOPE_MISSING | 403 | The credential does not hold the permission this call needs. | Add the named scope to the key, or reconnect the app with it. |
ERR_TENANT_MISMATCH | 403 | The key belongs to a different account than X-Tenant-Id names. | Check that the key and the account id came from the same place. |
ERR_NOT_FOUND | 404 | No such record in this account. | Check the id; records of other accounts are never visible. |
ERR_CONFLICT | 409 | The change conflicts with the record's current state. | Read the record again and retry. |
ERR_DELETE_BLOCKED | 409 | The record cannot be deleted while other records depend on it. | Read detail for what depends on it. |
ERR_FEATURE_OFF | 409 | The account has this area switched off. | Switch it on under Company Config. |
ERR_IDEMPOTENCY_IN_PROGRESS | 409 | A call with this Idempotency-Key is still running or never finished. | Wait and retry; or retry with a new key after checking whether the record exists. |
ERR_LOCKED | 409 | The record is locked: a sent or signed document, a payroll-locked day, a scheduled event. | Change it in the web app, where the lock can be lifted. |
ERR_NO_MAILBOX | 409 | The user the credential acts as has no connected mailbox to send from. | That user connects Gmail or Outlook under Profile settings, Personal Inbox, Send email as me. |
ERR_OVER_RECEIPT | 409 | More was received than is still outstanding on the purchase order line. | Receive at most the outstanding quantity named in detail. |
ERR_IDEMPOTENCY_MISMATCH | 422 | This Idempotency-Key was used with a different request body. | Use a new Idempotency-Key for a new request. |
ERR_IDEMPOTENCY_REQUIRED | 422 | This write needs an Idempotency-Key header. | Send a unique string per submission, such as a UUID. |
ERR_VALIDATION | 422 | The request body or query is not valid. | Read errors for each field. |
ERR_RATE_LIMITED | 429 | Too many calls in a short time. | Wait for Retry-After seconds; read X-RateLimit-Remaining. |
ERR_INTERNAL | 500 | Something failed on our side. | Quote request_id to support. |
ERR_SEND_FAILED | 502 | The mail provider refused or failed the send. | Read detail for the provider's reason; reconnect the mailbox if it says so. |
ERR_UPSTREAM | 502 | The account service could not complete the call. | Retry with backoff; quote request_id to support if it persists. |
ERR_LIMITER_UNAVAILABLE | 503 | The rate limiter could not record the call, so it was not made. | Retry after Retry-After seconds; quote request_id to support if it persists. |
ERR_UPSTREAM_TIMEOUT | 504 | The account service took too long. | Retry with backoff. |