Skip to content

Platform

Send: campaigns Send: SMTP relay & Email API Verify Deliver AI Automation All features

Developers

API documentation Email API overview Integrations Custom domains

Solutions

Small businesses E-commerce Agencies Startups & SaaS Creators & individuals

Resources

Blog Help center Free email verifier SPF checker DMARC checker Compare platforms Pricing

InboxRoads API documentation

REST over HTTPS with JSON. Base URL https://inboxroads.com/api/v1

Authentication

Create a key in Developers → API keys. Send it as a bearer token. Keys can be limited to scopes: send, verify, contacts, campaigns, domains, webhooks, automations, ai, reports. The full key is shown once; rotate it any time.

curl https://inboxroads.com/api/v1/me \
  -H "Authorization: Bearer YOUR_KEY"

Errors

Errors return JSON with a message; validation errors add an errors object. Every response carries an X-Request-Id header — include it when you contact support.

  • 401 missing or invalid key · 402 not enough credits · 403 scope, plan or feature not allowed · 404 not found (or not yours) · 413 message too large · 422 validation failed · 429 rate limit or daily sending limit reached · 5xx retry with back-off

Rate limits

Requests per minute depend on your plan (see pricing). When you exceed it you receive 429 with a Retry-After header. Sending also respects a per-account daily limit and infrastructure limits; temporarily rejected messages return 429.

Send email

POST /send sends one message (transactional or personalised) through the same pipeline as the SMTP relay. 1 credit per recipient; suppressed recipients are not charged and permanent failures are refunded. The From domain must be verified in your account. Requires the SMTP relay & Email API to be enabled for your account.

curl -X POST https://inboxroads.com/api/v1/send \
  -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
  -d '{
    "from": "Shop <orders@shop.com>",
    "to": ["jane@example.com"],
    "reply_to": "support@shop.com",
    "subject": "Your order {{order}}",
    "html": "<p>Hi {{first_name|there}}, thanks for order {{order}}.</p>",
    "variables": {"first_name": "Jane", "order": "1024"},
    "metadata": {"order_id": "1024"},
    "tags": ["order"],
    "attachments": [{"filename": "invoice.pdf", "content": "<base64>", "content_type": "application/pdf"}]
  }'

Use a saved template instead of html: "template_id": "<template id>" with variables. Placeholders are {{name}} or {{name|fallback}}; values are HTML-escaped, templates are never executed as code. Response 202: the message id, recipients and credits charged. Check status with GET /messages/{id}.

Verify email

Single (synchronous): POST /verify with {"email": "…"}. Bulk: {"emails": ["…", "…"]} (up to 50,000) returns 202 with a job id; poll GET /verify/{id}. 1 verification credit per address; duplicates and bad syntax are free.

{
  "email": "jane@company.com",
  "result": "valid",          // valid | invalid | risky | unknown
  "status": "valid",          // detailed: mailbox_error, disposable, role_based, …
  "sub_status": "deliverable",
  "mx_found": true, "disposable": false, "role_based": false, "free_provider": false
}

Contacts & lists

POST /contacts creates or updates by email: email, first_name, last_name, company, phone, country, custom_fields, lists (list ids). Suppressed addresses are stored as unsubscribed. GET /contacts?email=… looks one up; GET /lists, POST /lists manage lists.

Campaigns

POST /campaigns creates a draft (name, sender_id, subject, html or template_id, lists, segments, exclude_lists). POST /campaigns/{id}/send sends now or schedules with send_at; credits are reserved at send time. GET /reports/campaigns/{id} returns metrics and link clicks.

Domains

POST /domains adds a sending domain and returns the DNS records to publish; POST /domains/{id}/verify checks DNS now; GET /domains/{id} shows status.

Webhooks

Manage endpoints in the app or with /webhooks. Events:

  • delivered — Email delivered to the receiving server
  • bounced — Email bounced (hard, soft or blocked)
  • opened — Recipient opened an email (first open)
  • clicked — Recipient clicked a tracked link
  • complained — Recipient marked an email as spam
  • unsubscribed — Recipient unsubscribed
  • verification.completed — A verification (single or bulk) finished
  • campaign.completed — A campaign finished sending
  • warmup.status_changed — An IP warm-up schedule changed status
  • automation.completed — A contact finished an automation
  • relay.sent — SMTP/API message handed to the sending provider
  • relay.failed — SMTP/API message could not be delivered
  • relay.suppressed — SMTP/API recipient skipped (suppressed)
  • relay.delivered — SMTP/API message delivered
  • relay.bounced — SMTP/API message bounced
  • relay.complained — SMTP/API recipient complained

