Casa Mail API

Send transactional email with one HTTP call.

The same infrastructure powering the Casa Mail WordPress plugin, exposed as a plain REST API. Bearer-token auth, JSON in, message ID out. GBP 0.001 per email, prepaid credits, no monthly commitment. 100 free trial credits when you sign up.

100 free trial credits £0.001 per email Prepaid, no monthly bill
POST /v1/send
curl -X POST https://api.onlinestorenotifications.com/v1/send \
  -H "Authorization: Bearer $CASAMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient":  "customer@example.com",
    "from_email": "noreply@yourbrand.com",
    "from_name":  "Your Brand",
    "subject":    "Your order has shipped",
    "body_html":  "<p>Thanks for your order!</p>",
    "body_text":  "Thanks for your order!"
  }'
Response
{
  "ok":              true,
  "stream":          "txn",
  "id":              1104932,
  "idempotency_key": "abc123..."
}
One endpoint POST JSON to /v1/send. Bearer auth. Idempotent replays. No SDK required.
Pay per email GBP 0.001 per send. Top up in fixed amounts. Credits never expire.
Same warmed pool Your sends ride the same warmed IP pool as the WordPress plugin. Bounce handling, complaint suppression, and content scanning included.

Sign up

Get your API key in under a minute.

Enter your email, project name, and website. We send a 6-digit code to verify the email, then hand you a bearer token and 100 free credits. No card required for the trial.

Quickstart

Three steps from signup to sent.

The API is a single endpoint that accepts a JSON body and returns a durable message ID. Retry safely with an idempotency key. No polling required.

01

Sign up above

Enter your email and website, verify the OTP, and grab your bearer token. 100 credits added immediately.

02

POST to /v1/send

Bearer auth in the header, JSON body with recipient, from_email, subject, and body. HTTP 200 means the message is durably accepted.

03

Top up when you need more

Once your balance approaches zero the API returns 402 with a topup URL. Add credits from the dashboard in one click via Stripe Checkout.

04

(Optional) Verify your own domain

Add your own sending domain via the domain endpoints for stronger deliverability. Publish three DNS records; the API verifies them for you.

Response codes
CodeMeaning
200Durably accepted. The id in the body is your message ID.
401Missing or invalid Authorization header.
402Credit balance exhausted. Body includes topup_url.
422Body validation failed. Body includes error and detail.
429Rate-limited (60/min per API key). Retry after 60s.
451Content blocked by scanner. Contact support if unexpected.

Endpoints

The full API in one table.

All endpoints are HTTPS on api.onlinestorenotifications.com. Auth is Authorization: Bearer <api_key> unless noted. Request and response bodies are JSON.

MethodPathWhat it does
POST /v1/send Send one email. Body: recipient, from_email, from_name, subject, body_html, body_text, optional idempotency_key and headers. Debits one credit on success.
GET /v1/account Read tenant info: plan, credit balance, sends today, sends this month, recent credit ledger. Used by the dashboard.
POST /v1/billing/topup Create a Stripe Checkout session for a topup. Body: amount_gbp (one of 5, 25, 100, 500). Returns checkout_url.
POST /v1/onboard/request Anonymous. Send OTP to an email. Body: email, site_url, site_name, plan: "api".
POST /v1/onboard/verify Anonymous. Verify OTP and provision tenant + API key. Body: email, code, site_url, site_name. Returns the bearer once.
POST /v1/email/domain Add your own sending domain. Returns the DNS records to publish (DKIM, SPF, Return-Path). See the domain verification section.
POST /v1/email/domain/verify Trigger a DNS re-check on your domain. Idempotent, safe to poll every 30s.

Code samples

Working /v1/send in three languages.

Every example uses the shared onlinestorenotifications.com sender by default. Once you verify your own domain via /v1/email/domain, put your address in from_email.

send.sh
curl -X POST https://api.onlinestorenotifications.com/v1/send \
  -H "Authorization: Bearer $CASAMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient":  "customer@example.com",
    "from_email": "noreply@onlinestorenotifications.com",
    "from_name":  "Acme Notifications",
    "subject":    "Your order has shipped",
    "body_html":  "<p>Track it at <a href="https://acme.example/o/1234">acme.example</a>.</p>",
    "body_text":  "Track it at https://acme.example/o/1234"
  }'
send.php
<?php
$body = [
    'recipient'  => 'customer@example.com',
    'from_email' => 'noreply@onlinestorenotifications.com',
    'from_name'  => 'Acme Notifications',
    'subject'    => 'Your order has shipped',
    'body_html'  => '<p>Track it at <a href="https://acme.example/o/1234">acme.example</a>.</p>',
    'body_text'  => 'Track it at https://acme.example/o/1234',
];

