Skip to content

API reference

Every endpoint, every parameter and every error the API can answer with. This page is generated from the same OpenAPI document the API validates requests against, so it cannot describe a field the code does not have.

Version
1.0.0
Base URL
https://api.relayara.com/v1
Endpoints
34 in 9 groups
On this page

Transactional email API.

The surface is compatible with Resend: field names, status codes, error names, response bodies, event names and the signature scheme of the outgoing webhooks all match, so a client written against Resend keeps working after nothing more than a base URL and a key change.

Authentication

An API key, rl_live_ or rl_test_ followed by 32 bytes of base62. Treat it as opaque.

Every endpoint takes Authorization: Bearer <key>. A key is either full or sending_only. A sending_only key reaches the Emails group and nothing else; every other operation answers restricted_api_key for it. An operation states what it needs in x-required-key-scope, and an operation that can answer restricted_api_key is one a restricted key cannot call.

A sending_only key reaches Emails. Everything under Domains, API keys, Webhooks, Suppressions, Usage, Logs, Billing, Account needs a full key, and answers a restricted one with restricted_api_key.

Example
curl https://api.relayara.com/v1/domains \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Conventions

Timestamps

REST responses carry the Postgres textual form, YYYY-MM-DD HH:MM:SS.NNNNNN+00, which is not ISO 8601. Webhook bodies carry ISO 8601. That inconsistency is reproduced on purpose, because a client parsing one format in one place and the other elsewhere would break on a value that is merely more correct.

Unknown fields

Request bodies accept properties the schema does not name and drop them. A field added to a later version therefore reaches an older server without being rejected.

Errors

Every failure uses one shape, described by ApiError. Internal detail, stack traces and provider messages never appear in it. A response carries x-request-id, which is what a support request should quote.

The shape of every failure

  • statusCode

    integerRequired

  • name

    stringRequired

    validation_errormissing_required_fieldinvalid_from_addressinvalid_attachmentinvalid_idempotency_keyinvalid_idempotent_requestconcurrent_idempotent_requestsmissing_api_keyinvalid_api_keyexpired_api_keyrestricted_api_keymissing_sessioninvalid_sessioninsufficient_roleinvalid_tokenmfa_requiredinvalid_mfa_codecsrf_failednot_foundmethod_not_allowedrate_limit_exceededdaily_quota_exceededmonthly_quota_exceededdomain_not_verifiedrecipient_suppressedaccount_suspendedsecurity_errorinternal_error

  • message

    stringRequired

Every error name and the status it carries

  • 400validation_errorinvalid_idempotency_key
  • 401missing_api_keyrestricted_api_keymissing_session
  • 403invalid_api_keyexpired_api_keyinvalid_sessioninsufficient_roleinvalid_tokenmfa_requiredinvalid_mfa_codecsrf_faileddomain_not_verifiedaccount_suspended
  • 404not_found
  • 405method_not_allowed
  • 409invalid_idempotent_requestconcurrent_idempotent_requests
  • 422missing_required_fieldinvalid_from_addressinvalid_attachmentrecipient_suppressed
  • 429rate_limit_exceededdaily_quota_exceededmonthly_quota_exceeded
  • 451security_error
  • 500internal_error

Emails

Sending mail and reading it back.

POSThttps://api.relayara.com/v1/emails

Send an email

Queues a single message. The response is returned once the message is accepted and persisted, which is before the provider has seen it. Delivery is reported through webhooks and through the retrieve endpoint.

A sending_only key is enough for this endpoint.

Headers

  • Idempotency-Key

    stringOptional

    Optional. Repeating a request with the same key within 24 hours returns the identifier of the original message and sends nothing further. A key reused with a different body is rejected.

    1 to 256 characters

Request body

  • from

    stringRequired

    3 to 384 characters

  • subject

    stringRequired

    at most 998 characters

  • to

    string | string[]Required

    3 to 384 characters, 1 to 50 entries

  • cc

    string | string[]Optional

    3 to 384 characters, 1 to 50 entries

  • bcc

    string | string[]Optional

    3 to 384 characters, 1 to 50 entries

  • reply_to

    string | string[]Optional

    3 to 384 characters, 1 to 50 entries

  • html

    stringOptional

    at most 2000000 characters

  • text

    stringOptional

    at most 2000000 characters

  • headers

    objectOptional

    any key, values are string, each value at most 998 characters

  • attachments

    object[]Optional

    at most 20 entries

    • filename

      stringRequired

      1 to 255 characters

    • content

      stringOptional

      base64 encoded

    • path

      stringOptional

      format uri

    • content_type

      stringOptional

      1 to 78 characters

    • content_id

      stringOptional

      1 to 78 characters

  • tags

    object[]Optional

    at most 10 entries

    • name

      stringRequired

      matches ^[A-Za-z0-9_-]{1,256}$

    • value

      stringRequired

      matches ^[A-Za-z0-9_-]{1,256}$

  • scheduled_at

    stringOptional

    format date-time

