API documentation

Send a PDF, Word document or image, get structured JSON back.

Introduction

You describe the data you want as a category: a list of fields such as invoice number, date or line items, set up in the dashboard. Parsevix reads the document, fills those fields and returns them as JSON, together with the text it read and where each value was found.

The API is served over HTTPS from one base URL. Requests and responses are JSON, except file uploads, which are multipart/form-data.

https://parsevix.com/api/v1

Every API key belongs to one project. A key sees and changes only that project's documents, categories and webhooks.

Besides calling the API you can receive results through webhooks, connect Zapier, or send documents to a project's email address.

Conventions

  • API responses use camelCase field names. Webhook and callback bodies use snake_case.
  • Timestamps are UTC, in ISO 8601 (2026-10-25T10:12:06.791Z).
  • Error messages are in English, German, Turkish, French, Spanish, Italian, Dutch, Polish or Portuguese, following the Accept-Language header.

Quickstart

  1. 1

    Create an API key

    In the dashboard, open your project, go to API Keys and create a key. It is shown once; store it, for example as the environment variable PARSEVIX_API_KEY. The Free plan includes one key, paid plans more (see Limits and credits).

  2. 2

    Define a category

    Under Categories, create a category for your document type and add the fields you need, or start from a built-in template. The examples on this page use a category named Supplier invoice.

  3. 3

    Send a document

    POST /extract uploads the file and waits for the result. The response contains the filled fields under extracted.

To process many documents without holding requests open, upload asynchronously and receive results through webhooks.

curl https://parsevix.com/api/v1/extract \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -F file=@invoice.pdf \
  -F category="Supplier invoice"
Response200· shortened
{
  "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
  "fileName": "invoice.pdf",
  "status": "Completed",
  "category": "Supplier invoice",
  "processingMode": "specific",
  "confidenceScore": 0.97,
  "pageCount": 1,
  "language": "en",
  "retained": false,
  "extracted": {
    "invoice_number": "F-2026-88343",
    "invoice_date": "2026-10-03",
    "due_date": "2026-10-17",
    "currency": "GBP",
    "seller": {
      "name": "Northgate Systems Ltd",
      "vat_id": "GB566163740"
    },
    "line_items": [
      {
        "description": "LED panel light",
        "quantity": 4,
        "unit_price": 542.55,
        "total": 2170.2
      },
      {
        "description": "Office chair",
        "quantity": 1,
        "unit_price": 475.86,
        "total": 475.86
      }
    ],
    "gross_total": 7848.88,
    "_field_blocks": {
      "invoice_number": [
        {
          "page": 1,
          "x": 35.04,
          "y": 378.24,
          "width": 159.84,
          "height": 11.04,
          "text": "Invoice number: F-2026-88343"
        }
      ],
      "seller.name": [
        {
          "page": 1,
          "x": 34.08,
          "y": 558.24,
          "width": 120.48,
          "height": 12.96,
          "text": "Northgate Systems Ltd"
        }
      ]
    }
  }
}

Video tutorials

Five short videos show the main steps in the dashboard and your first API request. Each has voice-over and subtitles in nine languages: choose them under the gear icon in the player.

The videos play from YouTube (youtube-nocookie.com). Nothing is loaded from YouTube until you click play; then Google receives your IP address and may store cookies. See our Privacy Policy.

Authentication

Send your API key in the X-API-Key header with every request.

X-API-Key: psvx_…

A key works only on /api/v1; it cannot sign in to the dashboard. Keys are created and revoked under API Keys in the project. A revoked key stops working immediately.

Keep keys on your server. Anyone who has a key can upload documents and read the project's results, and the uploads use your credits.

When a key is refused

StatusCodeMeaning
401apikey.missingNo X-API-Key header was sent.
401apikey.invalidThe key does not exist or was revoked.
403apikey.plan_disabledThe account's plan does not include API access.
403apikey.paused_by_planThe key or its project is paused because the account's plan allows fewer keys or projects.
403apikey.account_unavailableThe account is closed or scheduled for deletion.
403apikey.project_unavailableThe key's project was deleted.
429apikey.too_many_invalidMore than 30 invalid keys came from your network within 10 minutes. Wait Retry-After seconds; a key that worked recently is not blocked.
Response401
{
  "error": {
    "code": "apikey.invalid",
    "message": "The API key is not valid. It may have been revoked; create a new one in the project under API Keys."
  }
}

Processing modes

