← Back to blog

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

ModuleRole
HTTP — Make a RequestPOST https://api.cryvis.com/v1/documents/receipt
Tools — Set VariablesBuild key, normalize date
Data Store — Get / Add / UpdateIdempotency
Google Sheets — Search RowsDuplicate check in the sheet itself
Google Sheets — Add a Row / Update a RowLedger write
Filter / RouterBranch on hit vs miss
Error HandlerDistinguish “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)

ItemValue
Endpointhttps://api.cryvis.com/v1/documents/receipt
AuthAuthorization: Bearer <API_KEY>
BodyMultipart field file
MIMEpdf, jpeg, png, webp
Credits1 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

ColumnType / formatCryvis / Make sourceNotes
A Entry IDTextMake UUID or row keyStable ID for Updates
B Idempotency KeyTextSee belowHidden column OK
C Receipt NumberTextdata.receipt_numberMay be blank
D Transaction DateDate yyyy-mm-dddata.transaction_dateNormalize TZ
E Transaction TimeTextdata.transaction_timeOptional
F MerchantTextdata.merchant.nameRaw, not cleaned
G Merchant Tax IDTextdata.merchant.tax_id
H CityTextdata.location.city
I CountryTextdata.location.country
J CurrencyTextdata.currencyISO
K SubtotalNumber 0.00data.subtotal
L Tax TotalNumber 0.00data.tax_total
M Total AmountNumber 0.00data.total_amountPrimary amount
N Amount PaidNumber 0.00data.amount_paid
O Payment MethodTextdata.payment.method
P Payment Last4Textdata.payment.last4ACL carefully
Q Receipt TypeTextdata.receipt_type
R NotesTextdata.notes
S Line Item CountNumberlength(data.line_items)
T Source SystemTextdrive / gmail / form
U Source RefTextFile ID / Message ID
V Source URLURLDrive/Gmail link
W Processed AtDatetime{{now}}
X StatusTextextractedLater: booked
Y Raw JSONText (optional)stringified dataDebug 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_date

Examples:

rct-88421|2026-09-10
|2026-09-10          // empty receipt_number — weak key

When receipt_number is empty, fall back to:

fallback_key = lower(merchant.name) + "|" + transaction_date + "|" + total_amount + "|" + currency

Document 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:

  1. Search Ledger where Receipt Number equals data.receipt_number AND Transaction Date equals data.transaction_date.
  2. If receipt_number empty, search on Merchant + Date + Total instead.
  3. If a row exists → Router to Skip (or Update Source URL) and write a breadcrumb on Duplicates.
  4. 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 days

Flow:

  1. Get record key.
  2. If found → stop (already processed). Optionally verify Sheets still has the row.
  3. 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.notes

Filter: proceed to Sheets only if success is true and data.total_amount is not empty (or allow empty with Status = needs_review).

Errors

CaseAction
Data Store outageFail closed (do not Add) or fail open with Sheets-only Search — pick deliberately
Sheets API 429Incomplete execution
Duplicate hitLog to Duplicates; exit success (not an error)
Cryvis failureFailures tab; no Data Store write
Empty merchant + empty totalFailures; 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

  1. Process one receipt → one Ledger row + one Data Store key.
  2. Re-run same file → zero new Ledger rows; Duplicates breadcrumb optional.
  3. Incomplete execution: cancel after Sheets Add, resume → still one row.
  4. Two different files, same merchant/date/total, empty receipt numbers → confirm fallback+Drive ID keeps them distinct.
  5. Clear Data Store key only → Search still blocks duplicate.
  6. 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 JSON and Payment Last4 from 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 data in 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.

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.