Sendardocs
Jump to content

API reference

Sendar API reference

Send and manage application email with predictable HTTP requests. Explore endpoints, choose your language and copy an example.

New to Sendar?

Start with the setup guide to verify your domain and create an API key. These examples use your private server-side key.

Authentication

Authenticate your API requests by providing your API key in the Authorization header as a Bearer token. You can manage your API keys in the dashboard — sign up free to create one.

Authorization: Bearer sndr_xxxxxxxxxxxx

All endpoints below accept API-key authentication. The base URL for every request is https://sendar.app/api.

Sending Email API

Everything you need to send and manage emails programmatically. Pick your language — every example updates to match.

Send Email

Send a single email. The domain in the from address must be added and verified in your account first.

  • •Provide html, text, or both — at least one is required (or pass templateId instead, see Send with a Template).
  • •Add scheduledAt (ISO 8601, up to 30 days ahead) to schedule the send instead of delivering immediately. Scheduled sending is available on the Growth plan and above.
  • •Attach files with attachments: up to 5 files, 1.3MB total, content base64-encoded.
  • •Set trackOpens / trackClicks (booleans) to record opens and link clicks for this email — omit them to use your account defaults from Settings. Tracking only works on HTML bodies: opens use an invisible pixel, clicks rewrite links through a redirect.
  • •Every plan includes a monthly sending quota (3,000 emails per month on Free — see the Pricing page); requests over the limit return a 429 error. Canceled emails don't count toward the quota.
POST/emails
Node.js
const response = await fetch("https://sendar.app/api/emails", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "from": "Acme <hello@acme.com>",
    "to": [
      "delivered@example.com"
    ],
    "subject": "Hello World",
    "html": "<p>It works!</p>"
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "id": 42,
  "providerEmailId": "0100019a7f3d2c8e-…",
  "fromAddress": "Acme <hello@acme.com>",
  "toAddresses": [
    "delivered@example.com"
  ],
  "subject": "Hello World",
  "status": "sent",
  "errorMessage": null,
  "scheduledAt": null,
  "trackOpens": false,
  "trackClicks": false,
  "openedAt": null,
  "clickedAt": null,
  "openCount": 0,
  "clickCount": 0,
  "createdAt": "2026-07-15T16:00:00.000Z",
  "updatedAt": "2026-07-15T16:00:01.000Z"
}

Send Batch Emails

Send up to 100 emails in one request. The batch is validated as a whole — if any item is invalid, nothing is sent. Accepted emails are queued and delivered asynchronously within seconds.

  • •Batch items don't support attachments or scheduledAt — use the single send endpoint for those.
  • •The response returns each email with status "queued"; poll Retrieve Email to see the final status.
  • •Each batch item counts toward your plan's monthly quota; a batch that would exceed it is rejected with a 429 error.
POST/emails/batch
Node.js
const response = await fetch("https://sendar.app/api/emails/batch", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify([
    {
      "from": "Acme <hello@acme.com>",
      "to": [
        "customer-one@example.com"
      ],
      "subject": "Your receipt",
      "html": "<p>Thanks for your order!</p>"
    },
    {
      "from": "Acme <hello@acme.com>",
      "to": [
        "customer-two@example.com"
      ],
      "subject": "Your receipt",
      "text": "Thanks for your order!"
    }
  ]),
});

const data = await response.json();
console.log(data);
Response (trimmed — each item is a full email object)
{
  "data": [
    {
      "id": 43,
      "status": "queued",
      "subject": "Your receipt"
    },
    {
      "id": 44,
      "status": "queued",
      "subject": "Your receipt"
    }
  ]
}

Retrieve Email

Fetch a single email by id, including its current delivery status.

