Error Handling
Error envelopes, status codes, request IDs, and throttling behavior across Steve's external API.
Every /api/v1 route uses RFC 9457 Problem Details for non-2xx responses.
Steve returns RFC 9457 Problem Details as application/problem+json across workflow, job, company, submission, fraud, and webhook-test endpoints.
Example:
Field meanings:
| Field | Meaning |
|---|---|
type | Machine-readable error category URI |
title | Short HTTP-status summary |
status | HTTP status code |
detail | Human-readable explanation |
instance | Request path |
requestId | Correlation id for support and debugging |
errors | Optional field-level validation errors |
Request IDs
All external routes support caller-supplied request IDs:
- send
X-Request-Idon the request - Steve echoes it back as
Request-Id - if you omit it, Steve generates one
Use the Request-Id value when escalating API issues.
Common error type slugs
Problem-detail routes use type URIs in the form:
Common slugs:
| Slug | Meaning |
|---|---|
bad-request | Malformed JSON or invalid request body |
unauthorized | Missing, malformed, or invalid API key |
forbidden | Revoked key or insufficient access |
key-not-company-scoped | Key is valid but cannot use company-scoped endpoints |
not-found | Workflow, session, submission, or fraud match not found |
conflict | Resource is in the wrong state for the requested transition |
gone | Session expired |
validation-error | Request body failed field-level validation |
files-missing | Required files were not uploaded before submit |
rate-limit-exceeded | Caller exceeded the configured limit |
internal-error | Unexpected server-side failure |
Status code guide
| Status | Where it appears | Meaning |
|---|---|---|
200 | Reads and most state transitions | Request succeeded |
201 | Create workflow session | Session created |
400 | Any external route | Malformed JSON or invalid request shape |
401 | All authenticated routes | Missing or invalid credentials |
403 | All authenticated routes | Revoked key, wrong key owner, or missing company scope |
404 | Workflow, job, submission, and fraud routes | Resource not found |
409 | Submit, approve, and similar transitions | Resource state conflict |
410 | Session submit flow | Session expired |
422 | Validation-heavy routes | Semantically invalid request |
429 | All external routes | Rate limit exceeded |
500 | Any route | Unexpected failure |
Rate-limit buckets
Steve enforces fixed one-minute windows per API key.
| Bucket | Endpoints | Limit |
|---|---|---|
read | GET /api/v1/companies, GET /api/v1/jobs/{sessionId}, workflow reads, submission reads, fraud reads | 300 req/min |
session | POST /api/v1/workflows/{slug}/sessions | 60 req/min |
submit | POST /api/v1/workflows/{slug}/sessions/{sessionId}/submit | 20 req/min |
write | submission approve, reject, cancel, and fraud resolve actions | 60 req/min |
webhook_test | POST /api/v1/webhooks/test | 10 req/min |
Successful responses include:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset
429 responses also include:
Retry-After
Retry guidance
Use this policy:
- Do not retry ordinary
4xxresponses. - Retry
429after waiting forRetry-After. - Retry transient
5xxfailures with exponential backoff and jitter. - Use
clientSubmissionIdwhen creating sessions so create retries stay idempotent.
Practical advice
- Keep headroom under published limits instead of running exactly at the ceiling.
- Prefer webhook delivery over tight polling loops.
- Treat
422as a request-contract issue, not a transient server issue. - On manual review actions, refetch the submission after a successful write if your UI needs the latest state.
- Expect camelCase fields in every success and error body, and ISO 8601 strings for body timestamps.