Example

cURL
curl -X POST https://api.relayara.com/v1/emails \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "subject": "Your receipt from Acme",
    "to": "[email protected]",
    "html": "<p>Thanks for your order.</p>"
  }'

Response 200

Message accepted.

  • id

    stringRequired

Errors

  • 400invalid_idempotency_keyvalidation_error
  • 401missing_api_key
  • 403account_suspendeddomain_not_verifiedexpired_api_keyinvalid_api_key
  • 409concurrent_idempotent_requestsinvalid_idempotent_request
  • 422invalid_attachmentrecipient_suppressed
  • 429daily_quota_exceededmonthly_quota_exceededrate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/emails

List sent emails

Returns the messages of the account, newest first, paged through after. The bodies are not included: a list is an overview, and the retrieve endpoint is the only way to the content of a message. after takes the id of the last message of the previous page.

A sending_only key is enough for this endpoint.

Query parameters

  • limit

    integerOptional

    Messages per page.

    defaults to 50, at least 1, at most 100

  • after

    stringOptional

    Identifier of the last message of the previous page.

    1 to 64 characters

  • last_event

    stringOptional

    Delivery state to filter on, in the same vocabulary the response reports.

    queuedscheduledsentdelivereddelivery_delayedbouncedcomplainedopenedclickedfailedcanceled

  • created_after

    stringOptional

    Only messages created at or after this moment, as an ISO 8601 timestamp with an offset.

    format date-time

  • created_before

    stringOptional

    Only messages created at or before this moment, as an ISO 8601 timestamp with an offset.

    format date-time

Example

cURL
curl https://api.relayara.com/v1/emails \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

One page of messages.

  • object

    stringRequired

    always list

  • data

    object[]Required

    • object

      stringRequired

      always email

    • id

      stringRequired

    • message_id

      string | nullRequired

    • to

      string[]Required

    • from

      stringRequired

    • created_at

      stringRequired

    • subject

      stringRequired

    • bcc

      string[]Required

    • cc

      string[]Required

    • reply_to

      string[]Required

    • last_event

      stringRequired

      queuedscheduledsentdelivereddelivery_delayedbouncedcomplainedopenedclickedfailedcanceled

    • scheduled_at

      string | nullRequired

    • tags

      object[]Required

      • name

        stringRequired

        matches ^[A-Za-z0-9_-]{1,256}$

      • value

        stringRequired

        matches ^[A-Za-z0-9_-]{1,256}$

  • has_more

    booleanRequired

Errors

  • 400validation_error
  • 401missing_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/emails/batch

Send up to 100 emails

Queues many messages in one request. Attachments are not accepted here. Either the whole batch is accepted or none of it is, and the identifiers come back in request order.

A sending_only key is enough for this endpoint.

Request body

  • from

    stringRequired

    3 to 384 characters

  • subject

    stringRequired

    at most 998 characters

  • to

    string | string[]Required

    3 to 384 characters, 1 to 50 entries

  • cc

    string | string[]Optional

    3 to 384 characters, 1 to 50 entries

  • bcc

    string | string[]Optional

    3 to 384 characters, 1 to 50 entries

  • reply_to

    string | string[]Optional

    3 to 384 characters, 1 to 50 entries

  • html

    stringOptional

    at most 2000000 characters

  • text

    stringOptional

    at most 2000000 characters

  • headers

    objectOptional

    any key, values are string, each value at most 998 characters

  • tags

    object[]Optional

    at most 10 entries

    • name

      stringRequired

      matches ^[A-Za-z0-9_-]{1,256}$

    • value

      stringRequired

      matches ^[A-Za-z0-9_-]{1,256}$

  • scheduled_at

    stringOptional

    format date-time

  • attachments

    not allowedOptional

Example

cURL
curl -X POST https://api.relayara.com/v1/emails/batch \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "from": "Acme <[email protected]>",
      "subject": "Your receipt from Acme",
      "to": "[email protected]",
      "html": "<p>Thanks for your order.</p>"
    },
    {
      "from": "Acme <[email protected]>",
      "subject": "Your receipt from Acme",
      "to": "[email protected]",
      "html": "<p>Thanks for your order.</p>"
    }
  ]'

Response 200

Every message of the batch was accepted.

  • data

    object[]Required

    • id

      stringRequired

