Skip to content
Tier 2 Schema

Parse Rideshare & Delivery Receipt Emails

Turn Uber, Lyft, DoorDash, and Grubhub receipts into typed JSON — service, trip/delivery ID, fare, subtotal, tax, tip, currency, pickup/dropoff or merchant, driver/courier, timestamp. Schema-first.

Every ride you take and every meal you order sends a receipt: an Uber or Lyft trip summary the moment you step out of the car, a DoorDash or Grubhub order confirmation when the courier drops the bag at your door, an Uber Eats or Instacart receipt with the itemized subtotal, tax, and tip. The emails come from receipts@uber.com, no-reply@lyftmail.com, no-reply@doordash.com, receipts@grubhub.com, and dozens of regional and white-labeled variants, and each one writes the receipt in its own template — but the fields you actually want are the same handful: which service, the trip or order ID, the fare or subtotal, the tax and tip, the total and its currency, where the trip started and ended (or which merchant filled the order), who drove or delivered, and when it happened.

MailFrame extracts those fields from any rideshare or delivery receipt into typed, schema-validated JSON you can route straight into an expense report (Expensify, Ramp, Brex, a custom T&E pipeline), a personal-spending tracker, or a mileage- and meal-reimbursement workflow. Match on the message body and the service-specific wording (“Thanks for riding”, “Your order from”, “Total”, “You rode with”, “Your Dasher”) rather than the From address alone — these platforms relay receipts through notification-platform and tenant-specific domains that drift over time. The service, transaction ID, fare, subtotal, tax, tip, total, currency, pickup/dropoff or merchant, driver/courier, and timestamp all normalize into one consistent shape regardless of which app sent the receipt. PDF, image, and calendar-attachment input are on the roadmap; inbox forwarding is planned.

Fields MailFrame extracts

FieldTypeExampleNotes
serviceenumuberOne of uber, lyft, doordash, grubhub, uber_eats, instacart, unknown
service_categoryenumrideshareOne of rideshare, delivery, unknownrideshare for point-to-point trips, delivery for food/grocery/parcel orders
transaction_idstring7f3c9a12-4b8e-4c21-9d6a-1e2f3a4b5c6dThe trip ID (rideshare) or order/delivery ID (delivery) — the dedup key for a single ride or order
statusenumcompletedOne of completed, canceled, adjusted, refunded, in_progress, unknown
farenumber18.2Base trip fare before booking fees, tolls, and tip (rideshare); omitted for delivery receipts that only itemize a subtotal
subtotalnumber20.84Sum of line items before tip — trip charges for rideshare, item subtotal for delivery
taxnumber1.87Sales tax on the order, when the receipt breaks it out; 0 when bundled into fees
tipnumber3Tip to the driver or courier, when the receipt shows it separately
feesnumber2.64Booking, service, delivery, and small-order fees combined
totalnumber23.84Grand total charged to the payment method
currencystringUSDISO 4217 currency code on the receipt; USD, EUR, GBP, CAD, AUD, etc.
pickup_locationstring1200 Market St, San Francisco, CATrip origin (rideshare); blank for delivery
dropoff_locationstring500 Terry Francois Blvd, San Francisco, CATrip destination (rideshare) or delivery address
merchant_namestringTartine BakeryThe restaurant or store that filled the order (delivery); blank for rideshare
driver_namestringMarcusFirst name of the driver (rideshare) or courier/Dasher (delivery), as printed
vehiclestringUberX · Toyota PriusService tier and vehicle description (rideshare), when present
distancestring3.4 miTrip distance as printed on the receipt (rideshare), when present
durationstring18 minTrip or delivery duration, when present
item_countnumber3Number of line items on a delivery order, when present
payment_methodstringVisa ••••4242Masked payment method the charge landed on
receipt_urlstringhttps://riders.uber.com/trips/7f3c9a12Link to the full receipt or trip-detail page
transaction_datestring2026-07-03T08:21:00-04:00Date/time the trip started or the order was placed, ISO 8601
datestring2026-07-03Date the email was sent, normalized to ISO 8601

Sample input

A typical Uber ride receipt is a multipart message with a plain-text and an HTML alternative:

From: Uber Receipts <receipts@uber.com>
Subject: Your Thursday morning trip with Uber
Date: Thu, 03 Jul 2026 08:47:12 -0400
To: jordan.rivera@example.com
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="b1_a3f9c2e1"

--b1_a3f9c2e1
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit

Thanks for riding, Jordan

Total  $23.84
July 3, 2026 | 8:21 AM

Trip ID: 7f3c9a12-4b8e-4c21-9d6a-1e2f3a4b5c6d