Each request body is {"id", "type", "created_at", "data"}. Event ids are stable, so you can de-duplicate. Failed deliveries are retried after 1 minute, 5 minutes, 30 minutes, 2, 6 and 12 hours; a 2xx response stops retries. Verify the signature:

// X-InboxRoads-Signature: t=1760000000,v1=5f2b…
[$t, $v1] = [/* parse t= and v1= */];
$expected = hash_hmac('sha256', $t.'.'.$rawBody, $secret);
if (! hash_equals($expected, $v1) || abs(time() - $t) > 300) {
    abort(400);
}
// Node.js
const [t, v1] = header.split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1)) && Math.abs(Date.now() / 1000 - t) < 300;

Automations

Enrol a lead in a webhook-triggered automation: POST /automations/{id}/trigger with email, optional contact fields, custom_fields and an event_id for idempotency. Each automation also has a private URL (/hooks/automations/…) you can paste into forms, CRMs, Zapier or n8n without an API key.

AI

POST /ai/campaign with prompt (plus optional objective, audience, tone, language, offer, cta, length, variations, followups) queues a draft; poll GET /ai/requests/{id} for the structured result. Counts toward your plan's monthly AI generations. Nothing is sent automatically.

Reports & usage

GET /reports/overview?from=2026-09-01&to=2026-09-30 — totals (sent, delivered, hard/soft bounces, opens, clicks, unsubscribes, complaints and rates), mailbox-provider breakdown, per-domain results and a daily series. GET /usage — API calls, emails, verifications and credits. GET /credits — balances (including what is usable for sending vs. verification).

SMTP relay

Host:        smtp.inboxroads.com
Port:        587 (STARTTLS) · 465 (SSL/TLS) · 2525 (STARTTLS)
Username:    your SMTP username (ir-…)
Password:    shown once when you create the credential
From:        an address on a verified domain

n8n

There is no native InboxRoads node yet; n8n works today with HTTP Request and Webhook nodes. In your account, Developers → Integrations has a downloadable workflow:

  1. Store your API key in n8n as the variable INBOXROADS_API_KEY.
  2. Webhook node receives a new lead.
  3. HTTP Request → POST https://inboxroads.com/api/v1/verify with {"email": "{{ $json.body.email }}"}.
  4. IF result equals valid.
  5. HTTP Request → POST https://inboxroads.com/api/v1/send, or POST /automations/{id}/trigger to hand the lead to an InboxRoads automation (wait, follow up if not opened, AI copy, CRM update).
  6. Add an n8n Webhook URL as an InboxRoads webhook endpoint to react to opened, clicked or bounced.

Code examples

PHP (Guzzle)

$client = new GuzzleHttp\Client(['base_uri' => 'https://inboxroads.com/api/v1/', 'headers' => ['Authorization' => 'Bearer '.getenv('INBOXROADS_KEY')]]);
$res = $client->post('verify', ['json' => ['email' => 'jane@example.com']]);
echo json_decode($res->getBody(), true)['result'];

Laravel

// .env: MAIL_MAILER=smtp  MAIL_HOST=smtp.inboxroads.com  MAIL_PORT=587  MAIL_ENCRYPTION=tls
//       MAIL_USERNAME=ir-…  MAIL_PASSWORD=…
Mail::to($user)->send(new OrderShipped($order));

// or the HTTP API
Http::withToken(config('services.inboxroads.key'))
    ->post('https://inboxroads.com/api/v1/send', ['from' => 'you@yourdomain.com', 'to' => [$user->email], 'subject' => 'Welcome', 'html' => $html]);

Node.js (Nodemailer)

const transporter = nodemailer.createTransport({ host: 'smtp.inboxroads.com', port: 587, secure: false,
  auth: { user: process.env.IR_SMTP_USER, pass: process.env.IR_SMTP_PASS } });
await transporter.sendMail({ from: 'you@yourdomain.com', to: 'jane@example.com', subject: 'Hi', html: '<p>Hello</p>' });

Python

import requests
r = requests.post('https://inboxroads.com/api/v1/send', headers={'Authorization': f'Bearer {KEY}'},
    json={'from': 'you@yourdomain.com', 'to': ['jane@example.com'], 'subject': 'Hi', 'text': 'Hello'})
print(r.status_code, r.json()['id'])