Errors

  • 400validation_error
  • 401missing_api_key
  • 403account_suspendeddomain_not_verifiedexpired_api_keyinvalid_api_key
  • 422recipient_suppressed
  • 429daily_quota_exceededmonthly_quota_exceededrate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/emails/{id}

Retrieve an email

Returns a message together with its most recent delivery state. created_at is the Postgres textual form rather than ISO 8601, matching the format Resend returns in REST responses.

A sending_only key is enough for this endpoint.

Path parameters

  • id

    stringRequired

    Message identifier.

Example

cURL
curl https://api.relayara.com/v1/emails/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The message.

  • object

    stringRequired

    always email

  • id

    stringRequired

  • message_id

    string | nullRequired

  • to

    string[]Required

  • from

    stringRequired

  • created_at

    stringRequired

  • subject

    stringRequired

  • html

    string | nullRequired

  • text

    string | nullRequired

  • bcc

    string[]Required

  • cc

    string[]Required

  • reply_to

    string[]Required

  • last_event

    stringRequired

    queuedscheduledsentdelivereddelivery_delayedbouncedcomplainedopenedclickedfailedcanceled

  • scheduled_at

    string | nullRequired

  • tags

    object[]Required

    • name

      stringRequired

      matches ^[A-Za-z0-9_-]{1,256}$

    • value

      stringRequired

      matches ^[A-Za-z0-9_-]{1,256}$

Errors

  • 401missing_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

PATCHhttps://api.relayara.com/v1/emails/{id}

Reschedule an email

Moves the send time of a message that has not left yet. Nothing else about a message can be changed, because the caller already holds its identifier and will correlate their own records against it.

A sending_only key is enough for this endpoint.

Path parameters

  • id

    stringRequired

    Message identifier.

Request body

  • scheduled_at

    stringRequired

    format date-time

Example

cURL
curl -X PATCH https://api.relayara.com/v1/emails/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scheduled_at": "2026-09-01T09:00:00.000Z"
  }'

Response 200

The new send time was stored.

  • object

    stringRequired

    always email

  • id

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

DELETEhttps://api.relayara.com/v1/emails/{id}

Cancel a scheduled email, synonym

Identical to POST /v1/emails/{id}/cancel. Offered because an earlier specification named this shape and supporting both costs nothing.

A sending_only key is enough for this endpoint.

Path parameters

  • id

    stringRequired

    Message identifier.

Example

cURL
curl -X DELETE https://api.relayara.com/v1/emails/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The message was cancelled.

  • object

    stringRequired

    always email

  • id

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/emails/{id}/cancel

Cancel a scheduled email

Stops a message that has not been handed to the provider. A message already on its way answers validation_error, because the request is well formed but does not apply to the state the message is in.

A sending_only key is enough for this endpoint.

Path parameters

  • id

    stringRequired

    Message identifier.

Example

cURL
curl -X POST https://api.relayara.com/v1/emails/cl9m2h4vk0000qzrmn831i7rn/cancel \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The message was cancelled.

  • object

    stringRequired

    always email

  • id

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

Domains

Sending domains and their DNS records.

POSThttps://api.relayara.com/v1/domains

Register a sending domain

Registers a domain and returns the DNS records that have to be published for it. Publishing them is what makes the domain usable; until then no message can be sent from it.

This endpoint needs a full key.

Request body

  • name

    stringRequired

    4 to 253 characters

  • region

    stringOptional

    defaults to eu-central-1

    eu-central-1

  • custom_return_path

    stringOptional

    1 to 63 characters

Example

cURL
curl -X POST https://api.relayara.com/v1/domains \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "yourdomain.com"
  }'

Response 201

The domain was registered.

  • id

    stringRequired

  • name

    stringRequired

  • status

    stringRequired

    pendingverifiedfailedtemporary_failure

  • region

    stringRequired

  • mail_from_domain

    string | nullRequired

  • mail_from_status

    stringRequired

    pendingsuccessfailedtemporary_failure

  • records

    object[]Required

    • type

      stringRequired

      CNAMEMXTXT

    • name

      stringRequired

    • value

      stringRequired

    • priority

      integerOptional

      greater than 0

    • proxied

      booleanRequired

      always false

  • verified_at

    string | nullRequired

    format date-time

  • ownership_verified_at

    string | nullRequired

    format date-time

  • created_at

    stringRequired

    format date-time

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/domains

List sending domains

Returns every domain registered for the account.

This endpoint needs a full key.

Example