GET/emails/{id}
Node.js
const response = await fetch("https://sendar.app/api/emails/42", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
{
  "id": 42,
  "providerEmailId": "0100019a7f3d2c8e-…",
  "fromAddress": "Acme <hello@acme.com>",
  "toAddresses": [
    "delivered@example.com"
  ],
  "subject": "Hello World",
  "status": "sent",
  "errorMessage": null,
  "scheduledAt": null,
  "trackOpens": true,
  "trackClicks": true,
  "openedAt": "2026-07-15T16:03:40.000Z",
  "clickedAt": "2026-07-15T16:04:12.000Z",
  "openCount": 2,
  "clickCount": 1,
  "createdAt": "2026-07-15T16:00:00.000Z",
  "updatedAt": "2026-07-15T16:00:01.000Z"
}

List Email Events

List the open and click events recorded for an email, newest first. Events only exist for emails sent with trackOpens or trackClicks enabled.

  • •Enable tracking per send with the trackOpens / trackClicks flags, or account-wide in Settings. Tracking only works on HTML emails.
  • •Some inboxes preload images and scan links automatically, so counts can include automated opens and clicks — treat them as engagement signals, not exact reads.
  • •The email row itself carries the rollup: openCount, clickCount, and the first openedAt / clickedAt timestamps.
GET/emails/{id}/events
Node.js
const response = await fetch("https://sendar.app/api/emails/42/events", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
[
  {
    "id": 2,
    "type": "click",
    "url": "https://acme.com/pricing",
    "occurredAt": "2026-07-15T16:04:12.000Z"
  },
  {
    "id": 1,
    "type": "open",
    "url": null,
    "occurredAt": "2026-07-15T16:03:40.000Z"
  }
]

Update Email

Reschedule a scheduled email. Only emails created with scheduledAt that haven't been sent or canceled yet can be updated.

  • •The new scheduledAt must be in the future and at most 30 days ahead. Requires a plan with scheduled sending (Growth and above).
  • •Returns the updated email object.
PATCH/emails/{id}
Node.js
const response = await fetch("https://sendar.app/api/emails/42", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "scheduledAt": "2026-08-01T09:00:00Z"
  }),
});

const data = await response.json();
console.log(data);

Cancel Email

Cancel a scheduled email before it is sent. Only scheduled emails that are still queued can be canceled.

  • •Returns the email object with status "canceled".
