← Back to blog

Convert PDFs to JSON in Zapier with Custom Extractors

Turn non-standard PDFs into JSON in Zapier: create a Cryvis custom extractor in Console, POST multipart file to /v1/custom-extractors/:slug, map data into Google Sheets or a webhook.

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 Zapier 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 give you a stable JSON contract for documents Cryvis does not ship as /v1/documents/*.

Hub: Zapier + Cryvis. Product: Custom extraction API. Schema reference: Custom extractor schemas. Console: Extractors.

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 team already named.

Stay on built-ins when the document is that type — e.g. PAN or Indian RC. Mapping invoice field paths onto a custom response produces empty columns, not a Cryvis bug.

End-to-end flow

Console: create extractor + schema
              |
              v
        slug assigned
              |
              v
Zapier: New File in Drive / Gmail attachment
              |
              v
Custom Request
  POST /v1/custom-extractors/<slug>
  multipart field: file
              |
              v
Filter: success = true
              |
              v
Google Sheets / webhook

Credits: 1 per PDF page or 1 per image. MIME: PDF, JPEG, PNG, WebP. Auth: Bearer API key.

Step 1 — Schema in Console

In Console → Extractors:

  1. Name the extractor (e.g. Utility bill).
  2. Document description: short phrase injected into the model prompt (residential utility bill).
  3. Root schema: type: object, properties, prefer nullable unions ["string", "null"] / ["number", "null"].
  4. Mark critical IDs x-cryvis-validation: hard; noisy OCR fields soft.
  5. Save and copy the slug from the extractor detail page (used in the URL path).

Minimal utility-bill schema:

{
  "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 Zapier mappings. Full schema docs: /docs/custom-extractors. API overview: /apis/custom.

Step 2 — Zap: PDF → JSON → Sheets

Steps

  1. Google Drive → New File in Folder (PDF / image filter if available)
  2. Ensure file binary is available (download / get file content)
  3. Webhooks by Zapier → Custom Request
  4. Filter by Zapiersuccess Exactly matches true
  5. Google Sheets → Create Spreadsheet Row
    or Webhooks by Zapier → POST to your own webhook with the JSON body

Custom Request

SettingValue
MethodPOST
URLhttps://api.cryvis.com/v1/custom-extractors/YOUR_SLUG
HeadersAuthorization: Bearer sk_live_...
Payload TypeForm / multipart
Field fileDrive binary; filename from Drive

After a test run, Zapier exposes success, data, meta as mappable fields.

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": "req_custom_01hxyz",
    "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.

cURL:

curl -X POST https://api.cryvis.com/v1/custom-extractors/YOUR_SLUG \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@utility-bill.pdf"

Step 3 — Map into Sheets

ColumnMapping
Accountdata.account_number
Addressdata.service_address
Period startdata.billing_period_start
Amount duedata.amount_due
Due datedata.due_date
Valid?meta.validation.is_valid
Request IDmeta.request_id

Use Formatter / Paths to blank out literal null strings. Your data keys are only what you declared in the schema.

Webhook, Gmail, and validation

Instead of Sheets, POST JSON (data + meta.request_id) to your own endpoint with a second Custom Request. Gmail variant: Gmail → New Attachment (filter PDF) → same multipart file → Sheets.

ValidationHTTPZap tip
Soft warning200Paths → Slack review if warnings length > 0
Hard fail422Stop; fix schema/document; no Create Row
Bad key / no credits401 / 402Rotate token or pause Zap (Credits)

Do not map invoice paths (seller, line_items) onto custom data — only schema keys exist. For ID documents use built-ins via Automate KYC.

Checklist: slug in URL from /console/extractors; Console sample test; multipart field exactly file; Sheets columns = schema keys; Filter on success.

CTA

Define your schema in /console/extractors, then Custom Request POST file to https://api.cryvis.com/v1/custom-extractors/:slug with Bearer auth. Product: /apis/custom. Docs: /docs/custom-extractors. Map data.* into Sheets or forward JSON to your webhook.