cURL
curl https://api.relayara.com/v1/domains \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The domains of the account.

  • data

    object[]Required

    • id

      stringRequired

    • name

      stringRequired

    • status

      stringRequired

      pendingverifiedfailedtemporary_failure

    • region

      stringRequired

    • mail_from_domain

      string | nullRequired

    • mail_from_status

      stringRequired

      pendingsuccessfailedtemporary_failure

    • records

      object[]Required

      • type

        stringRequired

        CNAMEMXTXT

      • name

        stringRequired

      • value

        stringRequired

      • priority

        integerOptional

        greater than 0

      • proxied

        booleanRequired

        always false

    • verified_at

      string | nullRequired

      format date-time

    • ownership_verified_at

      string | nullRequired

      format date-time

    • created_at

      stringRequired

      format date-time

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/domains/{id}

Retrieve a sending domain

Reads the stored state of a domain. It performs no provider call, so the verification state is as recent as the last verify request or the last provider event.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Domain identifier.

Example

cURL
curl https://api.relayara.com/v1/domains/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The domain.

  • id

    stringRequired

  • name

    stringRequired

  • status

    stringRequired

    pendingverifiedfailedtemporary_failure

  • region

    stringRequired

  • mail_from_domain

    string | nullRequired

  • mail_from_status

    stringRequired

    pendingsuccessfailedtemporary_failure

  • records

    object[]Required

    • type

      stringRequired

      CNAMEMXTXT

    • name

      stringRequired

    • value

      stringRequired

    • priority

      integerOptional

      greater than 0

    • proxied

      booleanRequired

      always false

  • verified_at

    string | nullRequired

    format date-time

  • ownership_verified_at

    string | nullRequired

    format date-time

  • created_at

    stringRequired

    format date-time

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

DELETEhttps://api.relayara.com/v1/domains/{id}

Remove a sending domain

Removes a domain. Messages already queued for it are unaffected, new ones are refused.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Domain identifier.

Example

cURL
curl -X DELETE https://api.relayara.com/v1/domains/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 204

The domain was removed.

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/domains/{id}/verify

Re-check a sending domain

Asks the provider for the current verification state and stores the answer. Rate limited more tightly than the rest of the API, because it turns into a provider call.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Domain identifier.

Example

cURL
curl -X POST https://api.relayara.com/v1/domains/cl9m2h4vk0000qzrmn831i7rn/verify \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The domain, with the state just fetched.

  • id

    stringRequired

  • name

    stringRequired

  • status

    stringRequired

    pendingverifiedfailedtemporary_failure

  • region

    stringRequired

  • mail_from_domain

    string | nullRequired

  • mail_from_status

    stringRequired

    pendingsuccessfailedtemporary_failure

  • records

    object[]Required

    • type

      stringRequired

      CNAMEMXTXT

    • name

      stringRequired

    • value

      stringRequired

    • priority

      integerOptional

      greater than 0

    • proxied

      booleanRequired

      always false

  • verified_at

    string | nullRequired

    format date-time

  • ownership_verified_at

    string | nullRequired

    format date-time

  • created_at

    stringRequired

    format date-time

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

API keys

Creating, rotating and revoking keys.

POSThttps://api.relayara.com/v1/api-keys

Create an API key

Creates a key and returns its plaintext exactly once. Every key expires; when no expiry is supplied the default lifetime applies.

This endpoint needs a full key.

Request body

  • name

    stringRequired

    1 to 100 characters

  • scope

    stringOptional

    fullsending_only

  • expires_at

    stringOptional

    format date-time

Example

cURL
curl -X POST https://api.relayara.com/v1/api-keys \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production sender",
    "scope": "sending_only"
  }'

Response 201

The key, including the plaintext.

  • id

    stringRequired

  • name

    stringRequired

  • key

    stringRequired

  • prefix

    stringRequired

  • last4

    stringRequired

  • scope

    stringRequired

    fullsending_only

  • expires_at

    stringRequired

  • created_at

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/api-keys

List API keys

Returns the keys of the account without any plaintext. A key whose expiry has passed is still listed and marked as expired.

This endpoint needs a full key.

Example

cURL
curl https://api.relayara.com/v1/api-keys \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The keys of the account.

  • data

    object[]Required

    • id

      stringRequired

    • name

      stringRequired

    • prefix

      stringRequired

    • last4

      stringRequired

    • scope

      stringRequired

      fullsending_only

    • expires_at

      stringRequired

    • expired

      booleanRequired

    • last_used_at

      string | nullRequired

    • created_at

      stringRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/api-keys/{id}/rotate

Rotate an API key

Creates a successor and lets the predecessor run out after a grace period. Both work meanwhile, so a caller can switch over without an outage.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Key identifier.

Example

