Error reference
Reference every error the Samva API can return, with its HTTP status, response fields, cause, and how to resolve it.
Every Samva API error is returned as a flat JSON body. The _tag field is the machine-readable
discriminator, and the remaining fields sit at the top level of the response beside it. The _tag
determines the HTTP status code. The SDK throws a class named for each _tag; see
Error handling.
{
"_tag": "ValidationError",
"message": "Invalid request",
"fields": {
"email.tracking.typo": ["Unexpected property"]
}
}Branch on _tag, never on message text.
After a failed or interrupted mailbox send response, preserve the original request and
Idempotency-Key. If the error includes a receipt, observe its actionId. Follow
mailbox recovery before submitting another email.
Error types
This table lists every error the public API declares. Each operation's API reference page lists the errors that operation can return.
_tag | Status | Fields | Cause | How to resolve |
|---|---|---|---|---|
AnalyticsQueryError | 400 | message | An analytics query's date range or limit is out of bounds. | Correct the query as message describes. |
UnauthorizedError | 401 | message | The credential is missing, invalid, revoked, or expired. | Send a valid credential. See Authentication. |
PaymentRequiredError | 402 | message, resource, currentUsage, limit | A plan limit or daily send quota blocks the request. | Add a payment method, upgrade, or wait for the limit to reset. |
ForbiddenError | 403 | message | The credential lacks permission, or the organization's sending is paused. | Use a credential with the permission message names, or contact support. |
OnboardingReviewRequiredError | 403 | message, code, decision, stage, nextAction, identityId | Email review blocks the organization or the sending identity. | Follow nextAction. |
MailboxSendRefusedError | 403 | message, receipt | A mailbox policy refuses the recorded send. | Inspect the receipt and resolve the refusal before deliberately submitting a new intent. |
FlagDisabledError | 403 | message, flag | The request uses a feature that is not enabled for the organization. | No client-side fix; contact support. |
ResourceNotFoundError | 404 | message, resource, id | The referenced resource does not exist in your organization. | Check the id. |
ConflictError | 409 | message, resource, id | The request conflicts with existing state. | Reconcile with the resource resource and id name. |
MailboxSendConflictError | 409 | message, resource, id, receipt | A competing decision or request already owns the send action. | Observe the winning receipt's action instead of submitting a replacement email. |
ValidationError | 422 | message, fields | The request body or parameters failed validation. | Correct the request; fields gives per-field detail. |
MailboxChannelUnsupportedError | 422 | message, channel | A mailbox request names a channel the mailbox cannot use yet. | Use email, the channel a mailbox uses. |
BrandAddressRequiredError | 422 | message, brand | A campaign's footer brand has no postal address. | Add the address in the brand's footer, then schedule or send again. |
CampaignFooterRequiredError | 422 | message | A campaign turned the footer off and its template does not render BrandFooter. | Turn the footer on, or render BrandFooter in the template. |
RateLimitedError | 429 | message, retryAfterSeconds | The organization or API key exceeded its send rate or a probation limit. | Wait retryAfterSeconds, then retry. |
InternalError | 500 | message | An unexpected server error. | Retry with backoff; contact support if it persists. |
BillingProviderError | 502 | message | Samva could not read the organization's plan. | Retry with backoff. |
EmailChannelError | 502 | reason, message, statusCode | The email service refused or could not complete a domain or sender step. | Retry when reason is transport or rate_limited. |
ExternalServiceError | 502 | message | A service Samva depends on returned an error. | Retry with backoff. |
DeliveryUnavailableError | 503 | message, retryAfterSeconds | Samva could not hand an accepted send to delivery. | Wait retryAfterSeconds, then retry with the same Idempotency-Key. |
SenderNotReadyError | 503 | message, sender, retryAfterSeconds | The sending identity is still being prepared or verified. | Wait for it to become ready; honor retryAfterSeconds when present. |
GatewayTimeoutError | 504 | message, retryAfterSeconds | The request did not finish inside the API's time limit. | Wait retryAfterSeconds, then retry with the same idempotency key. |
The published OpenAPI document marks each error schema
with x-retryable and x-category, so a client can decide whether to retry without matching on
_tag.
Errors in detail
AnalyticsQueryError (400)
Returned when an analytics query cannot be answered as asked, for example a before earlier than
its after, or a range longer than the operation allows. message says which.
{
"_tag": "AnalyticsQueryError",
"message": "before must not precede after"
}UnauthorizedError (401)
Returned when the credential cannot be validated. See Authentication.
{
"_tag": "UnauthorizedError",
"message": "Invalid API key"
}PaymentRequiredError (402)
Returned when a plan limit or entitlement blocks the request. resource names the ceiling reached,
and currentUsage and limit describe it. A spent daily send quota is this error with resource
set to daily send quota; see Daily send quota.
{
"_tag": "PaymentRequiredError",
"message": "daily send quota limit reached: usage 1000, limit 1000. Resets at 00:00 UTC. Raise your plan's limit in your dashboard's Settings > Billing (/dashboard/<orgSlug>/settings/billing).",
"resource": "daily send quota",
"currentUsage": 1000,
"limit": 1000
}ForbiddenError (403)
Returned when the credential is valid but not authorized for the request. A missing permission
names the permission in message. While an organization's sending is paused or disabled, every
send returns this error with message saying why; see
Paused sending.
{
"_tag": "ForbiddenError",
"message": "Caller requires contacts:create permission"
}OnboardingReviewRequiredError (403)
Returned by a send when your organization is waiting for review before its first send, when review
rejected it, or when review rejected the domain or sender the message would go out from. code says
what is blocking, decision and
stage report the review, and nextAction says what to do: wait_for_review,
provide_information, verify_sending_identity, reapply, or contact_support. identityId names
the domain or sender when the block is about one identity. See
Check email review status.
{
"_tag": "OnboardingReviewRequiredError",
"message": "Email sending is blocked by review (review_in_progress). Wait for review to complete before sending again.",
"code": "review_in_progress",
"decision": "undecided",
"stage": "manual_review",
"nextAction": "wait_for_review"
}FlagDisabledError (403)
Returned when the request uses a feature that is not enabled for your organization. flag names
the feature.
{
"_tag": "FlagDisabledError",
"message": "Feature 'email' is not enabled for your organization. Email support@samva.dev to request access.",
"flag": "email"
}MailboxSendRefusedError (403)
Returned when a mailbox policy refuses a recorded send. receipt identifies the action and its
outcome. Inspect its decision and problem before correcting the policy or email. Replaying the
original request observes that action; it does not bypass the refusal.
See mailbox approvals.
ResourceNotFoundError (404)
Returned when the referenced resource does not exist in your organization. resource and id
identify what was not found.
{
"_tag": "ResourceNotFoundError",
"message": "Message 'msg_7q2xk9mvt4znw8rh' not found. Call messages.list to find valid ids.",
"resource": "Message",
"id": "msg_7q2xk9mvt4znw8rh"
}ConflictError (409)
Returned when the request conflicts with existing state, such as a duplicate, or an
Idempotency-Key reused with a different request. resource names the conflicting resource, and
id identifies it when applicable.
{
"_tag": "ConflictError",
"message": "A webhook with this URL already exists",
"resource": "webhook"
}MailboxSendConflictError (409)
Returned when another resolution wins, an email has already been accepted before cancellation,
or the request conflicts with the original send. receipt is the authoritative current phase of
the action named by id. Observe that action and preserve its original request key; do not
replace it to recover an uncertain outcome.
ValidationError (422)
Returned when the request body or parameters fail validation. The optional fields map lists
per-field messages. Request-shape failures use Invalid request and dotted paths, including
array indices. Query and path failures name the parameter; an undecodable cursor names cursor.
Fix the listed fields before retrying.
{
"_tag": "ValidationError",
"message": "Invalid request",
"fields": {
"email.tracking.typo": ["Unexpected property"]
}
}RateLimitedError (429)
Returned when the organization or the API key exceeds its send rate, or an organization on
probation exceeds a probation limit. retryAfterSeconds, and the Retry-After header with the same
value, say how long to wait. A spent daily quota is a 402, not this error, because waiting a few
seconds does not clear it. The rates are in Rate limiting
and the probation limits in Probation limits.
{
"_tag": "RateLimitedError",
"message": "Organization or API key send rate limit reached. Retry after 1 seconds.",
"retryAfterSeconds": 1
}InternalError (500)
Returned for an unexpected server error. Retry with backoff; if it persists, contact support.
{
"_tag": "InternalError",
"message": "Internal server error"
}BrandAddressRequiredError (422)
Returned when a campaign is scheduled or sent and the brand that renders its footer has no postal
address. Campaigns sign off with a mailing address; transactional sends never fail on it. brand
names the brand to fix, or is null when no brand could be resolved.
{
"_tag": "BrandAddressRequiredError",
"message": "Add a postal address to the brand \"default\" before scheduling this campaign: a campaign's footer must include one.",
"brand": "default"
}CampaignFooterRequiredError (422)
Returned when a campaign is scheduled or sent with the appended footer turned off and a template
that does not render BrandFooter. Every campaign carries the brand footer: its postal address and
unsubscribe link. Transactional sends never fail on it.
{
"_tag": "CampaignFooterRequiredError",
"message": "A campaign must carry the brand footer (postal address and unsubscribe link). Turn the footer on, or render BrandFooter from samva:brand in the template."
}BillingProviderError (502)
Returned when Samva cannot read your organization's plan while deciding whether to admit the request. Retry with backoff.
{
"_tag": "BillingProviderError",
"message": "Billing service is temporarily unavailable"
}EmailChannelError (502)
Returned by domain, sender, tracking, and suppression operations when the email service refuses or
cannot complete the step. reason is one of:
reason | Meaning | Retry |
|---|---|---|
transport | The email service was temporarily unavailable. | yes |
rate_limited | The email service is temporarily rate limited. | yes |
rejected | The email service rejected the request. | no |
auth | Samva could not authenticate to the service. | no |
statusCode, when present, is the status the email service answered with.
{
"_tag": "EmailChannelError",
"reason": "transport",
"message": "Email service is temporarily unavailable"
}ExternalServiceError (502)
Returned when a service Samva depends on returns an error. The response carries no diagnostics from that service. Retry with backoff.
{
"_tag": "ExternalServiceError",
"message": "Upstream service is temporarily unavailable"
}DeliveryUnavailableError (503)
Returned by a send when Samva accepted the request but could not hand it to delivery. Nothing was
sent. retryAfterSeconds, and the Retry-After header with the same value, say how long to wait;
then retry with the same Idempotency-Key, and if an earlier attempt did complete, the retry
returns its message instead of sending again.
{
"_tag": "DeliveryUnavailableError",
"message": "Samva could not hand the message to delivery. Retry the request.",
"retryAfterSeconds": 5
}SenderNotReadyError (503)
Returned by a send when its sending identity is still being prepared or verified. sender names
the sending address. Wait for that identity to become ready before replaying the original request
with the same Idempotency-Key.
retryAfterSeconds is optional. When present, it and the Retry-After header say how long to wait
before another attempt. When absent, no retry interval is supplied. This request error does not
arrange an automatic retry. A queued mailbox action already owns its retries; observe that action
instead of starting another send.
{
"_tag": "SenderNotReadyError",
"message": "The sending identity is not ready to send yet.",
"sender": "support@acme.samva.email"
}GatewayTimeoutError (504)
Returned when a request runs past the API's time limit and is abandoned rather than held open, or
when work the request waits on misses its own deadline. The response carries Retry-After with the
same value as retryAfterSeconds, and x-samva-error-layer: deadline.
A 504 says the request did not finish, not that it did nothing. Work already committed stays
committed, so retry a write only with the same
Idempotency-Key as the attempt that timed out. Template
workspace writes carry their key as idempotencyKey in the body; retrying a save with the same key
returns the commit the first attempt made instead of committing twice.
{
"_tag": "GatewayTimeoutError",
"message": "The request did not complete within the API's time limit.",
"retryAfterSeconds": 1
}Which layer refused
Two response headers name the layer behind a refusal, so a status code alone is never the whole answer.
| Header | Values | Meaning |
|---|---|---|
x-samva-throttle-source | samva_admission | Samva's own plan and API-key admission shed the request. |
x-samva-error-layer | sql, application, provider, deadline | Samva's database, Samva's own code, a service Samva calls, or the API's time limit. |
Every 5xx Samva's code produced carries x-samva-error-layer. A 5xx without it, and a 429
without x-samva-throttle-source, came from infrastructure ahead of the API and never reached
Samva's code. Both are safe to retry with backoff. A 413 with no _tag also came from ahead of the
API: the body exceeded the request size, and a retry of the
same body fails the same way.
What to retry
| Status | Retry | How |
|---|---|---|
429 | yes | Wait Retry-After seconds, or retryAfterSeconds from the body, then retry. |
500 | yes | Exponential backoff. A repeated x-samva-error-layer: sql is worth reporting. |
502 | usually | Exponential backoff, except an EmailChannelError whose reason says not to. |
503 | yes | Exponential backoff with jitter; the API was at capacity and ran no code. |
504 | yes | Wait Retry-After seconds, then retry with the same idempotency key. |
402 | no | A quota or entitlement blocks it. Waiting a few seconds does not clear it. |
4xx | no | Correct the request. |
A read is safe to retry as-is. A write is not, because a 5xx does not tell you whether the write
landed. Send the same Idempotency-Key you used the first
time so the retry replays the original result instead of performing the write twice. Without a key,
read the resource back before retrying.
Related
Related documentation
REST API
Reference REST conventions for Samva's email API, covering auth, request and response shapes, status codes, rate limits, pagination, and errors.
Authentication
Reference Samva's credentials, covering API key format and headers, permissions, OAuth sessions for the CLI and MCP, and authentication errors.