$ch = curl_init('https://api.onlinestorenotifications.com/v1/send');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . getenv('CASAMAIL_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode($body),
    CURLOPT_RETURNTRANSFER => true,
]);
$res = json_decode(curl_exec($ch), true);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo "HTTP $code, id={$res['id']}\n";
send.js
const res = await fetch('https://api.onlinestorenotifications.com/v1/send', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.CASAMAIL_API_KEY}`,
    'Content-Type':  'application/json',
  },
  body: JSON.stringify({
    recipient:  'customer@example.com',
    from_email: 'noreply@onlinestorenotifications.com',
    from_name:  'Acme Notifications',
    subject:    'Your order has shipped',
    body_html:  '<p>Track it at <a href="https://acme.example/o/1234">acme.example</a>.</p>',
    body_text:  'Track it at https://acme.example/o/1234',
  }),
});

const data = await res.json();
console.log(`HTTP ${res.status}, id=${data.id}`);
send.py
import os, requests

res = requests.post(
    "https://api.onlinestorenotifications.com/v1/send",
    headers={
        "Authorization": f"Bearer {os.environ['CASAMAIL_API_KEY']}",
        "Content-Type":  "application/json",
    },
    json={
        "recipient":  "customer@example.com",
        "from_email": "noreply@onlinestorenotifications.com",
        "from_name":  "Acme Notifications",
        "subject":    "Your order has shipped",
        "body_html":  "<p>Track it at <a href='https://acme.example/o/1234'>acme.example</a>.</p>",
        "body_text":  "Track it at https://acme.example/o/1234",
    },
    timeout=15,
)
print(f"HTTP {res.status_code}, id={res.json().get('id')}")

Pricing

GBP 0.001 per email. Prepaid credits. Never expire.

The API plan is credit-metered, not subscription-metered. You buy credits in fixed amounts and each send debits one credit. There is no monthly bill, no idle-account fee, and no expiry.

£5 5,000 credits

5,000 emails. Enough for a small monthly newsletter or a quiet transactional flow.

£100 100,000 credits

100,000 emails. Bulk-priced for higher-volume transactional apps.

£500 500,000 credits

500,000 emails. For established SaaS or e-commerce apps.

  • Trial. Every new API tenant gets 100 free credits on signup. No card required.
  • Payments. Stripe Checkout, one-off, no subscription. VAT added at checkout for UK/EU customers.
  • Balance. Credits never expire. Cancel any time by not topping up.
  • 402 responses. When your balance hits zero the API returns HTTP 402 with a topup_url. Requests do not queue.

Developer FAQ

Common questions before you integrate.

Do I need the WordPress plugin?

No. The API is a plain REST endpoint. The plugin uses the same API under the hood; a direct API integration skips the plugin entirely. Use the plugin only if you want the free 10,000/month WordPress tier plus the WP admin UI.

Is there a free tier on the API?

No monthly free tier on the API plan. You get a one-time 100-credit trial when you sign up, then pay per email via topups. If you want the free 10,000/month plan, install the WordPress plugin instead.

How is authentication handled?

Bearer token in the Authorization header. The key is 64 hex characters, shown exactly once at signup, hashed on our side. Rotation requires operator action.

Can I send from my own domain?

Yes. Register your domain with POST /v1/email/domain, publish the three DNS records (DKIM, SPF, Return-Path) we return, and call POST /v1/email/domain/verify. Until verified, any from_email outside our shared sender is silently rewritten to the canonical address.

Is retry safe?

Yes. Every send accepts an optional 64-hex idempotency_key. Re-POSTing the same key returns the original result, never a duplicate send. If you omit it, we derive one from the recipient + subject + body hash.

What are the rate limits?

60 requests per minute per API key by default, tunable on request for higher-volume tenants. Bursts above 60/min return HTTP 429 with Retry-After: 60.

How does content scanning work?

High-volume transactional lanes are sampled with an LLM scanner. Critical verdicts return HTTP 451 and kill the send. False positives are rare and reviewable via support@onlinestorenotifications.com. Regular transactional traffic (order confirmations, password resets, account emails) is never blocked.

How do I check my balance?

Two options: GET /v1/account for a JSON snapshot, or open /dashboard and paste your API key. The dashboard also surfaces recent topups, sends today, and topup buttons.

What happens when I run out of credits?

New /v1/send calls return HTTP 402 with a topup_url. Existing queued messages are unaffected. Add credits via the dashboard; new calls resume immediately after the Stripe webhook lands (usually under 5 seconds).

Where do I go for support?

Email support@onlinestorenotifications.com. Include your tenant slug (visible in the dashboard) and a request or response ID if you have one.