Pickup    8:21 AM   1200 Market St, San Francisco, CA
Dropoff   8:39 AM   500 Terry Francois Blvd, San Francisco, CA
18 min | 3.4 mi

Trip fare        $18.20
Booking fee       $2.10
Wait time         $0.54
Subtotal         $20.84
Tip               $3.00
Total            $23.84

You rode with Marcus
UberX · Toyota Prius · 7KRK••

Visa ••••4242

View receipt: https://riders.uber.com/trips/7f3c9a12

--b1_a3f9c2e1
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<html><body><h1>Thanks for riding, Jordan</h1>
<p>Total <strong>$23.84</strong> =E2=80=94 July 3, 2026</p>
</body></html>

--b1_a3f9c2e1--

The same shape is produced for a DoorDash or Grubhub delivery receipt — service_category switches to delivery, merchant_name carries the restaurant, dropoff_location carries the delivery address, driver_name carries the courier, and item_count counts the line items — and the rest of the fields normalize to the same JSON keys regardless of which app sent the receipt.

Structured JSON output

{
  "service": "uber",
  "service_category": "rideshare",
  "transaction_id": "7f3c9a12-4b8e-4c21-9d6a-1e2f3a4b5c6d",
  "status": "completed",
  "fare": 18.2,
  "subtotal": 20.84,
  "tax": 0,
  "tip": 3,
  "fees": 2.64,
  "total": 23.84,
  "currency": "USD",
  "pickup_location": "1200 Market St, San Francisco, CA",
  "dropoff_location": "500 Terry Francois Blvd, San Francisco, CA",
  "driver_name": "Marcus",
  "vehicle": "UberX · Toyota Prius",
  "distance": "3.4 mi",
  "duration": "18 min",
  "payment_method": "Visa ••••4242",
  "receipt_url": "https://riders.uber.com/trips/7f3c9a12",
  "transaction_date": "2026-07-03T08:21:00-04:00",
  "date": "2026-07-03"
}

JSON Schema definition

Every field is validated against the schema before MailFrame returns it. You can copy this as a starting point and tighten it for your own use case — for example, require merchant_name when you only route delivery receipts, or restrict service_category to {"rideshare"} if you only reconcile trip fares for a mileage-reimbursement workflow:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "rideshare_delivery_receipt",
  "type": "object",
  "required": [
    "service",
    "service_category",
    "total",
    "currency"
  ],
  "properties": {
    "service": {
      "type": "string",
      "enum": ["uber", "lyft", "doordash", "grubhub", "uber_eats", "instacart", "unknown"]
    },
    "service_category": {
      "type": "string",
      "enum": ["rideshare", "delivery", "unknown"]
    },
    "transaction_id":  { "type": "string" },
    "status": {
      "type": "string",
      "enum": ["completed", "canceled", "adjusted", "refunded", "in_progress", "unknown"]
    },
    "fare":            { "type": "number", "minimum": 0 },
    "subtotal":        { "type": "number", "minimum": 0 },
    "tax":             { "type": "number", "minimum": 0 },
    "tip":             { "type": "number", "minimum": 0 },
    "fees":            { "type": "number", "minimum": 0 },
    "total":           { "type": "number", "minimum": 0 },
    "currency":        { "type": "string", "minLength": 3, "maxLength": 3 },
    "pickup_location": { "type": "string" },
    "dropoff_location":{ "type": "string" },
    "merchant_name":   { "type": "string" },
    "driver_name":     { "type": "string" },
    "vehicle":         { "type": "string" },
    "distance":        { "type": "string" },
    "duration":        { "type": "string" },
    "item_count":      { "type": "integer", "minimum": 0 },
    "payment_method":  { "type": "string" },
    "receipt_url":     { "type": "string", "format": "uri" },
    "transaction_date":{ "type": "string", "format": "date-time" },
    "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:

curl https://api.mailframe.ai/v1/parse \
  -H "Authorization: Bearer ${MAILFRAME_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "schema_id": "rideshare_delivery_receipt",
    "raw_mime": "From: Uber Receipts <receipts@uber.com>\r\nTo: jordan.rivera@example.com\r\nSubject: Your Thursday morning trip with Uber\r\nDate: Thu, 03 Jul 2026 08:47:12 -0400\r\n\r\nThanks for riding, Jordan\r\n\r\nTotal  $23.84\r\nJuly 3, 2026 | 8:21 AM\r\n\r\nTrip ID: 7f3c9a12-4b8e-4c21-9d6a-1e2f3a4b5c6d\r\n\r\nPickup    8:21 AM   1200 Market St, San Francisco, CA\r\nDropoff   8:39 AM   500 Terry Francois Blvd, San Francisco, CA\r\n18 min | 3.4 mi\r\n\r\nTrip fare        $18.20\r\nBooking fee       $2.10\r\nWait time         $0.54\r\nSubtotal         $20.84\r\nTip               $3.00\r\nTotal            $23.84\r\n\r\nYou rode with Marcus\r\nUberX · Toyota Prius\r\n\r\nVisa ••••4242\r\n\r\nView receipt: https://riders.uber.com/trips/7f3c9a12"
  }'