cURL
curl -X POST https://api.relayara.com/v1/api-keys/cl9m2h4vk0000qzrmn831i7rn/rotate \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 201

The successor, plus the moment the predecessor stops working.

  • id

    stringRequired

  • name

    stringRequired

  • key

    stringRequired

  • prefix

    stringRequired

  • last4

    stringRequired

  • scope

    stringRequired

    fullsending_only

  • expires_at

    stringRequired

  • created_at

    stringRequired

  • rotated_from

    stringRequired

  • predecessor_expires_at

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

DELETEhttps://api.relayara.com/v1/api-keys/{id}

Revoke an API key

Revokes a key immediately. It cannot be brought back.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Key identifier.

Example

cURL
curl -X DELETE https://api.relayara.com/v1/api-keys/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 204

The key was revoked.

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

Webhooks

Subscribing to delivery events.

POSThttps://api.relayara.com/v1/webhooks

Create a webhook endpoint

Registers an https endpoint for the selected events and returns its signing secret. This is the only response that ever carries the secret; a caller who loses it rotates the endpoint rather than looking it up.

This endpoint needs a full key.

Request body

  • url

    stringRequired

    at most 2048 characters, format uri

  • events

    string[]Required

    at least 1 entries, each one of email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.failed, email.scheduled, email.suppressed, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed

Example

cURL
curl -X POST https://api.relayara.com/v1/webhooks \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourdomain.com/webhooks/relayara",
    "events": [
      "email.delivered",
      "email.bounced"
    ]
  }'

Response 201

The endpoint, including its signing secret.

  • object

    stringRequired

    always webhook

  • id

    stringRequired

  • url

    stringRequired

  • events

    string[]Required

    each one of email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.failed, email.scheduled, email.suppressed, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed

  • enabled

    booleanRequired

  • consecutive_failures

    integerRequired

    at least 0

  • last_failure_at

    string | nullRequired

  • last_success_at

    string | nullRequired

  • disabled_at

    string | nullRequired

  • created_at

    stringRequired

  • secret

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/webhooks

List webhook endpoints

Returns every endpoint registered for the account.

This endpoint needs a full key.

Example

cURL
curl https://api.relayara.com/v1/webhooks \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The endpoints of the account.

  • object

    stringRequired

    always list

  • data

    object[]Required

    • object

      stringRequired

      always webhook

    • id

      stringRequired

    • url

      stringRequired

    • events

      string[]Required

      each one of email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.failed, email.scheduled, email.suppressed, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed

    • enabled

      booleanRequired

    • consecutive_failures

      integerRequired

      at least 0

    • last_failure_at

      string | nullRequired

    • last_success_at

      string | nullRequired

    • disabled_at

      string | nullRequired

    • created_at

      stringRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/webhooks/{id}

Retrieve a webhook endpoint

Reads one endpoint. The signing secret is not included.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Endpoint identifier.

Example

cURL
curl https://api.relayara.com/v1/webhooks/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The endpoint.

  • object

    stringRequired

    always webhook

  • id

    stringRequired

  • url

    stringRequired

  • events

    string[]Required

    each one of email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.failed, email.scheduled, email.suppressed, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed

  • enabled

    booleanRequired

  • consecutive_failures

    integerRequired

    at least 0

  • last_failure_at

    string | nullRequired

  • last_success_at

    string | nullRequired

  • disabled_at

    string | nullRequired

  • created_at

    stringRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

PATCHhttps://api.relayara.com/v1/webhooks/{id}

Update a webhook endpoint

Changes the target, the subscribed events or whether the endpoint is enabled. At least one of the three has to be supplied.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Endpoint identifier.

Request body

  • url

    stringOptional

    at most 2048 characters, format uri

  • events

    string[]Optional

    at least 1 entries, each one of email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.failed, email.scheduled, email.suppressed, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed

  • enabled

    booleanOptional

Example

cURL
curl -X PATCH https://api.relayara.com/v1/webhooks/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourdomain.com/webhooks/relayara",
    "events": [
      "email.delivered",
      "email.bounced"
    ],
    "enabled": false
  }'

Response 200

The updated endpoint.

  • object

    stringRequired

    always webhook

  • id

    stringRequired

  • url

    stringRequired

  • events

    string[]Required

    each one of email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.failed, email.scheduled, email.suppressed, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed

  • enabled

    booleanRequired

  • consecutive_failures

    integerRequired

    at least 0

  • last_failure_at

    string | nullRequired

  • last_success_at

    string | nullRequired

  • disabled_at

    string | nullRequired

  • created_at

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

DELETEhttps://api.relayara.com/v1/webhooks/{id}

Delete a webhook endpoint

