Email API

The API you know, on infrastructure you trust.

A REST API compatible with Resend, delivering through Amazon SES. Send, schedule and receive email, manage domains and keys, and subscribe to every delivery event.

send.ts · npm i resend
import { Resend } from 'resend';

// RESEND_BASE_URL=https://bokimo.ai/api/resend
const bokimo = new Resend(process.env.BOKIMO_API_KEY);

await bokimo.emails.send({
  from: 'Acme <[email protected]>',
  to: ['[email protected]'],
  subject: 'Your invoice is ready',
  html: '<p>Thanks for your order.</p>',
  tags: [{ name: 'category', value: 'billing' }],
});

Press Run to see the response.

Base URL

https://bokimo.ai/api/resend

Authentication

Authorization: Bearer <API_KEY>

Create keys in the dashboard or with POST /api-keys. Keys can be full-access or restricted to sending from one domain.

Existing API

The original /api/v1 endpoints and the @bokimo/email-sdk package keep working unchanged.

Resend compatibility

Swap the base URL, keep the code.

Requests, responses and error shapes follow the Resend API, so the official SDKs work as-is. Set one environment variable and use a Bokimo key.

.env
RESEND_BASE_URL=https://bokimo.ai/api/resend
RESEND_API_KEY=<your Bokimo API key>
  • html, text, cc, bcc, reply_to, headers, tags and attachments
  • scheduled_at as ISO 8601 or natural language, e.g. “in 1 hour”
  • template: { id, variables } using templates stored in Bokimo
  • Idempotency-Key header and x-batch-validation for batches
  • Not yet supported: broadcasts and server-side React rendering

Reference

Endpoints

All paths are relative to https://bokimo.ai/api/resend.

Emails

POST/emailsSend an email
POST/emails/batchSend up to 100 emails
GET/emailsList sent emails
GET/emails/:idRetrieve an email
PATCH/emails/:idReschedule a scheduled email
POST/emails/:id/cancelCancel a scheduled email

Receiving

GET/emails/receivingList received emails
GET/emails/receiving/:idRetrieve a received email
GET/emails/receiving/:id/attachmentsList attachments with download links

Domains

POST/domainsAdd a domain
GET/domainsList domains
GET/domains/:idRetrieve a domain and its DNS records
POST/domains/:id/verifyRefresh verification
DELETE/domains/:idRemove a domain

API keys

POST/api-keysCreate a key
GET/api-keysList keys
DELETE/api-keys/:idRevoke a key

Webhooks

POST/webhooksRegister an endpoint
GET/webhooksList endpoints
PATCH/webhooks/:idUpdate events or status
POST/webhooks/:id/signing-secret/rotateRotate the signing secret
DELETE/webhooks/:idRemove an endpoint

Contacts and segments

POST/contactsCreate a contact
GET/contacts/:id_or_emailRetrieve a contact
PATCH/contacts/:id_or_emailUpdate a contact
POST/segmentsCreate a segment
POST/contacts/:id/segments/:segment_idAdd a contact to a segment

Errors

Errors return { statusCode, name, message }.

401missing_api_keyNo Authorization header
401restricted_api_keySending-only key used on another endpoint
403invalid_api_keyKey is unknown or revoked
404not_foundResource does not exist
422validation_errorA field is invalid
422missing_required_fieldA required field is missing
429rate_limit_exceededToo many requests

Webhooks

Every event, signed.

Register an https endpoint and choose the events you want. Payloads are { type, created_at, data } and signed with the Svix scheme.

email.sentAccepted by SES
email.deliveredDelivered to the recipient’s server
email.delivery_delayedDelivery is being retried
email.bouncedPermanently rejected
email.complainedMarked as spam
email.openedOpened by the recipient
email.clickedA link was clicked
email.failedCould not be sent
email.scheduledScheduled for later
email.receivedInbound message arrived
verify.ts
import { Webhook } from 'svix';

const wh = new Webhook(process.env.BOKIMO_WEBHOOK_SECRET); // whsec_...

export async function POST(req: Request) {
  const payload = await req.text();
  const event = wh.verify(payload, {
    'svix-id': req.headers.get('svix-id'),
    'svix-timestamp': req.headers.get('svix-timestamp'),
    'svix-signature': req.headers.get('svix-signature'),
  });
  // event.type === 'email.delivered', 'email.received', ...
  return new Response('ok');
}

Inbound email

Set up receiving in three steps.

Inbound mail is routed to the organization that owns the recipient’s domain and stored with its attachments.

  1. 01

    Publish the MX record

    GET /domains/:id returns a Receiving record pointing your domain at inbound-smtp.<region>.amazonaws.com.

  2. 02

    Add an SES receipt rule

    Publish to the Bokimo SNS topic, using an SNS action for small messages or an S3 action for large ones.

  3. 03

    Subscribe to email.received

    Fetch the message with GET /emails/receiving/:id and its attachments through signed, expiring links.

Send your first email in minutes.

Free to start. Verify a domain, create an API key, and send through the SDK you already use.