The call is synchronous: /v1/parse validates the extraction against your schema and returns the typed JSON in the HTTP response, so you can act on it inline — attach the receipt to an open expense report, add the fare to a mileage log, or drop the order onto a spending dashboard. The response wraps the extracted data alongside the parse status and any schema validation errors:

{
  "id": "parse_9c41e7",
  "status": "completed",
  "validation_errors": [],
  "data": {
    "service": "uber",
    "service_category": "rideshare",
    "transaction_id": "7f3c9a12-4b8e-4c21-9d6a-1e2f3a4b5c6d",
    "status": "completed",
    "fare": 18.2,
    "subtotal": 20.84,
    "tax": 0,
    "tip": 3,
    "fees": 2.64,
    "total": 23.84,
    "currency": "USD",
    "pickup_location": "1200 Market St, San Francisco, CA",
    "dropoff_location": "500 Terry Francois Blvd, San Francisco, CA",
    "driver_name": "Marcus",
    "vehicle": "UberX · Toyota Prius",
    "distance": "3.4 mi",
    "duration": "18 min",
    "payment_method": "Visa ••••4242",
    "receipt_url": "https://riders.uber.com/trips/7f3c9a12",
    "transaction_date": "2026-07-03T08:21:00-04:00",
    "date": "2026-07-03"
  }
}

Routing on the result

The most useful split is by service_category: rideshare receipts feed a mileage- and travel-reimbursement lane (the pickup_location, dropoff_location, distance, and duration are what a T&E policy checks), while delivery receipts feed a meals-and-entertainment lane (the merchant_name, item_count, and subtotal are what an expense category needs). Inside those, status decides handling: a completed receipt is a routine expense, while a canceled, adjusted, or refunded receipt should reconcile against the original charge rather than create a new one. Use transaction_id as the deduplication key — a single ride or order can produce both an initial receipt and a later adjusted correction (a fare change, a tip added after the trip, a partial refund), and pairing on transaction_id keeps one row per real trip or order while letting you fold the correction into it. When transaction_id is absent, fall back to (service, total, transaction_date).

Signed webhook delivery

Prefer asynchronous delivery? Signed webhook delivery — where MailFrame POSTs the extraction result to your endpoint with an HMAC-SHA256 signature in the MailFrame-Signature header and exponential-backoff retries — is available during early access alongside the synchronous API. The webhook body wraps the same data payload in a delivery envelope; verify the signature over the raw request body before you trust it:

{
  "id": "parse_9c41e7",
  "status": "completed",
  "validation_errors": [],
  "data": {
    "service": "uber",
    "service_category": "rideshare",
    "transaction_id": "7f3c9a12-4b8e-4c21-9d6a-1e2f3a4b5c6d",
    "status": "completed",
    "total": 23.84,
    "currency": "USD",
    "pickup_location": "1200 Market St, San Francisco, CA",
    "dropoff_location": "500 Terry Francois Blvd, San Francisco, CA",
    "driver_name": "Marcus",
    "transaction_date": "2026-07-03T08:21:00-04:00",
    "date": "2026-07-03"
  }
}

The signature header looks like MailFrame-Signature: t=1751541440,v1=3f9a…; recompute HMAC-SHA256(secret, "{t}." + raw_body) and compare in constant time. Inbox forwarding — pointing a Gmail or Outlook filter at a unique inbox address MailFrame assigns you — is on the roadmap.

Working with related email types? See the Parse Shipping & Delivery Notifications schema, the Parse Travel Booking Confirmations schema, and the email-to-JSON API guide for a full walkthrough of POST /v1/parse. For a step-by-step tutorial that wires this schema into a real /v1/parse request, see Parse Rideshare & Delivery Receipt Emails to JSON.

Other schemas

Ship this schema in production

Define your fields once, then POST raw email to /v1/parse. MailFrame returns typed JSON in the HTTP response or via signed webhook delivery with retries, attempt history, dead-letter, and replay. (Inbox forwarding is on the roadmap.)

Request early access