Skip to main content

Error format

All errors return a JSON body with an errors array:
{
  "errors": [
    {
      "message": "Domain not verified",
      "field": "from"
    }
  ]
}
The field property is only present for validation errors and indicates which request field caused the problem.

HTTP status codes

CodeMeaningWhen it happens
200OKSuccessful read or update
201CreatedResource created
202AcceptedEmail queued (async operation)
400Bad RequestValidation error — check the errors array
401UnauthorizedMissing or invalid X-API-Key
402Payment RequiredPlan quota exceeded (emails, domains, or webhooks)
404Not FoundResource doesn’t exist or belongs to another workspace
409ConflictDuplicate resource (e.g. domain already registered)
422Unprocessable EntityBusiness logic error — domain not verified, recipient suppressed, domain scope mismatch
429Too Many RequestsRate limit exceeded — back off and retry
500Internal Server ErrorSomething went wrong on our side

Rate limiting

Requests are rate-limited per API key. If you exceed the limit you’ll receive a 429 response with a Retry-After header indicating when you can retry.
HTTP/1.1 429 Too Many Requests
Retry-After: 30

Handling errors

Node.js
const res = await fetch('https://api.torpedo.co.mz/api/v1/emails', {
  method: 'POST',
  headers: { 'X-API-Key': process.env.TORPEDO_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    from: 'hello@myapp.com',
    to: '...',
    subject: '...',
    html: '...',
    text: '...',
  }),
})

if (!res.ok) {
  const { errors } = await res.json()
  console.error(errors[0].message)
}