Each upload is read in one of four ways.

  • Automatic category (auto-classify). Parsevix picks the best-matching category of the project, then extracts its fields. Used when you send no category, or category=auto.
  • Classify only (classify-only). Parsevix picks the best-matching category and extracts nothing, for sorting documents by type. It reads the first 3 pages and costs 1 credit per document. The fields can be extracted later. See Classify a document.
  • Specific category (specific). You name the category; its fields are extracted.
  • Without a schema (auto-entity). No category is used. Parsevix returns the fields it finds, named after the document's own labels. See Extract without a schema.

The document's language is detected automatically. The optional language parameter is only a fallback for documents with too little text to detect.

Extract a document

POST/api/v1/extract

Uploads a document and waits until it is processed. The response contains the extracted fields.

filefilerequired
The document: PDF, DOCX, PNG, JPEG or TIFF, up to 10 MB and 30 pages.
categorystringoptional
Name of a category in the project. Leave it out, or send auto, to let Parsevix choose.
languagestringoptional
Two-letter ISO 639-1 code, such as de. Used only if the language cannot be detected.

Waiting and limits

  • The request stays open until the result is ready, for at most 285 seconds. Set your HTTP client's timeout above that.
  • If processing takes longer, you get 504 with document.sync_timeout and the documentId. Processing continues; the result goes to your webhooks.
  • If processing fails, you get 422 with document.sync_failed. reason says why; see failure reasons.
  • Each API key can have 5 requests open at once. More return 429 with document.sync_concurrency_limit. A request you close, or one that times out, keeps its place until its document is processed. For bulk uploads use asynchronous upload.

Response

idstring
Document id.
fileNamestring
The uploaded file's name.
statusstring
Completed.
categorystring | null
The category used; null without a schema.
processingModestring
auto-classify, specific or auto-entity.
confidenceScorenumber
Between 0 and 1: how certain the extraction is.
pageCountinteger
Pages processed; each costs one credit.
languagestring
Detected language, ISO 639-1.
retainedboolean
Whether Parsevix keeps the file and result. See Data retention.
extractedobject
The extracted fields. See The result.
curl https://parsevix.com/api/v1/extract \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -F file=@invoice.pdf \
  -F category="Supplier invoice"
Response200· shortened
{
  "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
  "fileName": "invoice.pdf",
  "status": "Completed",
  "category": "Supplier invoice",
  "processingMode": "specific",
  "confidenceScore": 0.97,
  "pageCount": 1,
  "language": "en",
  "retained": false,
  "extracted": {
    "invoice_number": "F-2026-88343",
    "invoice_date": "2026-10-03",
    "due_date": "2026-10-17",
    "currency": "GBP",
    "seller": {
      "name": "Northgate Systems Ltd",
      "vat_id": "GB566163740"
    },
    "line_items": [
      {
        "description": "LED panel light",
        "quantity": 4,
        "unit_price": 542.55,
        "total": 2170.2
      },
      {
        "description": "Office chair",
        "quantity": 1,
        "unit_price": 475.86,
        "total": 475.86
      }
    ],
    "gross_total": 7848.88,
    "_field_blocks": {
      "invoice_number": [
        {
          "page": 1,
          "x": 35.04,
          "y": 378.24,
          "width": 159.84,
          "height": 11.04,
          "text": "Invoice number: F-2026-88343"
        }
      ],
      "seller.name": [
        {
          "page": 1,
          "x": 34.08,
          "y": 558.24,
          "width": 120.48,
          "height": 12.96,
          "text": "Northgate Systems Ltd"
        }
      ]
    }
  }
}
Response422
{
  "error": {
    "code": "document.sync_failed",
    "message": "The file is damaged or is not a valid PDF, Word document or image.",
    "reason": "file_unreadable",
    "documentId": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581"
  }
}
Response504
{
  "error": {
    "code": "document.sync_timeout",
    "message": "Extraction did not finish within 285 seconds. Large documents may need to be split.",
    "documentId": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581"
  }
}

Extract without a schema

POST/api/v1/extract-auto

Like POST /extract, but without a category: Parsevix returns whatever fields it finds in the document.

filefilerequired
The document: PDF, DOCX, PNG, JPEG or TIFF, up to 10 MB and 30 pages.
languagestringoptional
Two-letter ISO 639-1 code. Used only if the language cannot be detected.

The output stays in the document's language. Keys are the document's own labels in snake_case (an invoice in German gives rechnungsnummer), and values are copied as printed: dates in the document's format, amounts as strings such as "2.430,09".

Use it to explore a new document type. For data you process automatically, a category gives you fixed keys and normalised values.

The response has the same fields as POST /extract, with processingMode auto-entity and category null.

curl https://parsevix.com/api/v1/extract-auto \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -F file=@invoice.pdf

Classify a document

POST/api/v1/classify

Uploads a document and waits until Parsevix has chosen one of the project's categories. No fields are extracted. Use it to sort or route documents by type.

