Risu Mail

API documentation

HTTP APIs live on the same host as the app. Use the guides below to authenticate, queue mail, and send OTPs.

Introduction

Base URL for this deployment:

https://risumail.vercel.app
  • Create secret keys in Dashboard → Mail API.
  • Queued mail uses the Mail API; OTP routes send over SMTP in the request.
  • Use the interactive studio at the bottom to copy snippets or run a test send.

Get started in 60 seconds

  1. 1

    Create an API key

    In the dashboard, create a key with send permission.

  2. 2

    Send your first email

    Replace YOUR_API_KEY and run:

  3. 3

    Done

    You should get QUEUED in the JSON response. Track delivery in Logs.

curl -X POST "https://risumail.vercel.app/api/v1/emails" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"hello@example.com","subject":"Hello from Risu Mail","text":"Your first email is queued."}'

Mail API

Queue-based sending for templates and transactional mail. Workers deliver asynchronously.

  • Mail API POST /api/v1/emails and POST /api/v1/templates/send return queued status.
  • OTP (browser / instant) — direct SMTP in the same HTTP request; not the template queue.
Advanced: OTP paths and dashboards
  • Server OTP POST /api/v1/backend-otp/send uses your secret key only. See Server OTP API.
  • Browser OTP /api/v1/instant-otp/* with risu_otp_… or secret key; CORS rules apply. Dashboard → OTP API.

Queue an email

POSThttps://risumail.vercel.app/api/v1/emails

Headers: Content-Type: application/json

  • to — one email or array (required).
  • subject — required, max 998 characters.
  • At least one of: html, text, templateId, or imageUrl.
  • templateId — optional; bodies from template if html/text omitted.
  • vars — replaces {{key}} placeholders (string / number / boolean).
  • imageUrl — optional https URL for image-style messages.

Success: 200 with { "success": true, "data": { "id": "<id>", "status": "QUEUED" } }

Send from template (queued)

POSThttps://risumail.vercel.app/api/v1/templates/send

Same queued pipeline as POST /api/v1/emails. Typical body: to, templateId, optional vars, overrides, and optional senderEmailId.

List sends

GEThttps://risumail.vercel.app/api/v1/emails?page=1&limit=20

Paginated list for the authenticated user. limit capped at 100.

Hosted forms

GET/f/{formId}
POST/api/f/{formId}
  • GET — hosted UI (iframe or direct link).
  • POST — JSON or multipart/form-data; responses include submissionId, saved, emailQueued, optional queuedEmailId, redirectUrl.

OTP API

Instant SMTP delivery; codes are stored hashed — the response does not include the OTP.

Send email OTP

POSThttps://risumail.vercel.app/api/v1/instant-otp/send

Legacy alias: POST https://risumail.vercel.app/api/v1/otp/send

  • email (required) — recipient.
  • Optional: from, subject, verificationLine, otpDigits, expiresInSeconds.

Success: 200 with sessionId, expiresAt, to, sent. Counts toward monthly quota.

curl -X POST "https://risumail.vercel.app/api/v1/instant-otp/send" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com"}'

Verify OTP

POSThttps://risumail.vercel.app/api/v1/instant-otp/verify

Legacy: POST https://risumail.vercel.app/api/v1/otp/verify

Body: sessionId, email, code.

Errors: INVALID_CODE, EXPIRED, LOCKED, NOT_FOUND.

curl -X POST "https://risumail.vercel.app/api/v1/instant-otp/verify" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sessionId":"<sessionId>","email":"user@example.com","code":"123456"}'

List verified OTP sessions

GEThttps://risumail.vercel.app/api/v1/instant-otp/verifications?limit=50

Requires both Authorization: Bearer risu_otp_… and X-Otp-Secret: risu_otp_sec_…. Same CORS and IP rules as send/verify. Legacy: GET …/api/v1/otp/verifications

Server OTP API (secret key only)

POSThttps://risumail.vercel.app/api/v1/backend-otp/send
POSThttps://risumail.vercel.app/api/v1/backend-otp/verify
GEThttps://risumail.vercel.app/api/v1/backend-otp/verifications
  • Use Authorization: Bearer risu_live_… with send permission.
  • Direct SMTP in the request — does not use the Mail API template queue.
  • Optional env CORS via API_CORS_ALLOWLIST. risu_otp_… tokens are rejected here.

Email verification by OTP

Separate OTP flow for verifying an email address.

POSThttps://risumail.vercel.app/api/v1/email-verification/send
POSThttps://risumail.vercel.app/api/v1/email-verification/verify
  • send — body: email, optional from, subject, etc. Returns sessionId.
  • verify — body: sessionId, email, code.

Authentication

  • Secret API keys (risu_live_…): Mail API routes and /api/v1/backend-otp/* use Authorization: Bearer … with send permission.
  • Browser OTP /api/v1/instant-otp/send and /verify accept the secret key or OTP client keys (risu_otp_…). Keys need at least one allowed hostname; browser Origin must match.
  • 403CORS_NOT_CONFIGURED (missing hostnames) or ORIGIN_NOT_ALLOWED.

Examples

Build requests, switch languages, copy snippets, or run a live test against this deployment (paste a real API key).

Interactive API studio

Configure the request, copy multi-language snippets, or run a live test.

Checking session…·Authentication

Endpoint

POST/api/v1/templates/send

Paste your secret key. Do not ship this to the browser in production.

Target email

One per line, or comma-separated.

Language

-- Add at least one recipient in “Target email”.

Error codes

Common responses when queueing mail:

  • VALIDATION_ERROR (400) — JSON or field rules.
  • NOT_FOUND (404) — template not in your account.
  • QUOTA_EXCEEDED / IMAGE_QUOTA_EXCEEDED (403) — plan limits.
  • SMTP_NOT_CONFIGURED (503) — SMTP pool not configured.
Infrastructure (advanced)

The app uses MongoDB (DATABASE_URL). Outbound mail is queued as documents and sent by the embedded worker or npm run worker:email.

Ready to start sending emails?

Create a key and send from your backend in minutes.

Get API Key