{"schema_version":"1.0","publisher":"Primitive SDKs","canonical_url":"https://test.abhinandan.one/python-types-reference","markdown_url":"https://test.abhinandan.one/python-types-reference.md","article":{"id":"1b6838e1-2cd7-4b18-881d-8bf178390983","article_slug":"python-types-reference","parent_article_slug":null,"parent_article_title":null,"kind":"reference","published_at":"2026-08-11T18:55:08.554783+00:00","keywords":["ReceivedEmail python","EmailReceivedEvent primitive","WEBHOOK_EVENT_TYPES","PaymentEvent TypedDict","ReceivedEmailAddress","is_payment_settled_event"],"meta_description":"Lists every generated dataclass, enum, and TypedDict in primitivedotev's Python SDK, covering ReceivedEmail, auth verdicts, and webhook event types.","og_image_url":null,"source_file_paths":["sdk-python/src/primitive/events.py","sdk-python/src/primitive/received_email.py"],"recording_id":null,"replayable":false,"task_name":"Python SDK Type Reference","category":"Python SDK","summary":null,"description":"Browse the generated dataclasses, enums, and TypedDicts the Python SDK uses to represent normalized emails, auth results, forward analysis, and webhook events.","content_kind":"repo_page","content_markdown":"Every type on this page is importable from the top-level `primitive` package unless otherwise noted. Types generated from the webhook JSON Schema (`EmailReceivedEvent`, `EmailAuth`, `EmailAnalysis`, `ForwardAnalysis`, and friends) are covered in depth on [Payment and Interaction Webhook Event Types](python-webhook-event-types); this page is the map of everything else: the normalized `ReceivedEmail` shape and the shared event-type catalog.\n\n## `ReceivedEmail` and its parts\n\n`primitive.receive(...)` and `primitive.normalize_received_email(...)` return a `ReceivedEmail` dataclass. It is the SDK-normalized representation of an inbound email; see [Receiving and Parsing Inbound Email](python-receive-email) for the full receive flow and field-by-field usage. This page documents only the dataclass shapes.\n\n| Field | Type | Description |\n|---|---|---|\n| `id` | `str` | The inbound email's id. |\n| `event_id` | `str` | The id of the webhook delivery (`event.id`) that produced this email. |\n| `received_at` | `str` | ISO-8601 timestamp string from `email.received_at`. |\n| `sender` | `ReceivedEmailAddress` | The From address, parsed strictly, falling back to the SMTP envelope sender if the header doesn't parse. |\n| `reply_target` | `ReceivedEmailAddress` | The address a reply should go to: the first `Reply-To` entry if present and valid, else `sender`. |\n| `received_by` | `str` | The first SMTP `RCPT TO` recipient. |\n| `received_by_all` | `list[str]` | Every SMTP `RCPT TO` recipient. |\n| `subject` | `str \\| None` | The raw `Subject` header. |\n| `reply_subject` | `str` | `subject` normalized with a `Re:` prefix (idempotent, doesn't double-prefix). |\n| `forward_subject` | `str` | `subject` normalized with a `Fwd:` prefix (idempotent). |\n| `text` | `str \\| None` | The parsed plain-text body. |\n| `thread` | `ReceivedEmailThread` | Threading headers extracted from the parsed email. |\n| `attachments` | `list[WebhookAttachment]` | Parsed attachment metadata. |\n| `auth` | `EmailAuth` | The SPF/DKIM/DMARC verdict fields, as delivered on the raw event. |\n| `analysis` | `EmailAnalysis` | Server-computed email analysis (bounce/report classification, etc.). |\n| `raw` | `EmailReceivedEvent` | The full validated `email.received` event this email was normalized from. |\n\n```python\n@dataclass(frozen=True)\nclass ReceivedEmail:\n    id: str\n    event_id: str\n    received_at: str\n    sender: ReceivedEmailAddress\n    reply_target: ReceivedEmailAddress\n    received_by: str\n    received_by_all: list[str]\n    subject: str | None\n    reply_subject: str\n    forward_subject: str\n    text: str | None\n    thread: ReceivedEmailThread\n    attachments: list[WebhookAttachment]\n    auth: EmailAuth\n    analysis: EmailAnalysis\n    raw: EmailReceivedEvent\n```\n\n### `ReceivedEmailAddress`\n\nA single parsed address with an optional display name.\n\n| Field | Type | Description |\n|---|---|---|\n| `address` | `str` | Lowercased email address. |\n| `name` | `str \\| None` | Display name, or `None` if the header carried none. Defaults to `None`. |\n\n```python\n@dataclass(frozen=True)\nclass ReceivedEmailAddress:\n    address: str\n    name: str | None = None\n```\n\n<Note>\n\n`sender` and `reply_target` are display-quality fields, not authorization anchors. To decide whether an email is really from a domain you trust, use [`is_trusted_sender`](python-sender-trust) instead of comparing these fields.\n\n</Note>\n\n### `ReceivedEmailThread`\n\nThreading headers extracted from the parsed email, used to build reply/forward headers.\n\n| Field | Type | Description |\n|---|---|---|\n| `message_id` | `str \\| None` | The `Message-Id` header of the inbound email. |\n| `in_reply_to` | `list[str]` | Parsed `In-Reply-To` header values. |\n| `references` | `list[str]` | Parsed `References` header values. |\n\n```python\n@dataclass(frozen=True)\nclass ReceivedEmailThread:\n    message_id: str | None\n    in_reply_to: list[str]\n    references: list[str]\n```\n\n### Helper functions that operate on these types\n\n| Function | Signature | Description |\n|---|---|---|\n| `receive` | `receive(*, body, headers, secret, tolerance_seconds=None) -> ReceivedEmail` | Verifies the webhook signature, parses and validates the body, and normalizes it into a `ReceivedEmail` in one call. |\n| `normalize_received_email` | `normalize_received_email(event: EmailReceivedEvent) -> ReceivedEmail` | Normalizes an already-validated `EmailReceivedEvent` into a `ReceivedEmail`. Raises `ValueError` if `email.smtp.rcpt_to` is empty. |\n| `build_reply_subject` | `build_reply_subject(subject: str \\| None) -> str` | Prefixes a subject with `Re:`, idempotently. Returns `\"Re:\"` for an empty/`None` subject. |\n| `build_forward_subject` | `build_forward_subject(subject: str \\| None) -> str` | Prefixes a subject with `Fwd:`, idempotently. Returns `\"Fwd:\"` for an empty/`None` subject. |\n| `format_address` | `format_address(address: ReceivedEmailAddress) -> str` | Renders `\"Name <addr>\"` when `name` is set, else the bare address. |\n| `parse_header_address` | `parse_header_address(value: str \\| None) -> ReceivedEmailAddress \\| None` | Parses a single RFC 5322 header address (From/Sender/Reply-To). Lenient about quirky headers but strict about the resulting address; returns `None` rather than a bad guess if nothing parseable is found. |\n\n<Warning>\n\n`parse_header_address` is intentionally lenient for display purposes. It is not a safe authorization anchor, do not gate access decisions on its output. Use [`is_trusted_sender`](python-sender-trust) for that.\n\n</Warning>\n\n## Webhook event-type catalog\n\nThese live in `primitive.events` (also re-exported from the top-level `primitive` package for the guard functions and `WEBHOOK_EVENT_TYPES`). Full event-handling flow is documented on [Handling Webhook Events](python-webhook-events); this section is the type catalog reference. See also [Payment and Interaction Webhook Event Types](python-webhook-event-types) for the complete `PaymentEvent`/`InteractionEvent` reference.\n\nThe event name for every family arrives in the `X-Webhook-Event` HEADER, never in the body, the stored payload is sent verbatim with no envelope. An `email.*` body carries `event`, a `payment.*` body carries the name in `type`, and an `interaction.*` body is just `{\"interaction\": {...}}` with no event/type field at all. That's why every catalog and guard function below keys off the header-derived value, not a body field.\n\n### Event-type tuples\n\n| Name | Type | Contents |\n|---|---|---|\n| `EMAIL_EVENT_TYPES` | `tuple[str, ...]` | `email.received`, `email.bounced`, `email.tls_report`, `email.dmarc_report`, `email.dmarc_failure` |\n| `PAYMENT_EVENT_TYPES` | `tuple[str, ...]` | `payment.settled`, `payment.failed` |\n| `INTERACTION_EVENT_TYPES` | `tuple[str, ...]` | `interaction.ack.acked`, `interaction.ack.canceled`, `interaction.ack.expired`, `interaction.ack.received`, `interaction.ack.requested`, `interaction.x402.challenge`, `interaction.x402.declined`, `interaction.x402.expired`, `interaction.x402.payment`, `interaction.x402.rejected`, `interaction.x402.settled`, `interaction.x402.verify_timeout` |\n| `WEBHOOK_EVENT_TYPES` | `tuple[str, ...]` | The union of all three tuples above, the full current catalog. |\n\n`WebhookEventType` is a plain `str` type alias for any current catalog value, as carried in the `X-Webhook-Event` header.\n\n```python\ndef is_known_webhook_event_type(event_type: str | None) -> bool: ...\n```\n\nReturns `True` if `event_type` is a value present in `WEBHOOK_EVENT_TYPES`.\n\n### `PaymentEvent` and its subtypes\n\n`PaymentEvent` is a `TypedDict` (`total=False`) representing a `payment.*` webhook body. The stored payload is flat, no envelope, no nested `payment` object, and carries the event name in `type`; the parser overlays a canonical `event` field (mirrored from the header) so consumers can branch on one field.\n\n| Key | Type | Description |\n|---|---|---|\n| `event` | `Literal[\"payment.settled\", \"payment.failed\"]` (read-only) | Canonical event name, overlaid from the `X-Webhook-Event` header. |\n| `type` | `Literal[\"payment.settled\", \"payment.failed\"]` (read-only) | The event name as carried in the raw stored body. |\n| `challenge_id` | `str` | The [x402 payment challenge](x402-payments-overview) this payment settles or fails. |\n| `network` | `str` | Settlement network (`\"base\"` or `\"base-sepolia\"`). |\n| `amount` | `str` | Amount in token base units (USDC has 6 decimals, so `\"10000\"` is 0.01). |\n| `asset` | `str` | The checksummed token contract address. |\n| `payer_org` | `str \\| None` | The paying organization id, or `None` when not on-net. |\n\n`PaymentSettledEvent` and `PaymentFailedEvent` are subclasses of `PaymentEvent` that narrow `event`/`type` to their respective literal, using `ReadOnly` (PEP 705) so a type checker rejects treating one as the other after a guard narrows it:\n\n| Type | Adds | Field |\n|---|---|---|\n| `PaymentSettledEvent` | `event`/`type` narrowed to `\"payment.settled\"` | `settle_tx: str`, the on-chain settlement transaction hash |\n| `PaymentFailedEvent` | `event`/`type` narrowed to `\"payment.failed\"` | `failure_reason: str`, human-readable failure reason |\n\n### `InteractionEvent`\n\nAn `interaction.*` webhook body (`TypedDict`, `total=False`). The stored payload is just `{\"interaction\": {...}}` with no event/type field; the parser overlays a canonical `event` from the header.\n\n| Key | Type | Description |\n|---|---|---|\n| `event` | `str` | Canonical event name, overlaid from the header (e.g. `interaction.x402.settled`). |\n| `interaction` | `dict[str, Any]` | The interaction payload body. |\n| `id` | `str` | Interaction id, when present. |\n\n`InteractionX402Event` is a type alias for `InteractionEvent`, the same shape, named for the `interaction.x402.*` family specifically.\n\n### Type guards\n\nAll guards accept `object` and narrow via `TypeGuard`, so they're safe to call on any parsed event value.\n\n| Function | Narrows to | True when |\n|---|---|---|\n| `is_payment_event(event)` | `PaymentEvent` | `event[\"event\"]` is `\"payment.settled\"` or `\"payment.failed\"` |\n| `is_payment_settled_event(event)` | `PaymentSettledEvent` | `event[\"event\"] == \"payment.settled\"` |\n| `is_payment_failed_event(event)` | `PaymentFailedEvent` | `event[\"event\"] == \"payment.failed\"` |\n| `is_interaction_x402_event(event)` | `InteractionEvent` | `event[\"event\"]` starts with `\"interaction.x402.\"` |\n\n```python\nfrom primitive import handle_webhook_event, is_payment_settled_event, is_interaction_x402_event\n\nevent = handle_webhook_event(body=raw_body, headers=headers, secret=secret)\n\nif is_payment_settled_event(event):\n    print(event[\"challenge_id\"], event[\"amount\"], event[\"settle_tx\"])\nelif is_interaction_x402_event(event):\n    print(event[\"event\"], event[\"interaction\"])\n```\n\n## Next steps\n\n<CardGroup cols={2}>\n\n<Card title=\"Payment and Interaction Webhook Event Types\" href=\"python-webhook-event-types\">\n\nFull reference for the payment and interaction event catalog, with per-field detail and guard usage.\n\n</Card>\n\n<Card title=\"Receiving and Parsing Inbound Email\" href=\"python-receive-email\">\n\nSee the full receive flow that produces a ReceivedEmail, with worked examples.\n\n</Card>\n\n<Card title=\"Handling Webhook Events\" href=\"python-webhook-events\">\n\nDispatch every webhook event family with handle_webhook_event.\n\n</Card>\n\n<Card title=\"Python SDK Error Reference\" href=\"python-errors-reference\">\n\nLook up the errors these types and helpers can raise.\n\n</Card>\n\n</CardGroup>","canonical_base_url":"https://test.abhinandan.one","seo_indexing_enabled":true,"last_modified":"2026-08-21T18:22:43.359885+00:00","video_url":null,"voiceover_url":null,"tools_used":[],"demonstrated_by":[],"steps":[],"related_links":[],"intro":null,"prerequisites":[],"verification":[],"troubleshooting":[],"suggest_edit_url":"https://github.com/abhi-browzer/primitive-sdks/edit/main/sdk-python/src/primitive/events.py","raise_issue_url":"https://github.com/abhi-browzer/primitive-sdks/issues/new?title=Docs+feedback%3A+Python+SDK+Type+Reference&body=Page%3A+https%3A%2F%2Ftest.abhinandan.one%2Fpython-types-reference","page_feedback_enabled":true,"verified_ref":null,"verified_at":"2026-08-11T18:38:45.205849+00:00"}}