Skip to navigation

Limits & facts

Every number the API enforces, on one page

Base URL and versioning

Base URLhttps://api.rray.app
Version prefix/v1 on every endpoint except the public error catalog (/errors)
Content typeapplication/json requests, application/json responses, application/problem+json errors
Auth headerAuthorization: Bearer rray_live_...

The version lives in the path. A breaking change ships as a new prefix; /v1 keeps its contract.

What fits in one send

LimitValue
Recipients per messageAt least one in to; no fixed ceiling across to, cc and bcc
Duplicate recipientsNot allowed — an address may appear only once across to, cc and bcc
Messages per batch1 to 100 per POST /v1/messages/batch
Attachments per messageNo count limit
Attachment bytes per message10 MiB total, decoded, across every attachment
Attachment URL fetch10 s timeout; the target must resolve to a public address
Attachment file typesExecutable and script extensions are refused (.exe, .bat, .cmd, .com, .scr, .msi, .vbs, .js, .jar, .ps1, .lnk, .app, .dll, .sh, .ps, .reg, .msc, .pif, .hta, .cpl)
Subject and body sizeNo API-level limit; the attachment budget is the only byte ceiling

Every recipient is one delivery, and every delivery counts once against your allowance. A message to three addresses costs three.

Rate limits

CredentialLimitCounted per
Workspace key300 requests/minuteWorkspace (all of its keys share the budget)
Platform key3000 requests/minuteAccount

Fixed one-minute windows. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; a 429 adds Retry-After in seconds. See Rate limits.

Quota headers

Send endpoints report your plan allowance as structured-field dictionaries: RRay-Quota-Limit, RRay-Quota-Remaining and RRay-Quota-Reset.

KeyMeaning
account.dailyDeliveries the account may send in one UTC day. Always present.
account.monthlyDeliveries included this period — prorated by time on each plan after a mid-period change.
account.monthly_overageDeliveries available beyond the included volume, bounded by your overage budget. Present only when a budget is set.
workspace.monthlyReplaces the two account.monthly* keys when a workspace key acts on a workspace that has its own limit.

RRay-Quota-Reset values are Unix timestamps: the end of the UTC day for account.daily, the end of the billing period for the rest.

Changing plan mid-period

Your delivery counter belongs to the billing period, not to the plan: an upgrade keeps the count where it is. The allowance and the overage are prorated by the time you spent on each plan, exactly the way the plan fee is.

Upgrade from Starter to Growth on day 15 of a 30-day period and the period includes 7,500 + 37,500 = 45,000 deliveries — half of each plan’s package.

Overage is split across the plans you were on in the same proportion, and each part is priced at that plan’s own rate, so an invoice shows them as separate lines.

The dashboard and RRay-Quota-Limit report the prorated allowance the moment the upgrade applies. The plan’s full allowance applies from the next period on.

Overage for a closed period is billed on its own invoice, raised right after the period ends. While such an invoice is unpaid, sending is paused and plan changes are refused; paying it resumes both.

Downgrades and cancellation take effect at the end of the period. You keep the current plan’s allowance until then, and the next period starts on the new plan. Cancelling moves you to Free rather than removing your account.

Plan fees are charged in advance. If a renewal cannot be collected after the retries, the account moves to Free, the uncollected renewal is cancelled, and nothing is owed for it.

Retention

DataKept for
Message bodies (GET /v1/messages/{id}/body)30 days after send, then removed — the message itself still reads normally
Messages, deliveries and eventsThe full stored history; no product window narrows it today
Idempotency-Key claims24 hours, after which the key is free to use again

Pagination

limit1 to 100, default 20
totalExact up to 10 000, then reported as total: 10000 with total_capped: true
total on cursor pagesnull — counting runs on the first page only

See Pagination.

Statistics windows

GET /v1/stats takes last buckets of size group_by, including the current partial one. The default is 1 for every grouping.

group_byMaximum last
day90
week52
month24

Workspace headers

RRay-Workspace-IdExactly one workspace id, no commas
RRay-Workspace-Ids1 to 50 comma-separated ids, unique, GET /v1/stats only
Workspace name1 to 100 characters, unique within your account

See Workspaces.

Identifiers

Ids are a short prefix, an underscore, and an opaque suffix. The prefix tells you what kind of object it is. Treat the suffix as opaque: do not parse it, and store ids as strings.

PrefixObjectExample
msg_Messagemsg_01M4ANAVD7EYMHY0PWSH5PBDJD
ws_Workspacews_01KYA3AWSZGCB9YMNKM5AQBA8G
evt_Delivery eventevt_01M4ANAVDNW22V8M1EHEPQJ8DM
cus_Accountcus_01KYA3AWSYX8ZWK2CJ4N0JYQ7D
key_API key recordkey_01KYA3AX04ME5Z2B3H9GQNQJ8R

API key secrets are not ids: they look like rray_live_... or rray_test_... and are shown exactly once. Ids are stable and safe to log; secrets are neither.

Proprietary headers

Standard headers are used bare (Idempotency-Key, RateLimit-*, Retry-After). Everything proprietary is RRay--prefixed; there are no X- headers in this API.

HeaderDirection
RRay-Workspace-IdRequest
RRay-Workspace-IdsRequest, GET /v1/stats only
RRay-Batch-ValidationRequest, POST /v1/messages/batch only
RRay-Request-IdResponse, on every response. Send one and it is echoed back and used as the correlation id.
RRay-Quota-Limit, RRay-Quota-Remaining, RRay-Quota-ResetResponse, send endpoints