Removes an endpoint. Deliveries already in flight are not recalled.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Endpoint identifier.

Example

cURL
curl -X DELETE https://api.relayara.com/v1/webhooks/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 204

The endpoint was removed.

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

Suppressions

Addresses that must not be written to.

GEThttps://api.relayara.com/v1/suppressions

List suppressed addresses

Returns the suppression list of the account, newest first, paged through after.

This endpoint needs a full key.

Query parameters

  • email

    stringOptional

    Substring filter on the address.

    at most 320 characters

  • limit

    integerOptional

    Entries per page.

    defaults to 50, at least 1, at most 200

  • after

    stringOptional

    Identifier of the last entry of the previous page.

    at most 64 characters

Example

cURL
curl https://api.relayara.com/v1/suppressions \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

One page of the suppression list.

  • object

    stringRequired

    always list

  • data

    object[]Required

    • object

      stringRequired

      always suppression

    • id

      stringRequired

    • email

      stringRequired

    • reason

      stringRequired

      hard_bouncecomplaintmanualspam_trap

    • source

      stringRequired

    • created_at

      stringRequired

  • has_more

    booleanRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/suppressions

Suppress an address

Adds an address by hand. Only the reason manual is accepted; the provider driven reasons are assertions about what happened at delivery time and are written by the ingest path alone.

This endpoint needs a full key.

Request body

  • email

    stringRequired

    3 to 320 characters

  • reason

    stringOptional

    always manual, defaults to manual

Example

cURL
curl -X POST https://api.relayara.com/v1/suppressions \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]"
  }'

Response 201

The entry was created.

  • object

    stringRequired

    always suppression

  • id

    stringRequired

  • email

    stringRequired

  • reason

    stringRequired

    hard_bouncecomplaintmanualspam_trap

  • source

    stringRequired

  • created_at

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

DELETEhttps://api.relayara.com/v1/suppressions/{email}

Remove a suppressed address

Makes an address sendable again. A deliberate act with consequences for the sending reputation, which is why it is a call of its own rather than a side effect of anything else.

This endpoint needs a full key.

Path parameters

  • email

    stringRequired

    The suppressed address. Percent encode it; the plus sign and the at sign both survive decoding intact.

Example

cURL
curl -X DELETE https://api.relayara.com/v1/suppressions/customer%40example.com \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The entry was removed.

  • object

    stringRequired

    always suppression

  • deleted

    booleanRequired

    always true

  • email

    stringRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

Usage

Consumption, limits and applications.

GEThttps://api.relayara.com/v1/usage

Report consumption and limits

Returns the limits in force plus consumption per day. Everything counts recipients rather than messages, because that is what the limit is enforced on.

This endpoint needs a full key.

Query parameters

  • from

    stringOptional

    First day to report, inclusive, as YYYY-MM-DD.

    matches ^\d{4}-\d{2}-\d{2}$

  • to

    stringOptional

    Last day to report, inclusive, as YYYY-MM-DD.

    matches ^\d{4}-\d{2}-\d{2}$

Example

cURL
curl https://api.relayara.com/v1/usage \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

Limits and consumption.

  • object

    stringRequired

    always usage

  • quota

    objectRequired

    • tier

      stringRequired

      trialstandardtrustedenterprise

    • daily_limit

      integerRequired

    • monthly_limit

      integerRequired

    • rate_per_second

      integerRequired

    • max_recipients

      integerRequired

    • attachment_max_bytes

      integerRequired

  • recipients_today

    integerRequired

  • recipients_this_month

    integerRequired

  • data

    object[]Required

    • date

      stringRequired

    • recipients

      integerRequired

    • messages

      integerRequired

    • attachment_bytes

      stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/quota-requests

Apply for a higher limit

Files an application for a higher daily limit. The use case is required and is the whole basis of the decision.

This endpoint needs a full key.

Request body

  • requested_daily

    integerRequired

    greater than 0, at most 10000000

  • requested_rate

    integerOptional

    greater than 0, at most 10000

  • use_case

    stringRequired

    50 to 4000 characters

Example

cURL
curl -X POST https://api.relayara.com/v1/quota-requests \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "requested_daily": 50000,
    "requested_rate": 25,
    "use_case": "Order confirmations and password resets for our shop, sent only to customers who placed an order."
  }'

Response 201

The application was filed.

  • object

    stringRequired

    always quota_request

  • id

    stringRequired

  • status

    stringRequired

    pendingapprovedrejectedneeds_info

  • requested_daily

    integerRequired

  • requested_rate

    integer | nullRequired

  • created_at

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/quota-requests

List limit applications

Returns every application the account has filed.