The candidates are the project's own categories, not the built-in templates. Parsevix reads the first 3 pages, so a classification costs 1 credit however long the document is.

filefilerequired
The document: PDF, DOCX, PNG, JPEG or TIFF, up to 10 MB and 30 pages.
languagestringoptional
Two-letter ISO 639-1 code. Used only if the language cannot be detected.

Waiting and errors work as for POST /extract: at most 285 seconds, 504 with document.sync_timeout if it takes longer, 422 with document.sync_failed if the document cannot be processed. The 5 open requests per key are shared by both endpoints.

Response

idstring
Document id.
fileNamestring
The uploaded file's name.
statusstring
Completed.
categorystring
The category Parsevix chose.
processingModestring
classify-only.
pageCountinteger
Pages in the document. The first 3 were read.
languagestring
Detected language, ISO 639-1.
retainedboolean
Whether Parsevix keeps the file. Only a kept document can be extracted later.

Extracting later

POST /documents/{id}/extract extracts the document's fields, as the category it was given or as one you name. It costs the document's pages less the 1 credit already paid: a 5-page document costs 4 more, 5 in total.

That needs the file, so the project must keep API uploads (see Data retention). Documents sent from the dashboard or by email are always kept. Asynchronous uploads can be classified too: processingMode=classify-only on POST /documents.

curl https://parsevix.com/api/v1/classify \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -F file=@invoice.pdf
Response200
{
  "id": "01a172b4-5d2e-7c61-8f0a-3b9d6e1c4a27",
  "fileName": "invoice.pdf",
  "status": "Completed",
  "category": "Supplier invoice",
  "processingMode": "classify-only",
  "pageCount": 1,
  "language": "en",
  "retained": true
}

Upload asynchronously

POST/api/v1/documents

Queues a document and answers immediately with 202 and the document record. Use it for bulk uploads and for clients that cannot keep a request open, such as Zapier.

filefilerequired
The document: PDF, DOCX, PNG, JPEG or TIFF, up to 10 MB and 30 pages.
categorystringoptional
Name of a category. Leave it out, or send auto, to let Parsevix choose.
processingModestringoptional
auto-classify, specific, auto-entity or classify-only. Optional: by default it follows from category. classify-only cannot be combined with a category.
languagestringoptional
Two-letter ISO 639-1 code. Used only if the language cannot be detected.
callbackUrlstringoptional
A public https URL. Parsevix sends the result there once, as a POST with the same body as a webhook event.

Getting the result

  • Webhooks of the project receive extraction.completed or extraction.failed. A classify-only upload sends classification.completed instead of extraction.completed.
  • callbackUrl, if given, receives the same event, with the same retries. It is not signed, so put a secret token in the URL and check it.
  • Polling GET /documents/{id} shows the status, and the result only if the project keeps API uploads (see Data retention).
curl https://parsevix.com/api/v1/documents \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -F file=@invoice.pdf \
  -F category="Supplier invoice" \
  -F callbackUrl="https://example.com/parsevix/callback?token=a-secret-only-you-know"
Response202
{
  "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
  "status": "Pending",
  "categoryName": "Supplier invoice",
  "processingMode": "specific",
  "fileName": "invoice.pdf",
  "fileSize": 22579,
  "source": "api",
  "discardFiles": true,
  "createdAt": "2026-10-25T10:12:06.791Z",
  "completedAt": null,
  "reprocessCount": 0,
  "lastReprocessedAt": null,
  "approvalStatus": "Unapproved",
  "isTrainingExample": false
}

The result

extracted

An object keyed by the category's field names (fieldName in the category schema). Objects and lists follow the schema.

Dates are YYYY-MM-DD. Numbers are JSON numbers, without currency symbols or thousand separators. A field the document doesn't contain is left out or null.

Personal data such as names and IBANs is returned as written in the document. It is masked only on the way to the AI model and restored before you receive it.

_field_blocks

Where each value was found. Keys are field paths such as seller.name or line_items[0].total; each entry lists the text lines with page, box and text. A value that could not be located is missing from it. Ignore keys starting with _ if you only need the data.

Coordinates

  • PDF and DOCX: PDF points (1/72 inch). The origin is the bottom-left corner of the page; y is the top edge of the box, measured from the bottom.
  • Images: pixels. The origin is the top-left corner; y is the top edge, measured from the top.
