Receipt to Google Sheets with Make.com
Map Cryvis receipt fields into a production Google Sheets ledger — column layout, receipt_number+date dedupe, and Make Data Store idempotency.
Appending rows is easy. Keeping a Sheets expense ledger trustworthy under retries, duplicate uploads, and incomplete executions is not. This guide assumes you already call Cryvis from Make and focuses on the Sheets side: columns, duplicate detection by receipt_number + transaction_date, and Data Store idempotency keys.
Companion call patterns: convert receipts to JSON. Triggers: Drive, images/webhook, Gmail. Hub: Make.com.
Workflow
[Source module] --> [HTTP Cryvis Receipt]
|
v
[Build idempotency key]
receipt_number|date|hash
|
v
[Data Store: Get record]
|
+-------------+-------------+
| key exists | key missing
v v
[Stop / Skip] [Sheets: Search Rows]
receipt_number + date
|
+-------------+-------------+
| found | not found
v v
[Skip or Update] [Sheets: Add a Row]
|
v
[Data Store: Add record]Modules
| Module | Role |
|---|---|
| HTTP — Make a Request | POST https://api.cryvis.com/v1/documents/receipt |
| Tools — Set Variables | Build key, normalize date |
| Data Store — Get / Add / Update | Idempotency |
| Google Sheets — Search Rows | Duplicate check in the sheet itself |
| Google Sheets — Add a Row / Update a Row | Ledger write |
| Filter / Router | Branch on hit vs miss |
| Error Handler | Distinguish “duplicate skip” from hard fail |
Use one Data Store per environment (receipt-idem-prod, receipt-idem-dev) so staging replays do not poison production keys.
Cryvis configuration (reminder)
| Item | Value |
|---|---|
| Endpoint | https://api.cryvis.com/v1/documents/receipt |
| Auth | Authorization: Bearer <API_KEY> |
| Body | Multipart field file |
| MIME | pdf, jpeg, png, webp |
| Credits | 1 per page/image |
Single file → map data.*. Multiple files → Iterator on results[] then run the idempotency block per item (file_name + data). See convert receipts to JSON.
Docs: extractReceipt. Product: Receipt API.
Deep Sheets column layout
Design the sheet before mapping. Recommended tabs: Ledger, Duplicates, Failures.
Ledger columns
| Column | Type / format | Cryvis / Make source | Notes |
|---|---|---|---|
A Entry ID | Text | Make UUID or row key | Stable ID for Updates |
B Idempotency Key | Text | See below | Hidden column OK |
C Receipt Number | Text | data.receipt_number | May be blank |
D Transaction Date | Date yyyy-mm-dd | data.transaction_date | Normalize TZ |
E Transaction Time | Text | data.transaction_time | Optional |
F Merchant | Text | data.merchant.name | Raw, not cleaned |
G Merchant Tax ID | Text | data.merchant.tax_id | |
H City | Text | data.location.city | |
I Country | Text | data.location.country | |
J Currency | Text | data.currency | ISO |
K Subtotal | Number 0.00 | data.subtotal | |
L Tax Total | Number 0.00 | data.tax_total | |
M Total Amount | Number 0.00 | data.total_amount | Primary amount |
N Amount Paid | Number 0.00 | data.amount_paid | |
O Payment Method | Text | data.payment.method | |
P Payment Last4 | Text | data.payment.last4 | ACL carefully |
Q Receipt Type | Text | data.receipt_type | |
R Notes | Text | data.notes | |
S Line Item Count | Number | length(data.line_items) | |
T Source System | Text | drive / gmail / form | |
U Source Ref | Text | File ID / Message ID | |
V Source URL | URL | Drive/Gmail link | |
W Processed At | Datetime | {{now}} | |
X Status | Text | extracted | Later: booked |
Y Raw JSON | Text (optional) | stringified data | Debug only; size limits |
Freeze header row. Use Data → Data validation on Status and Currency.
Line items sheet (optional)
Tab LineItems with Entry ID, Description, Quantity, Unit Price, Amount. Populate via Iterator after a successful Ledger insert. Do not Iterator before idempotency clears — you will duplicate children on retry.
Duplicate key: receipt_number + date
Business duplicate definition:
duplicate_key = lower(trim(receipt_number)) + "|" + transaction_dateExamples:
rct-88421|2026-09-10
|2026-09-10 // empty receipt_number — weak keyWhen receipt_number is empty, fall back to:
fallback_key = lower(merchant.name) + "|" + transaction_date + "|" + total_amount + "|" + currencyDocument that fallback collisions are possible (two coffees, same merchant, same day, same total). For those, include a file hash:
fallback_key += "|" + sha1(file_bytes_or_drive_id)Make does not always expose SHA easily — Drive file ID is a pragmatic stand-in for “same upload”.
Sheets Search Rows
Before Add a Row:
- Search
LedgerwhereReceipt Numberequalsdata.receipt_numberANDTransaction Dateequalsdata.transaction_date. - If
receipt_numberempty, search on Merchant + Date + Total instead. - If a row exists → Router to Skip (or Update Source URL) and write a breadcrumb on
Duplicates. - If none → Add a Row.
Search is case-sensitive depending on locale; normalize receipt numbers to upper/lower consistently at Set Variable time.
Data Store idempotency
Sheets search alone is not enough under concurrent scenario runs. Two executions can both Search-miss and both Add.
Data Store pattern:
key = "receipt:" + duplicate_key
value = { entry_id, processed_at, source_ref }
ttl = 0 // keep forever, or 180 daysFlow:
- Get record
key. - If found → stop (already processed). Optionally verify Sheets still has the row.
- If not found → Sheets Search (second line of defense) → Add Row → Add record
key.
On incomplete execution retry after Add Row but before Data Store Add, Search will catch the sheet row. On retry before Add Row, Data Store miss + Search miss correctly inserts once.
Store the Cryvis meta request id in the Data Store value when available for support tickets.
Replay and reparsing
If you must re-OCR a file after improving image quality:
- Delete the Data Store key, or
- Use key versioning:
receipt:v2:...
Do not silently Update totals in Ledger without an audit column (Previous Total, Reprocessed At).
Response mapping snippet
Idempotency Key <- receipt:{{lower(data.receipt_number)}}|{{data.transaction_date}}
Receipt Number <- data.receipt_number
Transaction Date <- data.transaction_date
Merchant <- data.merchant.name
Currency <- data.currency
Subtotal <- data.subtotal
Tax Total <- data.tax_total
Total Amount <- data.total_amount
Amount Paid <- data.amount_paid
Payment Method <- data.payment.method
Receipt Type <- data.receipt_type
Notes <- data.notesFilter: proceed to Sheets only if success is true and data.total_amount is not empty (or allow empty with Status = needs_review).
Errors
| Case | Action |
|---|---|
| Data Store outage | Fail closed (do not Add) or fail open with Sheets-only Search — pick deliberately |
| Sheets API 429 | Incomplete execution |
| Duplicate hit | Log to Duplicates; exit success (not an error) |
| Cryvis failure | Failures tab; no Data Store write |
| Empty merchant + empty total | Failures; do not idempotency-lock forever without review |
Treating duplicates as scenario errors creates noisy alerts. Use a Filter that ends the route successfully after logging.
Test plan
- Process one receipt → one Ledger row + one Data Store key.
- Re-run same file → zero new Ledger rows; Duplicates breadcrumb optional.
- Incomplete execution: cancel after Sheets Add, resume → still one row.
- Two different files, same merchant/date/total, empty receipt numbers → confirm fallback+Drive ID keeps them distinct.
- Clear Data Store key only → Search still blocks duplicate.
- Clear Data Store + delete Sheets row → clean reinsert.
Production checklist
- Sheet shared with a dedicated Google service account used by Make; least privilege.
- Hide
Raw JSONandPayment Last4from general viewers. - Nightly Sheets backup or Drive versioning on.
- Monitor Cryvis credits separately from “rows written” — retries after Cryvis success but before Data Store should not recall the API if you cache
datain Data Store too. - Align with approval flows so Approved-only writers still use the same keys (employee expense workflow).
- Invoice ledgers need different columns and endpoints — see extract invoice data with Make.com.
Related guides
- Extract receipt data with Make.com
- Extract receipt data from images
- Automate expense tracking
- Convert receipts to JSON
- Make.com hub
CTA
Production Sheets ledgers need stable keys, not just OCR. Extract with the Cryvis Receipt API, then enforce receipt_number + date idempotency in Make. Field reference: extractReceipt.