LeadRails

Error types

Every non-2xx response from the LeadRails v1 API is an RFC 9457 problem document with a stable type URL. The type URLs are the machine-readable identifier — pin against them in your client code. The title field is human-readable copy and may change.

Building an integration that sends lead events? Most of these errors come from a hand-rolled client getting the headers, idempotency key, or HMAC signature wrong. Don't hand-roll it — use @leadrails/sdk, which computes every required header, the canonical signing base string, and the idempotency key for you, so the integration in your repo is a typed function call. See the Server SDK page.

Shape of a problem response

HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{
  "type": "https://docs.leadrails.dev/errors/not-found",
  "title": "Resource not found",
  "status": 404,
  "detail": "No source with id src_01J5Z7N9X3M2VWPQ9YTBN2F0HR in this workspace.",
  "instance": "/v1/sources/src_01J5Z7N9X3M2VWPQ9YTBN2F0HR",
  "request_id": "req_01J5Z7T7M3M2VWPQ9YTBN2F0HR"
}

Always include request_id when reporting an issue. It is the single fastest way for us to find your request in the logs.

All problem types

Each row is anchored — link directly to https://docs.leadrails.dev/errors/<slug> and you'll land on the right row.

Slug / status When Fix
Invalid API key
invalid-api-key
HTTP 401
The Authorization header is missing, malformed, or carries a revoked / unknown key. Confirm the header looks like `Authorization: Bearer lr_live_<rest>`. If it does, the key is revoked or wrong — generate a new one at Settings → API keys. Learn more: Authentication →
Resource not found
not-found
HTTP 404
The resource ID is well-formed but does not exist in your workspace. Cross-workspace IDs look identical to missing IDs and resolve here. Verify the ID by listing the parent collection. If the ID came from another workspace, you cannot use it here.
Invalid pagination cursor
invalid-cursor
HTTP 400
The `cursor` query parameter could not be decoded. Cursors are opaque — only pass back what the API returned in `next_cursor`. Drop the `cursor` parameter to start from the beginning, or pass the exact value from a previous `next_cursor` response.
Invalid query parameter
invalid-parameter
HTTP 400
A query parameter failed validation — out of range, wrong type, or in an unexpected format. Check the parameter against the schema in the API reference. The `detail` field names the offending parameter.
Invalid reference
invalid-reference
HTTP 400
A POST/PATCH body references an ID (source_id, destination_id, ...) that exists but belongs to a different workspace, or does not exist at all. Re-fetch the IDs from the corresponding list endpoint. Make sure every referenced resource lives in the same workspace as the API key.
Invalid destination adapter type
invalid-adapter-type
HTTP 400
The `adapter_type` field on a destination create/update is not one of the known adapter slugs. Pick a supported `adapter_type` from the API reference (`slack_webhook`, `generic_webhook`, `n8n_webhook`, `housecall_pro`, `gohighlevel`, ...).
Idempotency-Key header required
idempotency-key-required
HTTP 400
POST or PATCH was called without an `Idempotency-Key` header. The header is required on every state-changing request. Generate a fresh UUID per logical operation and send it as `Idempotency-Key: <uuid>`. Retries with the same key + body return the original result. The @leadrails/sdk derives and sends this header for you. Learn more: Idempotency →
Idempotency-Key too long
idempotency-key-too-long
HTTP 400
The `Idempotency-Key` header exceeds 255 characters. Use a UUID (36 chars) or a short opaque token. Keys longer than 255 bytes are rejected to bound storage. Learn more: Idempotency →
Idempotency-Key conflict
idempotency-conflict
HTTP 422
The same `Idempotency-Key` was reused with a different request body. The first body is held for 24 hours; a second request with that key must match byte-for-byte. Generate a new `Idempotency-Key` for the changed request. Reuse the original key only when retrying the exact same body. Learn more: Idempotency →
Plan required
plan-required
HTTP 403
The endpoint requires a Pro+ plan and the API key belongs to a Starter workspace. `/v1/events` is the current Pro+ gate. Upgrade in the dashboard under Billing. The same data is available in the in-app Events view on every plan.
Rate limit exceeded
rate-limit-exceeded
HTTP 429
Per-key rate limit was hit. The `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` response headers describe the window. Back off until `RateLimit-Reset` seconds have passed, then retry. Honor `Retry-After` on 429s. For sustained throughput, contact us — we can lift the limit per key. Learn more: Rate limits →
Test-mode key not available
test-mode-not-available
HTTP 501
A key with the `lr_test_` prefix was used. The `lr_test_` namespace is reserved for a future test-mode tier that has not shipped. Use a live key (`lr_live_<rest>`) from your workspace. Test-mode arrives in a future release; this slug is the forward-compat placeholder. Learn more: Authentication →
Unsafe outbound URL
unsafe-url
HTTP 422
A destination config (webhook_url, callback_url, ...) points at a private network, an unsupported scheme, or otherwise fails the safe-outbound-URL check. The check runs at write time AND at delivery time. Use a public HTTPS URL. Private IPs (10.x, 192.168.x, 127.x, etc.), link-local addresses, and non-HTTP(S) schemes are all rejected.
Schema validation failed
schema-validation-failed
HTTP 422
A POST/PATCH body failed top-level schema validation. The specific field errors are returned in the `issues` extension member (each with a `path` and `message`). Walk the `issues` array — each entry names the offending field path and why it failed. Correct those fields and resend with the same `Idempotency-Key`.
Invalid destination config
invalid-destination-config
HTTP 422
The `config` object on a destination create/update failed the adapter-specific schema for its `adapter_type` (e.g. a Slack destination missing `webhook_url`). The per-field problems are in the `issues` extension. Check the `config` shape for the chosen `adapter_type` in the API reference, fix the fields named in `issues`, and resend.
Test variable validation failed
variable-validation-failed
HTTP 422
A test-send request supplied template variables that do not satisfy the destination template's variable contract (a required output is missing or a supplied value is the wrong shape). Provide every variable the template declares, with values matching its contract. The `detail` and any `issues` extension name what was missing or invalid.
Unsafe outbound URL
unsafe-outbound-url
HTTP 422
A URL field inside a destination `config` failed the SSRF guard at write time — a defence-in-depth re-check on top of the adapter schema. The offending field and reason are in `detail`. Use a public HTTPS endpoint. Private IP ranges (10.x, 192.168.x, 127.x), link-local addresses, and non-HTTP(S) schemes are rejected for every config URL field.
Request in progress
idempotency-in-progress
HTTP 409
A concurrent request with the same `Idempotency-Key` is still being processed. The first call has not finished, so the result is not yet available to replay. Wait for the first request to complete, then retry with the same key to receive the original result. Do not fire concurrent requests that share an `Idempotency-Key`. Learn more: Idempotency →
Route cap exceeded
route-cap-exceeded
HTTP 402
Creating (or activating a paused) route would exceed the number of active routes your plan allows. The `cap`, `current`, `plan_slug`, and `upgrade_url` are returned as extension members. Remove or pause an existing active route, or upgrade your plan via the `upgrade_url` in the response, then retry.
Refresh rate-limited
refresh-rate-limited
HTTP 429
A destination template-manifest refresh was requested again too soon. Refreshes are throttled per destination; the `retry_after_seconds` extension says how long to wait. Wait `retry_after_seconds` (also reflected in `Retry-After`) before refreshing this destination's template manifest again. Learn more: Rate limits →
Adapter does not support template refresh
adapter-does-not-support-template-refresh
HTTP 422
A template-manifest refresh was requested for a destination whose `adapter_type` has no provider-side template manifest to refresh. Only call refresh on adapters that expose a provider-side template manifest. For other adapter types there is nothing to refresh — manage their config directly.
Service unavailable
service-unavailable
HTTP 503
The API is temporarily unable to serve the request (e.g. a backing dependency is unhealthy or a server-side safety guard tripped). This is transient and not caused by your request body. Retry with exponential backoff. If it persists, check the status page and email support@leadrails.dev with the `request_id`.
Internal server error
internal-error
HTTP 500
The API hit an unexpected exception. The `request_id` field in the response is the key to look up the request in logs. Retry with backoff. If it persists, email support@leadrails.dev with the `request_id` — that's the fastest path to a root cause.

Versioning

The type URLs are stable identifiers and will not change for the v1 surface. New problem types may be added; existing slugs will not be repurposed. If a slug is ever retired, this page will keep redirecting to a successor and the API will emit the successor going forward.