API reference
A RESTful JSON API over HTTPS. The base URL is https://api.mailstack.voostack.com. Authenticate every request with a Bearer API key;
the key resolves to your organization and all resources are scoped to it.
Authentication
Authorization: Bearer ms_live_xxxxxxxxxxxxxxxxxxxx Keys carry scopes (for example emails:send). A request to an endpoint your key isn't
scoped for returns 403 Forbidden. Missing or invalid keys return 401 Unauthorized.
Errors & status codes
202 Accepted— a send was queued.200 OK— a read/list/verify succeeded.400 Bad Request— validation failed (e.g. unverified from-domain).402 Payment Required— free tier exhausted with no payment method, or spend cap reached.403 Forbidden— missing scope or no active organization.404 Not Found— resource doesn't exist in your org.409 Conflict— duplicate (e.g. domain or key name already exists).
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /v1/emails | Queue a single email. |
| POST | /v1/emails/batch | Queue up to 100 emails. |
| GET | /v1/emails/{id} | Get a message and its status. |
| GET | /v1/domains | List sending domains. |
| GET | /v1/domains/{id} | Get one domain with DNS records. |
| POST | /v1/domains | Register a sending domain. |
| POST | /v1/domains/{id}/verify | Re-check DNS and verify. |
| DELETE | /v1/domains/{id} | Delete a domain. |
| GET | /v1/api-keys | List API keys (metadata only). |
| POST | /v1/api-keys | Create a key (full secret shown once). |
| DELETE | /v1/api-keys/{id} | Revoke a key. |
| GET | /v1/billing/usage | Current-period usage & billing. |
| POST | /v1/webhooks | Manage event webhooks (planned). |
POST /v1/emails
Queue a single email. Requires the emails:send scope. Returns 202.
Request body
{
"from": "hello@yourdomain.com", // required, verified domain
"fromName": "Acme", // optional
"to": "user@example.com", // required
"cc": null, "bcc": null, "replyTo": null,
"subject": "Welcome", // required
"html": "<p>Hi</p>", // html and/or text required
"text": "Hi",
"templateId": null, // optional template id
"variables": { "name": "Sam" }, // optional substitutions
"tags": "welcome" // optional, comma-separated
} Response 202
{ "id": "8f3a1c2e-…", "status": "queued" } POST /v1/emails/batch
Queue up to 100 emails. Body is { "emails": [ EmailObject, … ] }. Each item is
validated independently. Returns 202.
{
"accepted": 1,
"rejected": 1,
"results": [
{ "index": 0, "id": "…", "status": "queued" },
{ "index": 1, "status": "rejected", "error": "Recipient is suppressed." }
]
} GET /v1/emails/{id}
Fetch a message and its current status, scoped to your org.
{
"id": "8f3a1c2e-…",
"fromEmail": "hi@you.com", "fromName": "Acme",
"toEmail": "user@example.com",
"cc": null, "bcc": null, "replyTo": null,
"subject": "Welcome",
"status": "Sent",
"providerMessageId": "0102018f…",
"errorMessage": null,
"tags": "welcome",
"queuedAt": "2026-06-18T10:00:00Z",
"sentAt": "2026-06-18T10:00:02Z",
"createdAt": "2026-06-18T10:00:00Z"
} GET /v1/domains
List all sending domains for your organization, each with its DNS records and status.
GET /v1/domains/{id}
Fetch a single domain.
POST /v1/domains
Register a sending domain. Body:
{ "domain": "yourdomain.com", "mailFromSubdomain": "mail" } Response — a Pending domain with the DNS records to publish:
{
"id": "3b1f…",
"domain": "yourdomain.com",
"status": "Pending",
"customMailFromDomain": "mail.yourdomain.com",
"dnsRecords": [
{ "type": "CNAME", "name": "…_domainkey.yourdomain.com",
"value": "….dkim.amazonses.com", "ttl": 1800, "purpose": "DKIM" }
],
"createdAt": "2026-06-18T10:00:00Z"
} POST /v1/domains/{id}/verify
Re-check DNS for the domain. Flips status to Verified once all records resolve.
DELETE /v1/domains/{id}
Remove a sending domain from your organization.
GET /v1/api-keys
List your keys. The secret is never returned — only a masked hint:
[
{
"id": "…", "name": "Production",
"keyPrefix": "abc12xyz",
"maskedKey": "ms_live_abc12xyz_••••",
"scopes": ["emails:send"],
"lastUsedAt": "2026-06-18T09:55:00Z",
"expiresAt": null, "revokedAt": null,
"isActive": true,
"createdAt": "2026-04-02T12:00:00Z"
}
] POST /v1/api-keys
Create a key. Body:
{ "name": "Production", "scopes": ["emails:send"], "expiresAt": null } Response — the metadata plus the full key, shown once:
{
"key": { "id": "…", "name": "Production", "keyPrefix": "abc12xyz", … },
"fullKey": "ms_live_abc12xyz_ZmFrZXNlY3JldA"
} DELETE /v1/api-keys/{id}
Revoke a key immediately. Revoked keys can't be reactivated.
GET /v1/billing/usage
Read the current period's usage and billing state for your org:
{
"periodKey": "2026-06",
"periodStart": "2026-06-01T00:00:00Z",
"periodEnd": "2026-07-01T00:00:00Z",
"emailsSent": 4200,
"freeMonthlyAllowance": 3000,
"freeRemaining": 0,
"billableEmails": 1200,
"pricePer1kCents": 40,
"hasPaymentMethod": true,
"monthlySpendCapCents": 5000
} POST /v1/webhooks (planned)
Manage event webhook subscriptions. See the dedicated webhooks guide for event types, payloads, and signature verification.