extracted200· shortened
{
  "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
  "fileName": "invoice.pdf",
  "status": "Completed",
  "category": "Supplier invoice",
  "processingMode": "specific",
  "confidenceScore": 0.97,
  "pageCount": 1,
  "language": "en",
  "retained": false,
  "extracted": {
    "invoice_number": "F-2026-88343",
    "invoice_date": "2026-10-03",
    "due_date": "2026-10-17",
    "currency": "GBP",
    "seller": {
      "name": "Northgate Systems Ltd",
      "vat_id": "GB566163740"
    },
    "line_items": [
      {
        "description": "LED panel light",
        "quantity": 4,
        "unit_price": 542.55,
        "total": 2170.2
      },
      {
        "description": "Office chair",
        "quantity": 1,
        "unit_price": 475.86,
        "total": 475.86
      }
    ],
    "gross_total": 7848.88,
    "_field_blocks": {
      "invoice_number": [
        {
          "page": 1,
          "x": 35.04,
          "y": 378.24,
          "width": 159.84,
          "height": 11.04,
          "text": "Invoice number: F-2026-88343"
        }
      ],
      "seller.name": [
        {
          "page": 1,
          "x": 34.08,
          "y": 558.24,
          "width": 120.48,
          "height": 12.96,
          "text": "Northgate Systems Ltd"
        }
      ]
    }
  }
}

Documents

Documents of the project, from every source: the dashboard, the API and email.

List documents

GET/api/v1/documents

Newest first. Lists only stored documents: API uploads appear only if the project keeps them.

pageintegeroptional
Page number, from 1.
pageSizeintegeroptional
1 to 100; default 20.
statusstringoptional
Pending, Processing, Completed or Failed.
categorystringoptional
Category name.
searchstringoptional
Part of the file name.
fileTypestringoptional
pdf, docx or image.
sourcestringoptional
dashboard, api or email.
processingModestringoptional
auto-classify, specific, auto-entity or classify-only.

Get a document

GET/api/v1/documents/{id}

The document with its result. outputDeanonymized is the extracted data, the same object as extracted. A classify-only document has its category in categoryName and no outputDeanonymized. A failed document has errorCode and errorMessage. If the project does not keep API uploads, the status is available but the result is not.

Reprocess a document

POST/api/v1/documents/{id}/reprocess

Runs the extraction again, for example after you changed the category's fields. Optional JSON body: category (a name, or auto) and processingMode. Answers 202; the result arrives like an asynchronous upload's. Credits are charged again. A classify-only document is classified again (1 credit) unless you name a category. Not possible for API uploads whose files were not kept (document.files_not_retained).

Extract a classified document

POST/api/v1/documents/{id}/extract

For a document uploaded with classify-only: extracts its fields as the category it was given, or as the category named in the optional JSON body. Costs the document's pages less the 1 credit the classification cost. Answers 202; the result arrives like an asynchronous upload's, as extraction.completed. For any other document it answers 400 with document.not_classify_only; use reprocess instead.

Delete a document

DELETE/api/v1/documents/{id}

Deletes the document, its file and its results. Answers 204.

An id that doesn't exist in the key's project returns 404 with document.not_found.

cURL
curl "https://parsevix.com/api/v1/documents?status=Completed&pageSize=20" \
  -H "X-API-Key: $PARSEVIX_API_KEY"
Response200· shortened
{
  "data": [
    {
      "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
      "status": "Completed",
      "categoryName": "Supplier invoice",
      "processingMode": "specific",
      "fileName": "invoice.pdf",
      "fileSize": 22579,
      "source": "api",
      "discardFiles": false,
      "createdAt": "2026-10-25T10:12:06.791Z",
      "completedAt": "2026-10-25T10:12:15.212Z",
      "reprocessCount": 0,
      "lastReprocessedAt": null,
      "approvalStatus": "Unapproved",
      "isTrainingExample": false
    }
  ],
  "totalCount": 1,
  "page": 1,
  "pageSize": 20
}
curl https://parsevix.com/api/v1/documents/01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581 \
  -H "X-API-Key: $PARSEVIX_API_KEY"
