Webhook Payload
Inbound emails POST to your endpoint as application/json with this schema. A Primitive-Signature header carries the HMAC-SHA256 signature; see Signature verification. The high-level primitive.receive(...) SDK helper exposes a normalized ReceivedEmail shape if you don't want the raw event envelope.
| Field | Type | Description |
|---|---|---|
| idreq | string | Unique delivery event ID. |
| eventreq | "email.received" | Event type identifier. Always `"email.received"` for this event type. |
| versionreq | WebhookVersion | API version in date format (YYYY-MM-DD). Use this to detect version mismatches between webhook and SDK. |
| deliveryreq | object | Metadata about this webhook delivery. |
| endpoint_idreq | string | ID of the webhook endpoint receiving this event. Matches the endpoint ID from your Primitive dashboard. |
| attemptreq | integer | Delivery attempt number, starting at 1. Increments with each retry if previous attempts failed. |
| attempted_atreq | string | ISO 8601 timestamp (UTC) when this delivery was attempted. |
| emailreq | object | The email that triggered this event. |
| idreq | string | Unique email ID in Primitive. Use this ID when calling Primitive APIs to reference this email. |
| received_atreq | string | ISO 8601 timestamp (UTC) when Primitive received the email. |
| smtpreq | object | SMTP envelope information. This is the "real" sender/recipient info from the SMTP transaction, which may differ from the headers (e.g., BCC recipients). |
| helo | string | null | HELO/EHLO hostname from the sending server. Null if not provided during SMTP transaction. |
| mail_fromreq | string | SMTP envelope sender (MAIL FROM command). This is the bounce address, which may differ from the From header. |
| rcpt_toreq | string[] | SMTP envelope recipients (RCPT TO commands). All addresses that received this email in a single delivery. |
| headersreq | object | Parsed email headers. These are extracted from the email content, not the SMTP envelope. |
| message_id | string | null | Message-ID header value. Null if the email had no Message-ID header. |
| subject | string | null | Subject header value. Null if the email had no Subject header. |
| fromreq | string | From header value. May include display name: `"John Doe" <[email protected]>` |
| toreq | string | To header value. May include multiple addresses or display names. |
| date | string | null | Date header value as it appeared in the email. Null if the email had no Date header. |
| contentreq | object | Raw email content and download information. |
| rawreq | RawContent | Raw email in RFC 5322 format. May be inline (base64) or download-only depending on size. |
| downloadreq | object | Download information for the raw email. Always present, even if raw content is inline. |
| parsedreq | ParsedData | Parsed email content (body text, HTML, attachments). Check `status` to determine if parsing succeeded. |
| ParsedDataComplete | object | Parsed email content when parsing succeeded. |
| ParsedDataFailed | object | Parsed email content when parsing failed. |
| analysisreq | EmailAnalysis | Email analysis and classification results. |
| spamassassin | object | SpamAssassin analysis results. |
| forward | ForwardAnalysis | Forward detection and analysis results. |
| authreq | EmailAuth | Email authentication results (SPF, DKIM, DMARC). |
| spfreq | SpfResult | SPF verification result. |
| dmarcreq | DmarcResult | DMARC verification result. |
| dmarcPolicy | DmarcPolicy | DMARC policy from the sender's DNS record. |
| dmarcFromDomain | string | null | The organizational domain used for DMARC lookups. |
| dmarcSpfAlignedreq | boolean | Whether SPF aligned with the From: domain for DMARC purposes. |
| dmarcDkimAlignedreq | boolean | Whether DKIM aligned with the From: domain for DMARC purposes. |
| dmarcSpfStrict | boolean | null | Whether DMARC SPF alignment mode is strict. |
| dmarcDkimStrict | boolean | null | Whether DMARC DKIM alignment mode is strict. |
| dkimSignaturesreq | DkimSignature[] | All DKIM signatures found in the email with their verification results. |
Notes
Delivery & retries
delivery.attempt is the attempt number (1 to 6). The event id (evt_ + 64 hex chars) stays stable across retries; track it for idempotency and return 2xx for events you've already processed. Full retry schedule on the Receiving mail page.
Raw email content
The raw email is included inline (base64-encoded) if it's smaller than 256KB. For larger emails, raw.included will be false and you'll need to fetch it from download.url.
Attachments
Attachment metadata is always included in the payload. To download the actual files, fetch the attachments_download_url which returns a tar.gz archive. Each file in the archive is named according to its tar_path.
Parsing failures
If email parsing fails, parsed.status will be "failed" and parsed.error will contain details. You can still access the raw email content to parse it yourself.
HTML safety
parsed.body_html contains the raw parsed HTML body. Treat it as untrusted content and sanitize it before rendering in a browser.
Spam analysis
The analysis.spamassassin.score field contains the SpamAssassin spam score. Higher scores indicate higher likelihood of spam. Typical thresholds are 5+ for spam. You decide how to handle it. We never silently drop mail.
Authentication results
auth includes the SPF and DMARC verdicts, alignment booleans, and an array of DKIM signatures (with domain, selector, key bits, and algorithm). Use these for your own anti-spoofing logic on top of Primitive's.
Forward detection
analysis.forward flags messages that contain a forwarded email (inline or as an attachment) and surfaces the original sender along with DKIM verdicts on that inner mail. Useful for detecting forwarded-as-attachment fraud or building “reply to the real sender” workflows.
Threading
parsed.in_reply_to and parsed.references carry the RFC 5322 threading headers when present. The high-level client.reply() helper uses these to chain replies correctly without your having to set them by hand.