Orly Email API

Version 1.0.0 - Email Relay Service

Authentication Required

All endpoints require a Bearer token in the Authorization header.

Authorization: Bearer orly_xxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API keys are issued per-project from the admin panel. Keys follow the format orly_<prefix>.<secret> and are shown only once at creation.

Simple API

Single-tenant endpoints that use the server's global SMTP configuration. Authenticated with the global API key.

GET

/api/health

Check API health status

Request:

curl -X GET https://email.getorly.com/api/health \
  -H "Authorization: Bearer $API_KEY"

Response:

{
    "status": "ok",
    "timestamp": "2025-11-09T10:46:25+00:00",
    "service": "Orly Email API",
    "version": "1.0.0"
}
POST

/api/send-email

Send an email synchronously

Parameters

to
Required. Recipient email address
subject
Required. Email subject (max 255 characters)
body
Required. Email body content (plain text or HTML)
priority optional
high, normal (default), or low. Sets X-Priority headers.
html optional
Boolean. Set to true to send body as HTML with an auto-generated plain-text fallback.

Examples

Plain text

curl -X POST https://email.getorly.com/api/send-email \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "recipient@example.com",
    "subject": "Hello",
    "body": "This is a plain text email."
  }'

Raw HTML

Pass any HTML string in body and set html: true.

curl -X POST https://email.getorly.com/api/send-email \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "recipient@example.com",
    "subject": "Welcome!",
    "body": "<!DOCTYPE html><html><body><h1>Welcome</h1><p>Thanks for signing up.</p></body></html>",
    "html": true,
    "priority": "high"
  }'

React Email

Use React Email to design your template, render it with @react-email/render, then pass the output as body.

npm install @react-email/render @react-email/components

1. Create your template:

// emails/WelcomeEmail.tsx
import { Html, Heading, Text, Button } from '@react-email/components';

export default function WelcomeEmail({ name }: { name: string }) {
  return (
    <Html>
      <Heading>Welcome, {name}!</Heading>
      <Text>Thanks for joining us.</Text>
      <Button href="https://email.getorly.com">Get started</Button>
    </Html>
  );
}

2. Render and send:

import { render } from '@react-email/render';
import WelcomeEmail from './emails/WelcomeEmail';

const html = await render(<WelcomeEmail name="John" />);

await fetch('https://email.getorly.com/api/send-email', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.API_KEY}`,
  },
  body: JSON.stringify({
    to: 'john@example.com',
    subject: 'Welcome!',
    body: html,
    html: true,
    priority: 'high',
  }),
});

Success Response (200)

{
    "success": true,
    "message": "Email sent successfully",
    "email_id": "3d1590af-3e5c-43a3-a467-4fda829b4ab7"
}

Validation Error (422)

{
    "success": false,
    "message": "Validation failed",
    "errors": {
        "to": ["The to field must be a valid email address."],
        "subject": ["The subject field is required."],
        "body": ["The body field is required."]
    }
}

Multi-tenant API (/api/v1)

Per-project endpoints with isolated SMTP settings, queued delivery, and email logs. Authenticated with a project-scoped API key.

API Key Scopes

Scope Grants access to
email:send POST /api/v1/emails
email:read GET /api/v1/emails, GET /api/v1/emails/{id}, GET /api/v1/health, GET /api/v1/templates/*
email:admin POST /api/v1/templates, PUT /api/v1/templates/{id}
POST

/api/v1/emails

scope: email:send

Queue an email for delivery using a project sender address and optional template

Parameters

email_id
Required. UUID of the sender address registered for this project
to
Required. Recipient email address
subject
Required. Email subject (max 255 characters)
type
Required. otp, ticket, or generic
data
Required. Object of template variables (keys vary by type — see below)

Data fields by type

Type Required fields Optional fields
otp otp, expiresIn recipientName, message
ticket eventName, eventDate, ticketNumber, totalPrice, currency recipientName, message
generic recipientName, message, htmlContent

OTP email

curl -X POST https://email.getorly.com/api/v1/emails \
  -H "Authorization: Bearer $PROJECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email_id": "550e8400-e29b-41d4-a716-446655440000",
    "to": "user@example.com",
    "subject": "Your verification code",
    "type": "otp",
    "data": {
      "recipientName": "Jane",
      "otp": "482910",
      "expiresIn": "10 minutes"
    }
  }'

Success Response (202 Accepted)

{
    "success": true,
    "message": "Email queued for sending",
    "email_id": "018e1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c",
    "status": "queued",
    "recipient": "user@example.com",
    "project": "my-project"
}
GET

/api/v1/emails/{email_id}

scope: email:read

Get the delivery status of a queued email

curl https://email.getorly.com/api/v1/emails/018e1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c \
  -H "Authorization: Bearer $PROJECT_API_KEY"
{
    "email_id": "018e1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c",
    "to": "user@example.com",
    "subject": "Your verification code",
    "type": "otp",
    "status": "sent",
    "sent_at": "2025-11-09T10:46:30+00:00",
    "error_message": null,
    "retry_count": 0,
    "created_at": "2025-11-09T10:46:25+00:00"
}

Status values: queuedsent or failed

GET

/api/v1/emails

scope: email:read

List email logs for this project with optional filters

Query Parameters

status optional
Filter by queued, sent, or failed
type optional
Filter by email type: otp, ticket, or generic
recipient optional
Filter by recipient email address
per_page optional
Results per page (default: 50, max: 100)
curl "https://email.getorly.com/api/v1/emails?status=failed&per_page=20" \
  -H "Authorization: Bearer $PROJECT_API_KEY"
GET

/api/v1/health

scope: email:read

Project-scoped health check with email delivery statistics

curl https://email.getorly.com/api/v1/health \
  -H "Authorization: Bearer $PROJECT_API_KEY"
{
    "status": "ok",
    "timestamp": "2025-11-09T10:46:25+00:00",
    "project": "my-project",
    "database": "connected",
    "stats": {
        "queued": 2,
        "sent": 1048,
        "failed": 3,
        "total": 1053
    }
}