This endpoint needs a full key.

Example

cURL
curl https://api.relayara.com/v1/quota-requests \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The applications of the account.

  • object

    stringRequired

    always list

  • data

    object[]Required

    • object

      stringRequired

      always quota_request

    • id

      stringRequired

    • status

      stringRequired

      pendingapprovedrejectedneeds_info

    • requested_daily

      integerRequired

    • requested_rate

      integer | nullRequired

    • created_at

      stringRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

Logs

The record of the calls an account made.

GEThttps://api.relayara.com/v1/logs

List API requests

Returns the calls this account made, newest first. One entry per request: which endpoint, which method, what was answered and how long it took. This is the record of the call rather than of the mail, so it also covers requests that were refused and therefore produced no message.

Nothing a request carried is kept. No body, no query string, no recipient address and no client address, and endpoint is the route as it is registered rather than the URL that was called, because the URL of a suppression delete is itself an address.

Only authenticated requests appear. A call with a missing, unknown, revoked or expired key belongs to no account and is therefore in no account's log.

This endpoint needs a full key.

Query parameters

  • limit

    integerOptional

    Entries per page.

    defaults to 50, at least 1, at most 100

  • after

    stringOptional

    Identifier of the last entry of the previous page.

    1 to 64 characters

  • status_code

    integerOptional

    Exact response status, so 422 rather than a class of codes.

    at least 100, at most 599

  • source

    stringOptional

    Entry point the call arrived through.

    apismtp

  • created_after

    stringOptional

    Oldest request to include, as RFC 3339.

    format date-time

  • created_before

    stringOptional

    Newest request to include, as RFC 3339.

    format date-time

Example

cURL
curl https://api.relayara.com/v1/logs \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

One page of the request log.

  • object

    stringRequired

    always list

  • data

    object[]Required

    • object

      stringRequired

      always request_log

    • id

      stringRequired

    • api_key_id

      stringRequired

    • method

      stringRequired

      GETPOSTPUTPATCHDELETEHEADOPTIONS

    • endpoint

      stringRequired

    • status_code

      integerRequired

    • duration_ms

      integerRequired

    • user_agent

      string | nullRequired

    • source

      stringRequired

      apismtp

    • created_at

      stringRequired

  • has_more

    booleanRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 429rate_limit_exceeded
  • 500internal_error

Billing

Reading the subscription, starting a checkout and opening the customer portal.

GEThttps://api.relayara.com/v1/billing

Report the plan and the subscription

Returns what the account is on and whether anything is being paid for. Read from our own records rather than from Stripe, so the answer is the same state every limit is enforced against.

This endpoint needs a full key.

Example

cURL
curl https://api.relayara.com/v1/billing \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The plan, and the subscription when there is one.

  • object

    stringRequired

    always billing_state

  • plan

    stringRequired

  • subscription

    object | nullRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/billing/checkout-sessions

Start a subscription

Opens a checkout for one of the published plans and returns the client secret needed to mount the payment form. The form is Stripe's and runs inside your own page; there is no URL to redirect to. Nothing is subscribed until the payment completes and Stripe reports it, so a session that is never finished changes nothing.

This endpoint needs a full key.

Request body

This body rejects properties it does not name, unlike the rest of the API, which drops them.

  • plan

    stringRequired

    matches ^[a-z0-9_]{1,40}$

Example

cURL
curl -X POST https://api.relayara.com/v1/billing/checkout-sessions \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "plan": "growth"
  }'

Response 201

The session, and the secret the form needs.

  • object

    stringRequired

    always checkout_session

  • id

    stringRequired

  • client_secret

    stringRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

GEThttps://api.relayara.com/v1/billing/checkout-sessions/{id}

Report how a checkout ended

Returns the state of a checkout session, so the page the customer lands on can tell them what happened. This grants nothing: the plan an account is on is decided by the signed event Stripe sends us, never by this call. A session belonging to another account answers not_found.

This endpoint needs a full key.

Path parameters

  • id

    stringRequired

    Checkout session identifier.

Example

cURL
curl https://api.relayara.com/v1/billing/checkout-sessions/cl9m2h4vk0000qzrmn831i7rn \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The session.

  • object

    stringRequired

    always checkout_session

  • id

    stringRequired

  • status

    stringRequired

    opencompleteexpired

  • payment_status

    stringRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

POSThttps://api.relayara.com/v1/billing/portal-sessions

Open the billing portal

Returns a URL to the billing portal, where a plan can be changed, a payment method updated and a subscription cancelled. Requires an account that has completed a checkout at least once; one that has not answers not_found. Changes made there reach us through the same signed event path as everything else.