Response200· shortened
{
  "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
  "status": "Completed",
  "categoryName": "Supplier invoice",
  "processingMode": "specific",
  "fileName": "invoice.pdf",
  "fileSize": 22579,
  "source": "api",
  "language": "en",
  "confidenceScore": 0.97,
  "pageCount": 1,
  "outputDeanonymized": {
    "invoice_number": "F-2026-88343",
    "invoice_date": "2026-10-03",
    "due_date": "2026-10-17",
    "currency": "GBP",
    "seller": {
      "name": "Northgate Systems Ltd",
      "vat_id": "GB566163740"
    },
    "line_items": [
      {
        "description": "LED panel light",
        "quantity": 4,
        "unit_price": 542.55,
        "total": 2170.2
      },
      {
        "description": "Office chair",
        "quantity": 1,
        "unit_price": 475.86,
        "total": 475.86
      }
    ],
    "gross_total": 7848.88,
    "_field_blocks": {
      "invoice_number": [
        {
          "page": 1,
          "x": 35.04,
          "y": 378.24,
          "width": 159.84,
          "height": 11.04,
          "text": "Invoice number: F-2026-88343"
        }
      ],
      "seller.name": [
        {
          "page": 1,
          "x": 34.08,
          "y": 558.24,
          "width": 120.48,
          "height": 12.96,
          "text": "Northgate Systems Ltd"
        }
      ]
    }
  },
  "errorMessage": null,
  "errorCode": null,
  "createdAt": "2026-10-25T10:12:06.791Z",
  "completedAt": "2026-10-25T10:12:15.212Z"
}
cURL
curl https://parsevix.com/api/v1/documents/01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581/reprocess \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"category": "auto"}'
cURL
curl https://parsevix.com/api/v1/documents/01a172b4-5d2e-7c61-8f0a-3b9d6e1c4a27/extract \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Response202
{
  "id": "01a172b4-5d2e-7c61-8f0a-3b9d6e1c4a27",
  "status": "Pending",
  "categoryName": "Supplier invoice",
  "processingMode": "specific",
  "fileName": "invoice.pdf",
  "fileSize": 22579,
  "source": "api",
  "discardFiles": false,
  "createdAt": "2026-10-25T10:12:06.791Z",
  "completedAt": null,
  "reprocessCount": 1,
  "lastReprocessedAt": "2026-10-25T11:04:12.530Z",
  "approvalStatus": "Unapproved",
  "isTrainingExample": false
}
cURL
curl -X DELETE https://parsevix.com/api/v1/documents/01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581 \
  -H "X-API-Key: $PARSEVIX_API_KEY"

Categories

The project's categories, including the built-in templates (isGlobal: true). Categories are created and edited in the dashboard.

List categories

GET/api/v1/categories

Get a category's schema

GET/api/v1/categories/{name}

The fields a category extracts. fieldName is the key in extracted. fieldType is string, number, date, boolean, object or array; objects and arrays have their fields in children. The name in the path is not case-sensitive.

cURL
curl https://parsevix.com/api/v1/categories \
  -H "X-API-Key: $PARSEVIX_API_KEY"
Response200· shortened
[
  {
    "id": 1,
    "name": "Invoice",
    "description": "Invoices and billing documents with seller/buyer info, line items, and totals",
    "isGlobal": true,
    "fieldCount": 48
  },
  {
    "id": 54,
    "name": "Supplier invoice",
    "description": "Commercial invoice: seller, buyer, line items and totals.",
    "isGlobal": false,
    "fieldCount": 26
  }
]
cURL
curl "https://parsevix.com/api/v1/categories/Supplier%20invoice" \
  -H "X-API-Key: $PARSEVIX_API_KEY"
Response200· shortened
{
  "id": 54,
  "name": "Supplier invoice",
  "description": "Commercial invoice: seller, buyer, line items and totals.",
  "fields": [
    {
      "fieldName": "invoice_number",
      "displayName": "Invoice number",
      "fieldType": "string",
      "description": null,
      "children": []
    },
    {
      "fieldName": "invoice_date",
      "displayName": "Invoice date",
      "fieldType": "date",
      "description": null,
      "children": []
    },
    {
      "fieldName": "seller",
      "displayName": "Seller",
      "fieldType": "object",
      "description": null,
      "children": [
        {
          "fieldName": "name",
          "displayName": "Name",
          "fieldType": "string",
          "description": null,
          "children": []
        },
        {
          "fieldName": "vat_id",
          "displayName": "VAT / tax id",
          "fieldType": "string",
          "description": null,
          "children": []
        }
      ]
    }
  ]
}

Key and credits

GET/api/v1/me

The key's project and the account's credit balance. Credits belong to the account and are shared by all its projects; resetsOn is the start of the next period. On an annual plan the period is the billing year and monthlyLimit holds the whole year's credits.

cURL
curl https://parsevix.com/api/v1/me \
  -H "X-API-Key: $PARSEVIX_API_KEY"
Response200
{
  "projectId": "01a16af3-0b1f-7f2f-8282-b3824309d921",
  "projectName": "Accounts payable",
  "projectSlug": "accounts-payable",
  "keyName": "ERP connector",
  "keyPrefix": "psvx_nyskxlv",
  "email": "you@example.com",
  "credits": {
    "period": "2026-10-04",
    "resetsOn": "2026-11-04",
    "monthlyLimit": 1000,
    "used": 312,
    "remaining": 688,
    "planName": "Growth"
  }
}

Manage webhooks

Webhooks can be managed in the dashboard (Webhooks) or through these endpoints.

Create a webhook

