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

Relay webhooks

Receive delivery, bounce and complaint events for SMTP relay and Email API messages, and verify their signature.

Webhooks send an HTTP POST to your application whenever a relay or API message changes status, so you don't need to poll the API.

Set up

  1. Go to SMTP & API → Webhooks.
  2. Enter a public https:// URL on your server and click Save. Private and local addresses are not accepted.
  3. Click Reveal to copy the signing secret, and Send test event to check that your endpoint responds.

Events

Event When
relay.sent The message was handed to the delivery provider for this recipient
relay.delivered The receiving server accepted the message (when the provider reports deliveries)
relay.bounced The message bounced. Hard bounces are added to your suppression list
relay.complained The recipient marked the message as spam. The address is suppressed
relay.failed Delivery failed permanently. The credit is refunded
relay.suppressed The recipient was skipped because of an earlier bounce or complaint (not charged)

Example body:

{
  "event": "relay.bounced",
  "message_id": "01JABCDEF0123456789XYZ0000",
  "smtp_message_id": "01JABCDEF0123456789XYZ0000@smtp.inboxroads.com",
  "recipient": "jane@example.com",
  "status": "bounced",
  "subject": "Your order #1024",
  "tags": ["order-confirmation"],
  "bounce_type": "hard_bounce",
  "diagnostic": "550 5.1.1 user unknown",
  "timestamp": "2026-10-01T09:30:00+00:00"
}

Verify the signature

Every request has the header X-InboxRoads-Signature: t=<unix time>,v1=<signature>. The signature is HMAC-SHA256 of t + "." + raw request body, using your signing secret. Reject requests where the signature doesn't match or t is more than 5 minutes old.

PHP:

[$t, $v1] = array_map(fn ($p) => explode('=', $p, 2)[1], explode(',', $_SERVER['HTTP_X_INBOXROADS_SIGNATURE']));
$expected = hash_hmac('sha256', $t.'.'.file_get_contents('php://input'), $secret);
$valid = hash_equals($expected, $v1) && abs(time() - (int) $t) < 300;

Node.js:

const [t, v1] = header.split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));

Delivery and retries

Respond with any 2xx status within 10 seconds. If your endpoint returns a 5xx or 429, or can't be reached, we retry up to 5 more times over about 3 hours. Events may occasionally arrive more than once or out of order, so use message_id + recipient + event to de-duplicate.

Still stuck? Our team answers every message.

Contact support

Last updated September 30, 2026