Convert PDFs to JSON in Make.com with Custom Extractors
Turn non-standard PDFs into JSON in Make.com: create a Cryvis custom extractor, POST multipart file, map data into Google Sheets.
Standard invoices and receipts already have Cryvis built-ins. Everything else—utility bills, packing lists, inspection reports, vendor scorecards—needs a custom extractor: you define the JSON Schema once, then Make posts the PDF to POST https://api.cryvis.com/v1/custom-extractors/:slug.
There is still no generic PDF-to-JSON dump endpoint. Custom extractors are how you get a stable JSON contract for documents Cryvis does not ship as /v1/documents/*.
Hub: Make.com + Cryvis. Product: Custom extraction API. Schema reference: Custom extractor schemas.
When custom beats built-ins
Use a custom extractor when:
- The PDF is not an invoice, receipt, passport, PAN, Aadhaar, driver’s license, or Indian RC.
- You only need five fields from a dense form and want a closed schema (
additionalProperties: false). - Multiple vendors share an internal template your finance team already named.
Stay on built-ins when the document is that type—invoice HTTP is faster to map and already models sellers, line items, and totals. Decision tree: Extract PDF data in Make.com.
End-to-end flow
Console: create extractor + schema
|
v
slug assigned
|
v
Make: Watch Drive / Gmail attachment
|
v
HTTP POST /v1/custom-extractors/<slug>
multipart field: file
|
v
Parse JSON → data.<your keys>
|
v
Google Sheets / Airtable / webhookCredits: 1 per PDF page or 1 per image. MIME: PDF, JPEG, PNG, WebP. Auth: Bearer API key.
Step 1 — Schema in Console
- Name the extractor (e.g.
Utility bill). - Document description: short phrase injected into the model prompt (
residential utility bill). - Root schema:
type: object,properties, prefer nullable unions["string", "null"]/["number", "null"]. - Mark critical IDs
x-cryvis-validation: hard; noisy OCR fieldssoft. - Save and copy the slug from the extractor detail page (path id used in the URL).
Minimal example for a utility bill:
{
"type": "object",
"properties": {
"account_number": {
"type": ["string", "null"],
"description": "Utility account or customer number",
"x-cryvis-validation": "hard"
},
"service_address": {
"type": ["string", "null"],
"description": "Service location as printed",
"x-cryvis-validation": "soft"
},
"billing_period_start": {
"type": ["string", "null"],
"format": "date",
"description": "Period start YYYY-MM-DD",
"x-cryvis-validation": "soft"
},
"billing_period_end": {
"type": ["string", "null"],
"format": "date",
"description": "Period end YYYY-MM-DD",
"x-cryvis-validation": "soft"
},
"amount_due": {
"type": ["number", "null"],
"description": "Total amount due",
"x-cryvis-validation": "soft"
},
"due_date": {
"type": ["string", "null"],
"format": "date",
"description": "Payment due date",
"x-cryvis-validation": "soft"
}
},
"required": ["account_number"],
"additionalProperties": false
}Upload a real sample in Console and inspect meta.validation.warnings before you trust Make mappings. Field-design tips: Extract specific fields from PDFs. Full build walkthrough: Build a custom document extractor.
Step 2 — Make scenario: PDF → JSON → Sheets
Modules
- Google Drive — Watch Files in a Folder (PDF filter)
- Google Drive — Download a File
- HTTP — Make a Request
- Google Sheets — Add a Row (or Update a Row if you upsert by account number)
HTTP module
| Setting | Value |
|---|---|
| URL | https://api.cryvis.com/v1/custom-extractors/YOUR_SLUG |
| Method | POST |
| Body type | Multipart/form-data |
| Header | Authorization: Bearer sk_live_... |
Field file | File → map Drive binary; filename from Drive |
Enable Parse response so Make exposes success, data, meta as mappable collections.
Successful response shape
{
"success": true,
"data": {
"account_number": "48291033",
"service_address": "12 Oak St",
"billing_period_start": "2026-02-01",
"billing_period_end": "2026-02-28",
"amount_due": 94.2,
"due_date": "2026-03-15"
},
"meta": {
"document_type": "custom:YOUR_SLUG",
"request_id": "...",
"validation": {
"is_valid": true,
"warnings": [],
"confidence": 1
}
}
}Hard validation failures return 422 with error.code VALIDATION_ERROR—not a partial data object. Soft failures stay 200 with warnings in meta.validation.
Step 3 — Map into Sheets
| Column | Mapping |
|---|---|
| Account | data.account_number |
| Address | data.service_address |
| Period start | data.billing_period_start |
| Amount due | data.amount_due |
| Due date | data.due_date |
| Valid? | meta.validation.is_valid |
| Request ID | meta.request_id |
Use ifempty() for nullable fields so empty cells stay empty instead of the literal string null. Nested objects and arrays: Map API JSON fields in Make.com.
Gmail variant
Replace Drive with Gmail — Watch Emails → Iterate attachments → filter application/pdf → HTTP custom extractor → Sheets. Same multipart file mapping; binary comes from the attachment bundle (Upload a file to Cryvis).
Soft vs hard in production Make flows
| Validation | HTTP status | Make behavior tip |
|---|---|---|
| Soft warning | 200 | Route on meta.validation.warnings length → Slack review queue |
| Hard fail | 422 | Error Handler → Break; fix schema or document |
| Bad key | 401 | Rotate Bearer token (auth guide) |
| No credits | 402 | Pause scenario; top up Console billing |
Do not confuse with invoice JSON
POST /v1/documents/invoice returns seller, line_items, total_amount, etc. Your custom data only contains keys you declared. Mapping invoice paths onto a custom response will produce empty Sheets columns—not a Cryvis bug.
Checklist
- Extractor created; slug copied into the HTTP URL
- Schema tested in Console with a real PDF
- Make multipart field name is exactly
file - Sheets columns mirror schema keys (not invoice field names)
- Error handler + optional Router for validation warnings
Next: wire multiple sources and destinations with the structured data pattern guide, or tighten field lists in extract specific fields.