PayPal emails a receipt for every payment sent and received, but the transaction ID, fee breakdown, and net amount are scattered across inconsistent HTML layouts depending on whether the payment was personal, commercial, or a refund. MailFrame extracts all of it into a single typed JSON object, consistently.
It works on “You sent a payment”, “Receipt for your payment to”, and refund confirmation emails from PayPal.
Fields MailFrame extracts
| Field | Type | Example | Notes |
|---|---|---|---|
transaction_id | string | 8XJ12345AB678901C | PayPal transaction ID |
amount_cents | integer | 5000 | Gross payment amount in minor units |
currency | string | usd | ISO 4217, lower-cased |
fee_cents | integer | 175 | PayPal processing fee in minor units |
net_cents | integer | 4825 | Amount after fees (amount_cents - fee_cents) |
payer_email | string | sam@example.com | Email of the sender |
recipient_email | string | shop@acmeco.com | Email of the recipient |
payment_status | enum | completed | One of completed, pending, refunded |
date | string | 2026-05-21 | Transaction date normalized to ISO 8601 |
Sample input
A typical PayPal receipt email looks like this:
From: service@paypal.com
Subject: Receipt for your payment to Acme Co.
Date: Wed, 21 May 2026 11:45:00 -0700
To: sam@example.com
Hello Sam,
You sent a payment of $50.00 USD to Acme Co. (shop@acmeco.com).
Transaction ID: 8XJ12345AB678901C
Date: May 21, 2026, 11:45 AM PDT
Payment details:
Amount sent: $50.00
PayPal fee: $1.75
Net amount: $48.25
Payment method: PayPal balance
Status: Completed
Structured JSON output
{
"transaction_id": "8XJ12345AB678901C",
"amount_cents": 5000,
"currency": "usd",
"fee_cents": 175,
"net_cents": 4825,
"payer_email": "sam@example.com",
"recipient_email": "shop@acmeco.com",
"payment_status": "completed",
"date": "2026-05-21"
}
JSON Schema definition
Every field is validated against the schema before delivery. You can copy this as a starting point and tighten it for your own use case:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "paypal_receipt",
"type": "object",
"required": ["transaction_id", "amount_cents", "currency", "payer_email", "recipient_email", "payment_status"],
"properties": {
"transaction_id": { "type": "string", "pattern": "^[A-Z0-9]{17}$" },
"amount_cents": { "type": "integer", "minimum": 0 },
"currency": { "type": "string", "minLength": 3, "maxLength": 3 },
"fee_cents": { "type": "integer", "minimum": 0 },
"net_cents": { "type": "integer", "minimum": 0 },
"payer_email": { "type": "string", "format": "email" },
"recipient_email": { "type": "string", "format": "email" },
"payment_status": { "type": "string", "enum": ["completed", "pending", "refunded"] },
"date": { "type": "string", "format": "date" }
}
}
Parse via the API
POST the raw email (MIME or plain text) to /v1/parse with the schema you want to
extract against:
The example below sends this page’s Sample input as raw_mime.
curl https://api.mailframe.ai/v1/parse \
-H "Authorization: Bearer $MAILFRAME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema_id": "paypal_receipt",
"raw_mime": "From: service@paypal.com\r\nTo: sam@example.com\r\nSubject: Receipt for your payment to Acme Co.\r\n\r\nHello Sam,"
}'
Prefer zero manual steps? Inbox forwarding — pointing PayPal’s notification forwarding
at a unique inbox address MailFrame assigns you — is on the roadmap. Until it ships,
POST the raw email to /v1/parse as shown above.
Signed webhook delivery (roadmap)
Signed webhook delivery — where MailFrame would POST the extraction result to your
endpoint — is on the roadmap, not yet available. As planned, each delivery would carry an
HMAC-SHA256 signature in the MailFrame-Signature header for verification, with retries
on failure also planned. The envelope below is an illustrative sketch of the planned
format and may change; the confidence block reflects per-field confidence scoring,
which is also on the roadmap and not yet available:
{
"event": "parse.completed",
"parse_id": "parse_d9e2c1",
"schema": "paypal_receipt",
"data": {
"transaction_id": "8XJ12345AB678901C",
"amount_cents": 5000,
"currency": "usd",
"fee_cents": 175,
"net_cents": 4825,
"payer_email": "sam@example.com",
"recipient_email": "shop@acmeco.com",
"payment_status": "completed",
"date": "2026-05-21"
},
"confidence": { "transaction_id": 0.99, "amount_cents": 0.99, "fee_cents": 0.96 },
"received_at": "2026-05-21T18:45:07Z"
}
For synchronous delivery, use POST /v1/parse as shown above — the response returns
typed JSON for every successful extraction.