POST/emails/{id}/cancel
Node.js
const response = await fetch("https://sendar.app/api/emails/42/cancel", {
  method: "POST",
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);

List Emails

List your most recent emails, newest first. Use the limit query parameter (1–100, default 50).

  • •Returns an array of email objects.
GET/emails
Node.js
const response = await fetch("https://sendar.app/api/emails?limit=50", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);

List Attachments

List the attachments of an email. Returns metadata only — use Retrieve Attachment to get the file content.

GET/emails/{id}/attachments
Node.js
const response = await fetch("https://sendar.app/api/emails/42/attachments", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
[
  {
    "id": 7,
    "emailId": 42,
    "filename": "receipt.pdf",
    "contentType": "application/pdf",
    "sizeBytes": 24576,
    "createdAt": "2026-07-15T16:00:00.000Z"
  }
]

Retrieve Attachment

Fetch a single attachment including its content. The content field is base64-encoded — decode it to get the original file bytes.

GET/emails/{id}/attachments/{attachmentId}
Node.js
const response = await fetch("https://sendar.app/api/emails/42/attachments/7", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
{
  "id": 7,
  "emailId": 42,
  "filename": "receipt.pdf",
  "contentType": "application/pdf",
  "sizeBytes": 24576,
  "content": "JVBERi0xLjQKJcTl…",
  "createdAt": "2026-07-15T16:00:00.000Z"
}

List Suppressions

List the addresses on your suppression list — recipients that hard-bounced or reported an email as spam. Sends to these addresses are rejected with a 400 error so they never count against your quota or reputation.

  • •reason is one of: bounce (delivery hard-bounced), complaint (recipient reported spam), other (blocked at the delivery provider for another reason).
  • •Suppressions are detected automatically within a few minutes of the bounce or complaint. The triggering email's status changes to bounced or complained, and email.bounced / email.complained webhook events fire.
GET/suppressions
Node.js
const response = await fetch("https://sendar.app/api/suppressions", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
[
  {
    "id": 3,
    "email": "bounced@example.com",
    "reason": "bounce",
    "suppressedAt": "2026-07-20T10:12:00.000Z",
    "createdAt": "2026-07-20T10:14:02.000Z"
  }
]

Remove Suppression

Remove an address from your suppression list so future sends can reach it again.

  • •Only remove an address when you're confident the mailbox exists and wants your mail — repeated bounces and complaints damage your sender reputation.
  • •Returns 204 No Content on success.
DELETE/suppressions/{id}
Node.js
const response = await fetch("https://sendar.app/api/suppressions/3", {
  method: "DELETE",
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);

Send with a Template

Send a saved template by id instead of passing inline content. The template's subject and HTML are resolved with your variables at send time, and the sent email stores the resolved result — editing or deleting the template later never changes what was already sent.

  • •When templateId is set, subject, html, and text must be omitted — the template supplies them.
  • •variables is checked strictly: every {{placeholder}} in the template needs a value, and unknown keys are rejected. Values are HTML-escaped automatically.
  • •Batch sends support templateId and variables per item, so one request can send the same template to many recipients with different values.
  • •Works with scheduledAt and attachments exactly like a normal send.
POST/emails
Node.js
const response = await fetch("https://sendar.app/api/emails", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "from": "Acme <hello@acme.com>",
    "to": [
      "delivered@example.com"
    ],
    "templateId": 5,
    "variables": {
      "first_name": "Ada",
      "workspace": "acme-inc"
    }
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "id": 43,
  "from": "Acme <hello@acme.com>",
  "to": [
    "delivered@example.com"
  ],
  "subject": "Welcome to Acme, Ada!",
  "status": "sent",
  "createdAt": "2026-07-15T12:01:30.000Z"
}

Create Template

Save a reusable email template. Use {{variable}} placeholders anywhere in the subject or HTML and supply per-recipient values when sending.

  • •Placeholder names use letters, digits, and underscores, and must not start with a digit — {{first_name}}, {{code2}}.
  • •The response includes variables: every placeholder detected in the subject and body.
  • •Each plan includes a number of saved templates (3 on Free — see the Pricing page).
POST/templates
Node.js
const response = await fetch("https://sendar.app/api/templates", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Welcome",
    "subject": "Welcome to Acme, {{first_name}}!",
    "html": "<h1>Hi {{first_name}}</h1><p>Your workspace {{workspace}} is ready.</p>"
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "id": 5,
  "name": "Welcome",
  "subject": "Welcome to Acme, {{first_name}}!",
  "html": "<h1>Hi {{first_name}}</h1><p>Your workspace {{workspace}} is ready.</p>",
  "variables": [
    "first_name",
    "workspace"
  ],
  "createdAt": "2026-07-15T12:00:00.000Z",
  "updatedAt": "2026-07-15T12:00:00.000Z"
}

List Templates

List your saved templates, most recently updated first.

GET/templates
Node.js
const response = await fetch("https://sendar.app/api/templates", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
[
  {
    "id": 5,
    "name": "Welcome",
    "subject": "Welcome to Acme, {{first_name}}!",
    "html": "<h1>Hi {{first_name}}</h1><p>Your workspace {{workspace}} is ready.</p>",
    "variables": [
      "first_name",
      "workspace"
    ],
    "createdAt": "2026-07-15T12:00:00.000Z",
    "updatedAt": "2026-07-15T12:00:00.000Z"
  }
]

Retrieve Template

Fetch a single template, including the variables it uses.

GET/templates/{id}
Node.js
const response = await fetch("https://sendar.app/api/templates/5", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
{
  "id": 5,
  "name": "Welcome",
  "subject": "Welcome to Acme, {{first_name}}!",
  "html": "<h1>Hi {{first_name}}</h1><p>Your workspace {{workspace}} is ready.</p>",
  "variables": [
    "first_name",
    "workspace"
  ],
  "createdAt": "2026-07-15T12:00:00.000Z",
  "updatedAt": "2026-07-15T12:00:00.000Z"
}

Update Template

Update a template's name, subject, or HTML. Only the fields you pass are changed.

  • •Future sends use the new content; emails already sent keep the content they were sent with.
PATCH/templates/{id}
Node.js
const response = await fetch("https://sendar.app/api/templates/5", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "subject": "You're in, {{first_name}} 🎉"
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "id": 5,
  "name": "Welcome",
  "subject": "You're in, {{first_name}} 🎉",
  "html": "<h1>Hi {{first_name}}</h1><p>Your workspace {{workspace}} is ready.</p>",
  "variables": [
    "first_name",
    "workspace"
  ],
  "createdAt": "2026-07-15T12:00:00.000Z",
  "updatedAt": "2026-07-16T09:30:00.000Z"
}

Delete Template

Delete a template. Sends that reference the deleted id will fail with a clear error; already-sent emails are unaffected.

  • •Returns 204 No Content on success.
DELETE/templates/{id}
Node.js
const response = await fetch("https://sendar.app/api/templates/5", {
  method: "DELETE",
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);

Create Audience

Create a contact list for newsletters. Contacts count toward your plan's total across all audiences (250 on Free — see the Pricing page).

POST/audiences
Node.js
const response = await fetch("https://sendar.app/api/audiences", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Product updates"
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "id": 3,
  "name": "Product updates",
  "contactCount": 0,
  "unsubscribedCount": 0,
  "createdAt": "2026-07-20T10:00:00.000Z",
  "updatedAt": "2026-07-20T10:00:00.000Z"
}

Add Contact

Add one contact to an audience. Addresses are stored lowercase; adding the same address to the same audience twice returns a 409 error.

  • •name is optional and fills the {{name}} personalization in broadcasts (falls back to the part before the @).
  • •If the address previously unsubscribed from your emails, it is added with unsubscribed: true and broadcasts will skip it.
  • •Returns 403 when your plan's total contact limit is reached.
POST/audiences/{id}/contacts
Node.js
const response = await fetch("https://sendar.app/api/audiences/3/contacts", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "email": "ada@example.com",
    "name": "Ada Lovelace"
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "id": 71,
  "email": "ada@example.com",
  "name": "Ada Lovelace",
  "unsubscribed": false,
  "createdAt": "2026-07-20T10:05:00.000Z"
}

Import Contacts (CSV)

Bulk-add contacts from CSV text — either bare email,name lines or any column order with a header row naming an email (and optionally name) column.

  • •Up to 10,000 rows per request. Invalid rows and duplicates are skipped and counted, never fatal.
  • •If the file holds more contacts than your plan allows, the import fills the remaining space and reports the rest as skippedOverLimit — re-importing the same file after upgrading picks up where it left off.
POST/audiences/{id}/contacts/import
Node.js
const response = await fetch("https://sendar.app/api/audiences/3/contacts/import", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "csv": "email,name\nada@example.com,Ada Lovelace\ngrace@example.com,Grace Hopper"
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "added": 2,
  "skippedInvalid": 0,
  "skippedDuplicates": 0,
  "skippedOverLimit": 0,
  "totalRows": 2,
  "invalidSamples": []
}

List Contacts

List an audience's contacts, newest first, with their unsubscribe status.

  • •Filter with ?search= (matches email and name). Page with limit (up to 200) and offset.
GET/audiences/{id}/contacts
Node.js
const response = await fetch("https://sendar.app/api/audiences/3/contacts?limit=50&offset=0", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
{
  "data": [
    {
      "id": 71,
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "unsubscribed": false,
      "createdAt": "2026-07-20T10:05:00.000Z"
    }
  ],
  "total": 1
}

Send Broadcast

Send a newsletter to every eligible contact in an audience. Unsubscribed and suppressed addresses are skipped automatically, every email gets a personal unsubscribe link, and delivery drains gradually at a provider-safe pace.

  • •Use {{name}} and {{email}} in subject or html for per-recipient personalization ({{name}} falls back to the address's local part).
  • •Or pass templateId + variables instead of subject/html — name and email are then filled per recipient automatically and must not appear in variables.
  • •Every recipient counts toward your sending quota, checked up front — the broadcast is all-or-nothing.
  • •Recipients' mail apps also get a one-click unsubscribe button (RFC 8058 headers).
POST/broadcasts
Node.js
const response = await fetch("https://sendar.app/api/broadcasts", {
  method: "POST",
  headers: {
    Authorization: "Bearer sndr_xxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "audienceId": 3,
    "from": "Acme <news@acme.com>",
    "subject": "Our July update, {{name}}",
    "html": "<h1>Hi {{name}},</h1><p>Here's what's new...</p>"
  }),
});

const data = await response.json();
console.log(data);
Response
{
  "id": 9,
  "audienceId": 3,
  "audienceName": "Product updates",
  "fromAddress": "Acme <news@acme.com>",
  "subject": "Our July update, {{name}}",
  "status": "sending",
  "totalRecipients": 184,
  "skippedUnsubscribed": 12,
  "skippedSuppressed": 4,
  "counts": {
    "queued": 184,
    "sending": 0,
    "sent": 0,
    "failed": 0,
    "bounced": 0,
    "complained": 0
  },
  "createdAt": "2026-07-20T11:00:00.000Z"
}

Retrieve Broadcast

Fetch a broadcast with live delivery progress. Status is derived from the per-recipient emails: sending while any are queued, then sent (or failed if nothing was delivered).

GET/broadcasts/{id}
Node.js
const response = await fetch("https://sendar.app/api/broadcasts/9", {
  headers: { Authorization: "Bearer sndr_xxxxxxxxxxxx" },
});

const data = await response.json();
console.log(data);
Response
{
  "id": 9,
  "audienceId": 3,
  "audienceName": "Product updates",
  "fromAddress": "Acme <news@acme.com>",
  "subject": "Our July update, {{name}}",
  "status": "sent",
  "totalRecipients": 184,
  "skippedUnsubscribed": 12,
  "skippedSuppressed": 4,
  "counts": {
    "queued": 0,
    "sending": 0,
    "sent": 181,
    "failed": 1,
    "bounced": 2,
    "complained": 0
  },
  "createdAt": "2026-07-20T11:00:00.000Z"
}

Send Email — Request Body

PropertyTypeDescription
from*stringSender email address. Must use a domain added and verified in your account. Supports "Name <email@domain.com>" format.
to*array of strings1–50 recipients, with one mailbox per array entry. Display names are supported. Each recipient counts toward your sending allowance.
subjectstringEmail subject line. Required unless templateId is set.
htmlstringHTML body. At least one of html or text is required (unless templateId is set).
textstringPlain-text body. At least one of html or text is required (unless templateId is set).
templateIdintegerSend using a saved template. When set, subject, html, and text must be omitted — the template supplies them. Create templates on the Templates page or via the API.
variablesobjectString values for the template's {{placeholders}}. Checked strictly: every placeholder needs a value, and unknown keys are rejected. Only valid together with templateId.
scheduledAtstring (ISO 8601)Schedule delivery up to 30 days in the future. Scheduled emails can be rescheduled or canceled until they are sent.
attachmentsarray of objectsUp to 5 files, 1.3MB total. Each item: filename, content (base64), and optional contentType.

Batch items accept the same fields except scheduledAt and attachments.

Webhooks

Configure a webhook to receive real-time updates about email events. Add an endpoint on the Webhooks page — sign up free to get started and Sendar will send it a signed POST request every time a subscribed event happens.

EventSent when
email.sentAn email was accepted by the sending provider.
email.failedA send attempt failed. The payload includes the error message.
email.scheduledAn email was scheduled for later delivery.
email.canceledA scheduled email was canceled before sending.
email.bouncedDelivery hard-bounced and the address was added to your suppression list.
email.complainedThe recipient marked the email as spam and the address was added to your suppression list.
email.openedA recipient opened a tracked email. Only fires for emails sent with open tracking on; the payload includes the running openCount.
email.clickedA recipient clicked a tracked link. Only fires for emails sent with click tracking on; the payload includes the clicked url and clickCount.
email.testA sample event sent from the Test button in the dashboard.
Example payload
{
  "type": "email.sent",
  "createdAt": "2026-07-15T12:00:00.000Z",
  "data": {
    "id": 42,
    "from": "Acme <hello@acme.com>",
    "to": ["user@example.com"],
    "subject": "Welcome to Acme",
    "status": "sent",
    "scheduledAt": null,
    "errorMessage": null,
    "createdAt": "2026-07-15T11:59:58.412Z"
  }
}

Verifying signatures

Every delivery includes an X-Sendar-Signature header: an HMAC-SHA256 of <timestamp>.<raw body> using your endpoint's signing secret (shown under Manage on the Webhooks page). The timestamp is in the X-Sendar-Timestamp header (Unix seconds). Always verify before trusting a payload.

Verify signatures (Node.js)
import crypto from "node:crypto";

// rawBody must be the exact request body bytes, before any JSON parsing.
function verifySendarSignature(headers, rawBody, secret) {
  const timestamp = headers["x-sendar-timestamp"];
  const received = headers["x-sendar-signature"]; // "v1=<hex>"

  const expected = "v1=" + crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  const a = Buffer.from(received ?? "");
  const b = Buffer.from(expected);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    throw new Error("Invalid webhook signature");
  }

  // Reject stale events to prevent replays.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
    throw new Error("Webhook timestamp too old");
  }
}

Deliveries time out after 5 seconds and are retried once after 30 seconds if your endpoint fails or is unreachable. The last 50 delivery attempts per endpoint are visible in the dashboard. Any 2xx response counts as delivered; redirects are not followed.

Need a hand with your integration?Contact Sendar