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.

_tagStatusFieldsCauseHow to resolve
AnalyticsQueryError400messageAn analytics query's date range or limit is out of bounds.Correct the query as message describes.
UnauthorizedError401messageThe credential is missing, invalid, revoked, or expired.Send a valid credential. See Authentication.
PaymentRequiredError402message, resource, currentUsage, limitA plan limit or daily send quota blocks the request.Add a payment method, upgrade, or wait for the limit to reset.
ForbiddenError403messageThe credential lacks permission, or the organization's sending is paused.Use a credential with the permission message names, or contact support.
OnboardingReviewRequiredError403message, code, decision, stage, nextAction, identityIdEmail review blocks the organization or the sending identity.Follow nextAction.
MailboxSendRefusedError403message, receiptA mailbox policy refuses the recorded send.Inspect the receipt and resolve the refusal before deliberately submitting a new intent.
FlagDisabledError403message, flagThe request uses a feature that is not enabled for the organization.No client-side fix; contact support.
ResourceNotFoundError404message, resource, idThe referenced resource does not exist in your organization.Check the id.
ConflictError409message, resource, idThe request conflicts with existing state.Reconcile with the resource resource and id name.
MailboxSendConflictError409message, resource, id, receiptA competing decision or request already owns the send action.Observe the winning receipt's action instead of submitting a replacement email.
ValidationError422message, fieldsThe request body or parameters failed validation.Correct the request; fields gives per-field detail.
MailboxChannelUnsupportedError422message, channelA mailbox request names a channel the mailbox cannot use yet.Use email, the channel a mailbox uses.
BrandAddressRequiredError422message, brandA campaign's footer brand has no postal address.Add the address in the brand's footer, then schedule or send again.
CampaignFooterRequiredError422messageA campaign turned the footer off and its template does not render BrandFooter.Turn the footer on, or render BrandFooter in the template.
RateLimitedError429message, retryAfterSecondsThe organization or API key exceeded its send rate or a probation limit.Wait retryAfterSeconds, then retry.
InternalError500messageAn unexpected server error.Retry with backoff; contact support if it persists.
BillingProviderError502messageSamva could not read the organization's plan.Retry with backoff.
EmailChannelError502reason, message, statusCodeThe email service refused or could not complete a domain or sender step.Retry when reason is transport or rate_limited.
ExternalServiceError502messageA service Samva depends on returned an error.Retry with backoff.
DeliveryUnavailableError503message, retryAfterSecondsSamva could not hand an accepted send to delivery.Wait retryAfterSeconds, then retry with the same Idempotency-Key.
SenderNotReadyError503message, sender, retryAfterSecondsThe sending identity is still being prepared or verified.Wait for it to become ready; honor retryAfterSeconds when present.
GatewayTimeoutError504message, retryAfterSecondsThe 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:

reasonMeaningRetry
transportThe email service was temporarily unavailable.yes
rate_limitedThe email service is temporarily rate limited.yes
rejectedThe email service rejected the request.no
authSamva 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.

HeaderValuesMeaning
x-samva-throttle-sourcesamva_admissionSamva's own plan and API-key admission shed the request.
x-samva-error-layersql, application, provider, deadlineSamva'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

StatusRetryHow
429yesWait Retry-After seconds, or retryAfterSeconds from the body, then retry.
500yesExponential backoff. A repeated x-samva-error-layer: sql is worth reporting.
502usuallyExponential backoff, except an EmailChannelError whose reason says not to.
503yesExponential backoff with jitter; the API was at capacity and ran no code.
504yesWait Retry-After seconds, then retry with the same idempotency key.
402noA quota or entitlement blocks it. Waiting a few seconds does not clear it.
4xxnoCorrect 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 documentation

On this page