Sales Engine
API documentation
Getting started

Errors

Every error returns a real HTTP status and one body shape. Branch on code, never on message: codes are stable, messages are written for people and may be reworded.

Error envelope
{
  "error": {
    "code": "insufficient_scope",
    "message": "This call needs the 'send' scope; the key has read, write.",
    "details": { "required_scope": "send" }
  }
}

Codes

CodeStatusMeaning
unauthorized401No credential: no key and no session. Add the Authorization header.
invalid_key401The key is malformed, unknown, revoked, or its owner left the workspace. Check for a truncated paste; otherwise create a new key.
insufficient_scope403The key is valid but lacks the scope this call needs; details.required_scope names it.
session_only403This call belongs to the signed-in browser (profile, avatar, workspace switching) and takes no key.
unknown_operation403The path is not a registered operation. Keys fail closed: a route has to be in the registry before any key can reach it.
forbidden403You are not a member of that workspace, or the action needs an owner or admin.
not_found404No record with that id, or it belongs to another workspace. Both answer the same way on purpose.
locked409The campaign is launched: steps, day offsets and variants are frozen. Duplicate it to change the shape.
invalid422The input did not validate. message says what, and details carries the field errors when there are any.
rate_limited429Over the per-key budget. Retry-After and details.retry_after give the seconds to wait.
internal500Something failed on our side. Retry with backoff; if it persists, mail work@ashwanth.dev with the time of the request.

Retrying

Retry 429 after the wait it names, and 500 with backoff. Do not retry 400 to 404, 409 or 422: they fail the same way until the request or the key changes.

Jobs that fail

A job that was accepted returns 200. If the work then fails, the failure is on the job, not the request: read the job and look at status and error. See Jobs and polling.