POST/api/v1/webhooks
urlstringrequired
A public https URL. Addresses in private networks are refused.
eventsstring[]required
One or more of extraction.completed, extraction.failed and classification.completed.
filtersobjectoptional
Optional. sources (dashboard, api, email) and categories (names) limit which documents send events.

The response contains the signing secret once. Store it to verify signatures.

List webhooks

GET/api/v1/webhooks

Delete a webhook

DELETE/api/v1/webhooks/{id}

Sample events

GET/api/v1/webhooks/samples

The latest documents of the project as event bodies, for testing your receiver. Query: event (required), limit (1–10, default 3), category. If there is no such document yet, a sample is built from the category schema.

cURL
curl https://parsevix.com/api/v1/webhooks \
  -H "X-API-Key: $PARSEVIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/parsevix/webhook",
    "events": ["extraction.completed", "extraction.failed"],
    "filters": { "sources": ["api", "email"] }
  }'
Response201
{
  "secret": "d0726faeb5c655d349fc30ed226e93e531ac2499800aacde100e83554b48701c",
  "id": "01a17295-c761-7b8f-b173-388bc754b1ba",
  "url": "https://example.com/parsevix/webhook",
  "events": [
    "extraction.completed",
    "extraction.failed"
  ],
  "filters": {
    "sources": [
      "api",
      "email"
    ],
    "categories": null
  },
  "isActive": true,
  "disabledAt": null,
  "disabledReason": null,
  "managedBy": null,
  "createdAt": "2026-10-25T10:23:09.311Z"
}
cURL
curl "https://parsevix.com/api/v1/webhooks/samples?event=extraction.completed&limit=1" \
  -H "X-API-Key: $PARSEVIX_API_KEY"

Webhooks

When a document is finished, Parsevix sends a POST with a JSON body to each of the project's webhooks. Webhooks receive documents from every source: dashboard, API and email.

Events

EventDescription
extraction.completedA document was processed. data holds the extracted fields.
classification.completedA classify-only document got its category: document.category, with the document's pages in document.page_count. There is no data.
extraction.failedA document could not be processed, also a classify-only one. error_code is one of the failure reasons; error is the message shown in the dashboard.
test.pingSent by the Test button on a webhook's page in the dashboard.

Headers

HeaderDescription
X-Webhook-IdEvent id. The same in every attempt; use it to ignore duplicates. Also the body's id.
X-Webhook-EventThe event name.
X-Webhook-TimestampUnix time of this attempt, in seconds.
X-Webhook-Signaturesha256= followed by the hex HMAC-SHA256 of {timestamp}.{raw body}, keyed with the webhook's secret.
X-Webhook-AttemptAttempt number, from 1.

Verify the signature

Compute the HMAC over the raw request body exactly as received, before parsing it. Reject events whose timestamp is more than 5 minutes old.

Responding

  • Answer with a 2xx status within 10 seconds, then process the event. Anything else counts as a failure. Redirects are not followed.
  • Failed deliveries are retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 24 hours: 7 attempts over about 33 hours.
  • Answering 410 Gone switches the webhook off at once. It is also switched off when three events have failed every attempt and no delivery has succeeded for 3 days. The owner gets an email; turn it back on in the dashboard. Events in between are not sent again.
  • The secret can be rotated in the dashboard. The old secret stops working at once.