This endpoint needs a full key.

Example

cURL
curl -X POST https://api.relayara.com/v1/billing/portal-sessions \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 201

The portal session.

  • object

    stringRequired

    always portal_session

  • url

    stringRequired

    format uri

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

Account

Reading and changing settings for the account as a whole, currently open and click tracking, off by default.

Read this before you switch tracking on

  • The setting covers the whole account. Amazon SES attaches tracking to a configuration set and Relayara keeps one of those per account, so switching it on applies to every domain you send from. There is no narrower setting, and there is no way to have it on for a newsletter domain and off for the domain your password resets go out from.
  • Click tracking rewrites every link in your messages. Each URL in the body is replaced by one that points at a redirect host and forwards to the original, so the address a recipient sees, hovers over and later finds in their history is not the address you wrote. A password reset, a sign in link and a confirmation link all travel through that host on the way to their destination. Open tracking adds a one pixel image to the HTML body and changes nothing else.
  • Opens and clicks are two separate switches, because SES reports them as two event types. Both are off for a new account and stay off until you deliberately turn them on. That default is on purpose: both record personal data about your recipients, including their address, their IP and the moment they opened or clicked, and you are the controller of that data while we process it for you.

GEThttps://api.relayara.com/v1/account/tracking

Read the engagement tracking settings

Returns whether opens and clicks are being recorded. Both are off for a new account and stay off until switched on here.

This endpoint needs a full key.

Example

cURL
curl https://api.relayara.com/v1/account/tracking \
  -H "Authorization: Bearer $RELAYARA_API_KEY"

Response 200

The settings in force.

  • open_tracking

    booleanRequired

  • click_tracking

    booleanRequired

Errors

  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

PATCHhttps://api.relayara.com/v1/account/tracking

Change the engagement tracking settings

Switches open and click tracking on or off. Either field may be sent on its own; an empty body is refused.

The setting applies to **the whole account, not to a single domain**. Amazon SES attaches tracking to a configuration set and Relayara keeps one per account, so there is no narrower setting to offer. Switching tracking on affects every domain the account sends from.

**Click tracking rewrites the links in your messages.** Every URL in the body is replaced with one that points at a redirect host and forwards to the original, so the address a recipient sees, hovers over and finds in their history is not the address you wrote. Weigh that for one time links in particular: a password reset or sign in link travels through a third host before reaching its destination. Open tracking adds a one pixel image to the HTML body and changes nothing else.

Both record personal data about your recipients, including their IP address and the time they opened or clicked. You are the controller of that data and we process it on your behalf, which is why it is off unless you ask for it.

This endpoint needs a full key.

Request body

  • open_tracking

    booleanOptional

  • click_tracking

    booleanOptional

Example

cURL
curl -X PATCH https://api.relayara.com/v1/account/tracking \
  -H "Authorization: Bearer $RELAYARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Response 200

The settings after the change.

  • open_tracking

    booleanRequired

  • click_tracking

    booleanRequired

Errors

  • 400validation_error
  • 401missing_api_keyrestricted_api_key
  • 403account_suspendedexpired_api_keyinvalid_api_key
  • 404not_found
  • 429rate_limit_exceeded
  • 500internal_error

Event delivery

Event delivered to a webhook endpoint

Sent to every enabled endpoint subscribed to the event.

Verify it before trusting it: the signed content is ${svix-id}.${svix-timestamp}.${raw body}, the secret is the part after whsec_ base64 decoded, the algorithm is HMAC SHA256, the result is base64, and the comparison has to run in constant time. Reject a timestamp more than five minutes away in either direction.

Events: email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.failed, email.scheduled, email.suppressed, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed.

data carries at least email_id, from, to, subject and created_at. email.bounced adds a bounce object described by the BounceDetail schema, whose field names are camelCase while everything around them is snake_case. That is how Resend emits it.

Answer with any 2xx. Anything else is retried with backoff, and an endpoint that keeps failing is disabled.

Headers

  • svix-id

    stringRequired

    Unique identifier of this delivery.

  • svix-timestamp

    stringRequired

    Seconds since the epoch, not milliseconds.

  • svix-signature

    stringRequired

    One or more signatures of the form `v1,<base64>`, separated by spaces.

Request body

  • type

    stringRequired

    email.sentemail.deliveredemail.delivery_delayedemail.bouncedemail.complainedemail.openedemail.clickedemail.failedemail.scheduledemail.suppresseddomain.createddomain.updateddomain.deletedsuppression.addedsuppression.removed

  • created_at

    stringRequired

  • data

    objectRequired

    any key, any value

The path to a first message is covered by the quickstart

API reference, Relayara