API Reference · Introduction

Errors

Daffy Voice uses standard HTTP status codes. A 2xx means it worked; anything else comes with a JSON body that says what went wrong, in words you can show to a person.

Error format

Most errors return a single detail message:

Response · 404
{ "detail": "Campaign not found" }

When the request body itself is malformed — a required field is missing, or a value has the wrong type — the status is 422 and detail is a list, one entry per problem. loc points at the field:

Response · 422
{
  "detail": [
    {
      "type": "missing",
      "loc": ["body", "agent_id"],
      "msg": "Field required",
      "input": { "name": "October EMI reminders" }
    }
  ]
}

Check the type of detail

Some 422 errors are checks Daffy Voice makes itself (for example "Invalid agent_id"), and those return detail as a string. Handle both a string and a list.

Rate-limit errors are the one exception to this format — see 429 below.

Status codes

Codes the API returns

200 OKSuccess
The request worked. The body holds the result.
201 CreatedSuccess
A campaign or phone number was created. The body is the new item.
204 No ContentSuccess
A delete worked. The body is empty.
400 Bad RequestYour request
A campaign ID that isn't a valid UUID ("Invalid id"), or a contacts CSV that can't be read.
401 UnauthorizedYour key
No API key was sent, or it is wrong or revoked.
403 ForbiddenYour key
A read-only key tried to change something, or the item belongs to another company.
404 Not FoundYour request
The item doesn't exist in your company.
409 ConflictCurrent state
The item isn't in a state that allows this — for example deleting a running campaign, or adding a number that is already registered.
413 Payload Too LargeYour request
More than 1,000 contacts in one workflow trigger.
422 UnprocessableYour request
A field is missing, has the wrong type, or holds an ID that isn't a valid UUID.
429 Too Many RequestsRate limit
More than 120 requests in a minute from your IP address.
500 Server ErrorDaffy Voice
Something failed on our side. Retry later; contact us if it keeps happening.

Rate-limit errors

A 429 has its own body, with no detail:

Response · 429
{ "error": "rate_limited", "scope": "ip" }

There is no Retry-After header. Back off for a few seconds and retry.

Retrying safely

Retry 429 and 5xx responses after a short wait. Don't retry other 4xx errors unchanged — fix the request first.

Creates aren't idempotent

Creating a campaign, uploading contacts and triggering a workflow have no idempotency key. If a request times out and you send it again, the contacts may be added — and called — twice. Check the campaign's contact counts before retrying.