extraction.completed200· shortened
{
  "id": "01a172a0-3f1e-7d42-9b6c-8e2f5a7d1c90",
  "event": "extraction.completed",
  "timestamp": "2026-10-25T10:12:21.592Z",
  "project_id": "01a16af3-0b1f-7f2f-8282-b3824309d921",
  "project_name": "Accounts payable",
  "project_slug": "accounts-payable",
  "document": {
    "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
    "file_name": "invoice.pdf",
    "category": "Supplier invoice",
    "source": "api",
    "processing_mode": "specific",
    "language": "en",
    "confidence_score": 0.97
  },
  "data": {
    "invoice_number": "F-2026-88343",
    "invoice_date": "2026-10-03",
    "due_date": "2026-10-17",
    "currency": "GBP",
    "seller": {
      "name": "Northgate Systems Ltd",
      "vat_id": "GB566163740"
    },
    "line_items": [
      {
        "description": "LED panel light",
        "quantity": 4,
        "unit_price": 542.55,
        "total": 2170.2
      },
      {
        "description": "Office chair",
        "quantity": 1,
        "unit_price": 475.86,
        "total": 475.86
      }
    ],
    "gross_total": 7848.88,
    "_field_blocks": {
      "invoice_number": [
        {
          "page": 1,
          "x": 35.04,
          "y": 378.24,
          "width": 159.84,
          "height": 11.04,
          "text": "Invoice number: F-2026-88343"
        }
      ],
      "seller.name": [
        {
          "page": 1,
          "x": 34.08,
          "y": 558.24,
          "width": 120.48,
          "height": 12.96,
          "text": "Northgate Systems Ltd"
        }
      ]
    }
  }
}
classification.completed200
{
  "id": "01a172b5-8e47-7a13-b2c9-4f6d0a8e3b51",
  "event": "classification.completed",
  "timestamp": "2026-10-25T10:14:02.334Z",
  "project_id": "01a16af3-0b1f-7f2f-8282-b3824309d921",
  "project_name": "Accounts payable",
  "project_slug": "accounts-payable",
  "document": {
    "id": "01a172b4-5d2e-7c61-8f0a-3b9d6e1c4a27",
    "file_name": "invoice.pdf",
    "category": "Supplier invoice",
    "source": "api",
    "processing_mode": "classify-only",
    "language": "en",
    "page_count": 1
  }
}
extraction.failed200
{
  "id": "01a172a1-0c55-7e18-a3d4-6b9f2e8c1d07",
  "event": "extraction.failed",
  "timestamp": "2026-10-25T10:12:23.711Z",
  "project_id": "01a16af3-0b1f-7f2f-8282-b3824309d921",
  "project_name": "Accounts payable",
  "project_slug": "accounts-payable",
  "document": {
    "id": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581",
    "file_name": "invoice.pdf",
    "category": "Supplier invoice",
    "source": "api",
    "processing_mode": "specific"
  },
  "error_code": "file_unreadable",
  "error": "The file is damaged or is not a valid PDF, Word document or image."
}
import hashlib
import hmac
import time

