Extract Invoice Data into Google Sheets with Zapier
Build a Zap: Google Drive New File → Cryvis Invoice OCR → Google Sheets. Map invoice_number, dates, seller, and totals.
What we're building
A Drive folder drops invoice PDFs or images. Zapier posts each file to Cryvis, then appends one Sheets row with header fields — number, dates, vendor, totals. One document → one row (no line-item expansion).
Google Drive: New File in Folder
|
v
(Download / file binary available to next step)
|
v
Webhooks by Zapier: Custom Request
POST https://api.cryvis.com/v1/documents/invoice
Authorization: Bearer <API_KEY>
multipart part: file = binary
|
v
Filter: success is true
|
v
Google Sheets: Create Spreadsheet Row
invoice_number | invoice_date | due_date | currency
seller.name | buyer.name | subtotal | tax_total
total_amount | amount_due | file nameHub: Zapier + Cryvis. Multipart field names: Send multipart form data.
What you need
- Zapier account
- Google Drive folder for inbound invoices
- Google Sheet with a header row (columns in the destination section)
- Cryvis API key — Invoice API, docs at /docs/api/extractInvoice
- Sample invoice PDF or JPEG/PNG/WebP
Credits: 1 per PDF page or image. See Credits.
Create the Zap
Add steps in this order:
- Google Drive — New File in Folder (Trigger)
- Webhooks by Zapier — Custom Request (Action)
- Filter — continue only when extraction succeeded
- Google Sheets — Create Spreadsheet Row (Action)
Optional later: MIME Filter after Drive, Paths for amount thresholds, archive/move after success.
Configure source
New File in Folder
- Connect the Google account that owns (or can read) the inbox folder
- Pick the inbound folder only — do not watch the whole Drive
- Prefer uploaded PDFs/images; skip Google Docs natives unless you convert to PDF first
While testing, keep one sample file in the folder and use Zapier’s test / Zap history so you are not burning credits on every Drive sync.
Configure Cryvis HTTP
Webhooks by Zapier → Custom Request — required HTTP shape:
| Piece | Value |
|---|---|
| Method | POST |
| URL | https://api.cryvis.com/v1/documents/invoice |
| Header | Authorization: Bearer <API_KEY> |
| Body | multipart/form-data |
| Part name | file |
| Part value | binary from the Drive trigger / download step |
Do not force Content-Type: application/json. The multipart boundary must come from the HTTP client.
Accepted MIME: pdf, jpeg, png, webp. This Zap sends one file per run.
If the Custom Request returns a string body, confirm Zapier parsed JSON (or use a Formatter step) before mapping. Check success is boolean true, not the string "true".
Process response
Cryvis returns roughly:
{
"success": true,
"data": {
"invoice_number": "INV-2024-00142",
"invoice_date": "2024-03-15",
"due_date": "2024-04-14",
"currency": "USD",
"seller": { "name": "Acme Cloud Services", "tax_id": "US12-3456789" },
"buyer": { "name": "Globex Corporation" },
"line_items": [],
"subtotal": 1148.98,
"tax_total": 94.79,
"total_amount": 1193.77,
"amount_due": 1193.77
},
"meta": {}
}Map from data.*:
data.invoice_numberdata.invoice_datedata.due_datedata.currencydata.seller.namedata.buyer.namedata.subtotaldata.tax_totaldata.total_amountdata.amount_due
Nested objects need dotted paths. Do not dump the whole seller object into one cell unless you want raw JSON.
Configure destination
Sheet headers (row 1):
Invoice Number | Invoice Date | Due Date | Currency | Vendor | Buyer | Subtotal | Tax | Total | Amount Due | Source File | Processed At
Create Spreadsheet Row mapping:
| Column | Source |
|---|---|
| Invoice Number | data.invoice_number |
| Invoice Date | data.invoice_date |
| Due Date | data.due_date |
| Currency | data.currency |
| Vendor | data.seller.name |
| Buyer | data.buyer.name |
| Subtotal | data.subtotal |
| Tax | data.tax_total |
| Total | data.total_amount |
| Amount Due | data.amount_due |
| Source File | Drive file name |
| Processed At | Zapier timestamp / Formatter “now” |
Prefer Airtable instead? Use Invoice to Airtable.
Filters and error handling
Filter after Drive (recommended): continue only if filename ends with .pdf, .jpg, .jpeg, .png, or .webp.
Filter after Custom Request:
Only continue if: Custom Request → success (boolean) is trueOn hard failures, open Zap history for the Custom Request step — status code and body snippet tell you whether auth, MIME, or mapping broke. For Slack alerts on high amounts, see Automate invoice processing.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 / 403 | Bad or missing Bearer token | Header must be Authorization: Bearer … with a single space |
| Validation / missing file | Wrong part name or JSON body | Multipart part must be file, not document or attachment |
| Empty Sheets row | Mapping from top-level instead of data | Use data.invoice_number, not bare invoice_number |
| Duplicate rows | Drive re-fires on same file | Move to Processed after success; Filter on invoice_number if needed |
| Credits higher than expected | Multi-page PDF | Each page = 1 credit — Credits |
Test the Custom Request alone in Zap history before wiring Sheets. That separates API issues from mapping bugs.
Production notes
- Archive after success: move the Drive file to
/Invoices/Processedso New File does not re-pick the same PDF. - Keep the trigger folder quiet — no drafts, exports, or spreadsheets.
- Multi-page PDFs: each page costs 1 credit; huge statements add up.
- Idempotency: Filter on known
invoice_numbervalues if vendors resend the same PDF.
Next steps
Gmail intake with Slack: Automate invoice processing. Airtable AP base: Invoice to Airtable. Multipart reference: Send multipart form data.
API: extractInvoice · Product: Invoice · Hub: Zapier + Cryvis · Sign up · Pricing.