def verify(raw_body: bytes, headers, secret: str) -> bool:
    timestamp = headers["X-Webhook-Timestamp"]
    signature = headers["X-Webhook-Signature"]  # "sha256=<hex>"
    if abs(time.time() - int(timestamp)) > 300:
        return False  # older than 5 minutes: possibly replayed
    expected = hmac.new(
        secret.encode(),
        timestamp.encode() + b"." + raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(signature, "sha256=" + expected)

Zapier

The Parsevix app for Zapier connects with an API key of a project. Add it through the invite link on the project's Zapier page in the dashboard or here.

Triggers

  • Extraction Completed: a document was processed. Optionally only one category or source.
  • Extraction Failed: a document could not be processed.
  • Document Classified: a document sent only to be classified got its category, for example from an email address set to classify only.

Actions

  • Extract Document sends a file from an earlier step, optionally with a category, and passes the extracted fields to the next steps. With a category chosen, its fields can be mapped while you build the Zap.
  • Classify Document sends a file and passes the category Parsevix chose to the next steps, without extracting fields. Use it to route documents by type.

Zaps you turn on appear on the project's Zapier page and under Webhooks.

Email

From the Starter plan on, every project has an email address under Email inbox. Each attachment of a mail sent to it becomes a document; the results appear in the dashboard and are sent to your webhooks with source email.

Addresses look like name+inbox@inbox.parsevix.com. Depending on the plan, a project can have more than one, for example one per supplier or department.

Per address

  • Attachments: extract every attachment as one fixed category; let Parsevix choose the category, then extract; or only choose the category (classify-only, 1 credit per document), with the fields extracted later if you need them.
  • Allowed senders: only mail from these domains is accepted, and only if it passes DKIM or SPF for that domain, so a forged sender is rejected.

What is processed

  • PDF, DOCX, PNG, JPEG and TIFF attachments, including those inside forwarded mails. Images shown in the mail body, such as signature logos, are skipped.
  • A mail may be up to 30 MB, and its first 20 attachments become documents. One address takes up to 1,000 mails and makes up to 1,000 documents in 24 hours; past that, mail is refused and attachments are listed as not imported. Receiving is free; each document costs credits like any other.
  • The same mail delivered twice (same Message-ID) is processed once.

Errors

Errors have an HTTP status and a body with a stable code and a readable message. Branch on code; messages can change.

Status codes

StatusMeaning
400The request is invalid: a missing or wrong parameter, an unsupported file, too few credits. validation.failed lists the problems per parameter in fields.
401No API key, or not a valid one.
403The key is valid but may not be used. See Authentication.
404The document, category, webhook or endpoint does not exist in this project.
413The upload is larger than the request limit.
422POST /extract or POST /classify ran, but the document could not be processed.
429Rate limit or concurrency limit reached. Wait Retry-After seconds.
5xxA server error (with a reference to quote to support), maintenance (503) or a timeout (504).

Common codes

CodeMeaning
validation.file_requiredNo file was sent.
document.content_not_supportedThe file's content is not PDF, DOCX, PNG, JPEG or TIFF, whatever its name says.
credit.file_size_exceeds_planThe file is larger than the plan allows.
validation.language_invalidlanguage is not a two-letter code.
document.callback_url_*callbackUrl is not a public https URL of at most 2,000 characters.
credit.insufficient_creditsNot enough credits left this period.
document.refund_pendingA refund of the subscription is being reviewed; nothing is processed until it is settled.
category.not_foundNo category with that name in the project.
document.classify_only_categoryclassify-only was sent together with a category. The mode chooses the category itself.
document.not_classify_onlyPOST /documents/{id}/extract was called for a document not uploaded with classify-only.
document.files_not_retainedThe API upload's files were not kept, so it cannot be reprocessed.
webhook.url_*The webhook URL is not a public https URL.
*.limit_reachedA plan limit was reached, such as the number of webhooks per project.

Failure reasons

Why a document failed: reason in the 422 from POST /extract or POST /classify, error_code in extraction.failed, errorCode on the document.

CodeMeaning
too_many_pagesMore than 30 pages. Split the file.
sync_too_many_pagesMore pages than POST /extract and POST /classify accept.
pdf_encryptedThe PDF is password-protected.
file_unreadableThe file is damaged or not a valid document.
no_textNo text was found: blank, or the scan is unreadable.
no_categoriesThe category was to be chosen automatically, but the project has no categories.
no_schema_fieldsThe category has no fields.
no_fields_foundNone of the category's fields was found in the document; it is probably in the wrong category. Reprocess it with the right one.
no_data_foundAutomatic extraction found no data in the document.
insufficient_creditsThe document needs more credits than are left this period. Nothing was charged; reprocess it after an upgrade or the reset.
refund_pendingA refund of the subscription was being reviewed. If it is declined, reprocess the document.
masking_failedPersonal data could not be masked, so the document was not sent to the AI model. Retry.
worker_unavailableProcessing was temporarily unavailable. Retry.
ai_failedThe AI model failed temporarily. Retry.
processing_failedAn internal error. Retry; contact support if it repeats.
processing_timeoutProcessing stopped before it finished (for example during a restart). Retry.

The last five are temporary: reprocess the document or send it again. Failed runs are not charged per page.

Response400
{
  "error": {
    "code": "validation.failed",
    "message": "The file field is required.",
    "fields": {
      "file": [
        "The file field is required."
      ]
    }
  }
}
Response422
{
  "error": {
    "code": "document.sync_failed",
    "message": "The file is damaged or is not a valid PDF, Word document or image.",
    "reason": "file_unreadable",
    "documentId": "01a1728b-cc26-7ba9-ad3c-dcf5e6d8e581"
  }
}

Limits and credits

Files

  • PDF, DOCX, PNG, JPEG and TIFF (also multi-page). The type is taken from the file's content, not its name.
  • Up to 10 MB and 30 pages per document.

Credits

  • Each processed page costs 1 credit. Choosing the category automatically costs nothing extra.
  • Classifying only (classify-only) costs 1 credit per document. Extracting such a document later costs its pages less that credit, so the total is still 1 credit per page.
  • A failed run costs nothing for its pages. Reprocessing costs credits again. Receiving email is free.
  • When the credits of a period are used up, uploads are refused with credit.insufficient_credits until the next period or an upgrade. A document's credits are reserved once its pages are counted; if they no longer fit, for example after many parallel uploads, the document fails with insufficient_credits and nothing is charged.

Request rate

Each API key may make a number of requests per minute, depending on the plan. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix time). Over the limit you get 429 with Retry-After.

By plan

PlanRequests / minuteCredits / monthAPI keysWebhooks / project
Free102011
Starter3050022
Growth602,00035
Pro1206,0001010
Business30020,000unlimited25

Also: POST /extract and POST /classify wait at most 285 seconds and allow 5 open requests per key between them.

Response429
{
  "error": {
    "code": "apikey.rate_limited",
    "message": "Too many requests for this API key: the limit is 60 per minute. Retry in 18 s.",
    "limit": 60,
    "retryAfterSeconds": 18
  }
}

Data retention

What Parsevix keeps of an API upload is a project setting: API uploads, under Project settings. It is Delete after processing by default; Keep like dashboard uploads keeps them.

  • Delete after processing: the file is deleted when processing ends and the result is not stored. The API response, webhook or callback is the only copy. Such documents are not listed and cannot be reprocessed or downloaded; retained is false.
  • Keep like dashboard uploads: files and results are stored like dashboard uploads, until you delete them.

Dashboard and email uploads are always stored. Personal data is masked before any text reaches the AI model; see Security.