Skip to content

API reference

The Vink API

Let your own program or automation platform talk to Vink. Everything on this page comes from the same OpenAPI document the API serves.

Overview

Every endpoint lives under one base URL. The version is in the path: /v1.

https://vink.page/v1

Requests and answers are JSON, and every key is snake_case, the same as in the webhook Payload. Ids are strings.

Within /v1 we only add: new endpoints, new optional parameters and new keys in answers. Ignore keys you don't know. Anything that would break your code gets a new version.

Download the OpenAPI 3.1 document to generate a client or import it into a tool.

Authentication

Send an API Key with every request. An Admin makes one under Settings → API Keys in the app, gives it a name and sees it once. A key belongs to one Organisation and only reaches that Organisation's data.

Authorization: Bearer vink_live_…

Treat a key like a password: keep it on your server, never in a browser or app. A missing, unknown or revoked key gets 401. Revoking one key leaves your other keys working.

An API Key is for a program without a user: it sends Submissions in, reads them and their Deliveries, manages Subscriptions and sends a failed Delivery again, but it can't change a Submission. An AI agent uses an Agent Connection instead, see For AI agents. Each endpoint below says which access it takes.

For AI agents

Let your own AI agent work with Vink: send a paper in, read its values, correct what is unsure and, where you allow it, approve it. The agent acts as you, and everything it changes is recorded as yours via agent.

Connect an agent

Add Vink as a remote MCP server in your agent. It works with any MCP client that supports remote servers with OAuth, such as Claude, ChatGPT or Cursor.

https://vink.page/mcp

The agent opens Vink, you sign in, pick the Organisation and approve. That is an Agent Connection: it has your rights in that Organisation, and you can revoke it under Settings → Agent Connections. Without MCP, an agent can call the same endpoints with its OAuth access token as Authorization: Bearer $VINK_AGENT_TOKEN.

The loop

  1. send_submission: send a PDF, a photo, an email, a spreadsheet or a Word file in, for one Form or for Vink to pick the Form.
  2. get_submission with wait (up to 25 seconds): the call answers as soon as Vink has read it. Still processing? Call again.
  3. Read fields: every value has its confidence and needs_review.
  4. correct_fields: fix the values that need review. A corrected value no longer needs review.
  5. approve: only when the Form allows Agent Approval and nothing still needs review. Otherwise a person approves it in Vink.

The agent also has list_forms and get_form_schema to read your Forms, change_form and reject before Approval, and, for an Admin, propose_form and get_form_proposal to have Vink propose the Fields of a new Form, and list_integrations, get_deliveries and retry_delivery to check that an approved Submission reached your systems. get_usage shows the Credits left.

Agent Approval

Approval sends the Payload to your systems (bookkeeping, sheets) and is hard to undo. So an agent may approve only on a Form where an Admin switched on Agent Approval, and only when nothing on the Submission needs review. It is off by default. When it is off, approve answers agent_approval_off; with values that still need review, needs_review.

Example: wait for the values

The same call without MCP. It holds until Vink has read the Submission, at most 25 seconds.

Request
curl "https://vink.page/v1/submissions/j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb?wait=25" \
  -H "Authorization: Bearer $VINK_AGENT_TOKEN"
Example answer
{
  "id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
  "form_id": "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra",
  "state": "needs_review",
  "filename": "factuur-1042.pdf",
  "uploaded_at": "2026-10-06T09:00:00.000Z",
  "data_deleted_at": null,
  "fields": {
    "supplier": {
      "value": "Hoekstra Installatie",
      "confidence": 0.97,
      "needs_review": false,
      "pages": [
        1
      ]
    },
    "invoice_number": {
      "value": "F2026-0412",
      "confidence": 0.95,
      "needs_review": false,
      "pages": [
        1
      ]
    },
    "total_amount": {
      "value": 151.25,
      "confidence": 0.62,
      "needs_review": true,
      "pages": [
        1
      ]
    }
  },
  "payload": null
}

payload stays null until Approval: an API Key or an agent gets the Payload only after Approval, the same one your Integrations get.

Errors

A failed request gets a 4xx or 5xx status and the same JSON body. Branch on code; message is for people and may change.

{
  "error": {
    "code": "invalid_api_key",
    "message": "This API Key doesn't exist or was revoked."
  }
}
StatusCodeMeaning
401missing_api_keyNo Authorization: Bearer <key> header.
401invalid_api_keyThe key is unknown or was revoked.
401invalid_tokenThe agent's OAuth access token is unknown or expired, or its Agent Connection was revoked or ended.
403forbiddenThe endpoint needs the other kind of access: an API Key (Subscriptions, Integrations, Deliveries), or an Agent Connection (changes to a Submission, Form Proposals); Form Proposals also need an Admin's Agent Connection.
404not_foundNo such endpoint, or nothing with that id in your Organisation.
500internal_errorSomething went wrong on our side. Try again later.
400missing_fileNo file part, or an empty body.
400invalid_requestAn email's JSON is invalid (not JSON, a wrong type, or an attachment that isn't base64), or a reference is over 100 characters or has a control character.
402out_of_itemsNot enough Items left for this input.
409form_archivedThe Form is archived; an Admin can restore it in Vink.
413file_too_largeThe file is larger than 10 MB.
415unsupported_file_typeThe file is none of the types Vink reads, or can't be opened.
415not_a_pdfThe file is sent as a PDF and isn't a PDF Vink can read.
415media_type_mismatchThe Content-Type names another file type than the file is.
415unsupported_media_typeThe body is none of multipart/form-data, application/json, a file type (application/pdf, image/jpeg, image/png, image/heic, message/rfc822, application/vnd.ms-outlook, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, text/csv) or application/octet-stream.
422too_many_pagesThe PDF has more than 20 pages.
422too_many_attachmentsThe email has more than 10 attachments.
422empty_emailThe email has no text and no attachments.
422too_many_rowsVink reads up to 5,000 rows per Spreadsheet; this one has more.
400invalid_requestwait on Get a Submission isn't a whole number of seconds.
403agent_approval_offAn agent may approve only on a Form whose Agent Approval an Admin switched on.
409conflictThe Submission's state rules the change out: it is approved, rejected or still being read.
409needs_reviewAn agent may approve only when nothing on the Submission needs review: correct those values first.
400invalid_requestThe body isn't the JSON the endpoint takes.
409too_many_subscriptionsThe Organisation already has 50 Subscriptions.
409form_archivedThe Form is archived; an Admin can restore it in Vink.
422invalid_urlA Subscription's url must be an https URL.
409not_failedOnly a failed Delivery can be sent again.
409integration_removedThe Delivery's Integration was removed or detached; it can't be sent again.
409data_deletedThe Submission's data was deleted; there's nothing left to send.
422invalid_descriptionThe description is empty or longer than 2000 characters.
429too_many_descriptionsThe Organisation described 20 Forms in the last 24 hours.

Forms

The kinds of document your Organisation reads, and their Fields.

List Forms

GET/v1/forms

Access: API Key or Agent Connection

Every Form of the key's Organisation, with the Fields of its current version. Automation platforms use it to show your Fields as dynamic fields.

Responses

StatusDescription
200The Forms.({ data: Form[] })
401The API Key is missing, unknown or revoked.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/forms \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "data": [
    {
      "id": "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra",
      "name": "Invoice",
      "description": "Incoming supplier invoices",
      "version": 3,
      "fields": [
        {
          "key": "supplier",
          "label": "Leverancier",
          "type": "text",
          "required": true
        },
        {
          "key": "invoice_number",
          "label": "Factuurnummer",
          "type": "text",
          "required": true
        },
        {
          "key": "invoice_date",
          "label": "Factuurdatum",
          "type": "date",
          "required": true
        },
        {
          "key": "total_amount",
          "label": "Totaalbedrag",
          "type": "number",
          "required": true
        },
        {
          "key": "currency",
          "label": "Valuta",
          "type": "choice",
          "required": false,
          "options": [
            "EUR",
            "USD"
          ]
        },
        {
          "key": "lines",
          "label": "Regels",
          "type": "list",
          "required": false,
          "fields": [
            {
              "key": "description",
              "label": "Omschrijving",
              "type": "text",
              "required": true
            },
            {
              "key": "quantity",
              "label": "Aantal",
              "type": "number",
              "required": false
            },
            {
              "key": "amount",
              "label": "Bedrag",
              "type": "number",
              "required": true
            }
          ]
        }
      ]
    }
  ]
}

Get a Form

GET/v1/forms/{id}

Access: API Key or Agent Connection

One Form of your Organisation, with the Fields of its current version, as in List Forms, and also its General Instruction and Guidelines: what your Organisation told Vink about reading this kind of document. You can read them here; an Editor changes them in the app.

Parameters

NameTypeDescription
idrequiredstringThe Form's id, from List Forms.

Responses

StatusDescription
200The Form.(FormWithInstructions)
401The API Key is missing, unknown or revoked.(Error)
404No Form with that id in your Organisation.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/forms/{id} \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "id": "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra",
  "name": "Invoice",
  "description": "Incoming supplier invoices",
  "version": 3,
  "fields": [
    {
      "key": "supplier",
      "label": "Leverancier",
      "type": "text",
      "required": true
    },
    {
      "key": "invoice_number",
      "label": "Factuurnummer",
      "type": "text",
      "required": true
    },
    {
      "key": "invoice_date",
      "label": "Factuurdatum",
      "type": "date",
      "required": true
    },
    {
      "key": "total_amount",
      "label": "Totaalbedrag",
      "type": "number",
      "required": true
    },
    {
      "key": "currency",
      "label": "Valuta",
      "type": "choice",
      "required": false,
      "options": [
        "EUR",
        "USD"
      ]
    },
    {
      "key": "lines",
      "label": "Regels",
      "type": "list",
      "required": false,
      "fields": [
        {
          "key": "description",
          "label": "Omschrijving",
          "type": "text",
          "required": true
        },
        {
          "key": "quantity",
          "label": "Aantal",
          "type": "number",
          "required": false
        },
        {
          "key": "amount",
          "label": "Bedrag",
          "type": "number",
          "required": true
        }
      ]
    }
  ],
  "general_instruction": "Our supplier numbers start with LEV-. Leave a number without it empty.",
  "guidelines": [
    {
      "name": "Credit notes",
      "use_when": "The document is a credit note",
      "instruction": "Write the total as a negative amount.",
      "field_keys": [
        "total_amount"
      ]
    }
  ]
}

Submissions

PDFs, photos, emails, Spreadsheets and Word Files Vink reads into a Form's Fields.

Send a Submission in, without choosing the Form

POST/v1/submissions

Access: API Key or Agent Connection

Sends a PDF, a photo (JPG, PNG, HEIC) or an email in, exactly as if it was uploaded in the app: the same checks, the same Items counted once, and it shows in Vink with the API Key's name as its source. Without form_id, Vink reads it and picks the Form from your Organisation's Forms; a Submission that fits none waits under No Form (state: no_form in Get a Submission). With form_id, it is read with that Form, as on Send a Submission in. A PDF is at most 20 pages and 10 MB, an image 10 MB, an email's text 200 KB with at most 10 attachments of 12 MB together. Your Organisation must have enough Items left: a PDF costs its pages, a photo 1, an email its text (1, when it has any) plus each attachment; an email file (.eml) is split as mail to an Intake Address is, into one Submission or one per paper (id is the first), and a text that is only a cover note costs nothing.

Parameters

NameTypeDescription
form_idstringThe Form's id, from List Forms. Left out, Vink picks the Form. It can also be a form_id part of a multipart body or a form_id property of an email's JSON.
filenamestringThe name the Submission shows in Vink. Defaults to the multipart file's name, else document.pdf (.jpg, .png, .heic, .docx, .xlsx, .csv) by what the file is, else an email's subject.
referencestringYour own id for this input, such as an order number or a case id: 1 to 100 characters, no line breaks or other control characters. Vink keeps it on every Submission the input becomes, shows it in review, and sends it as submission.reference in each Delivery and in Get a Submission. Left out or empty: no Reference. A reference part of a multipart body, or a reference property of an email's JSON, comes before this one.

Request body

The file or the email, with a request body of at most 10 MB in total. A file is a PDF, a JPG, PNG or HEIC image, an email file (message/rfc822 .eml, or Outlook's application/vnd.ms-outlook .msg), a Word File (.docx) or a Spreadsheet of up to 5,000 rows (.xlsx, or a text/csv .csv with ;, , or tab between the fields): send it as multipart/form-data with the file in a part named file (an optional filename part names it, an optional form_id part picks the Form, an optional reference part is your own id for it), or as the body itself. Vink decides what the file is from its first bytes (a CSV, which has none, by its Content-Type or its name). A Content-Type that names one of these types and contradicts the bytes is refused (media_type_mismatch); application/octet-stream or a part without a type leaves it to the bytes. An email can also be sent as application/json (see EmailSubmission): its text and up to 10 attachments of the file types above, base64-encoded.

Responses

StatusDescription
201Vink accepted the file or email and is reading it.(SentSubmission)
400The request has no file in it (missing_file), or an email body or a reference isn't valid (invalid_request).(Error)
401The API Key is missing, unknown or revoked.(Error)
402Your Organisation has fewer Items left than the input needs.(Error)
404A form_id was given, and no Form in your Organisation has it.(Error)
409The Form is archived. An Admin can restore it in Vink.(Error)
413The request body, an image, a Word File, a Spreadsheet or an email's text or attachments are over their limit.(Error)
415Vink can't read the file. unsupported_file_type: it is none of the file types above (or an email, Word File or Spreadsheet that can't be opened). not_a_pdf: it is sent as a PDF and isn't a PDF Vink can read. media_type_mismatch: the Content-Type names another file type than the bytes. unsupported_media_type: the body is none of the content types above.(Error)
422The PDF has more than 20 pages (too_many_pages), an email has more than 10 attachments (too_many_attachments) or no text and no attachments (empty_email), or a Spreadsheet has more than 5,000 rows (too_many_rows).(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/submissions \
  -H "Authorization: Bearer $VINK_API_KEY" \
  -F "[email protected]"
Example answer
{
  "id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
  "ids": [
    "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb"
  ],
  "state": "processing"
}

Send a Submission in

POST/v1/forms/{form_id}/submissions

Access: API Key or Agent Connection

Sends a PDF, a photo (JPG, PNG, HEIC) or an email to a Form. It becomes a Submission exactly as if it was uploaded in the app: the same checks, the same Items counted once, and it shows in Vink with the API Key's name as its source. Vink then reads it; the Submission needs review or is approved later. A PDF is at most 20 pages and 10 MB, an image 10 MB, an email's text 200 KB with at most 10 attachments of 12 MB together. Your Organisation must have enough Items left: a PDF costs its pages, a photo 1, an email its text (1, when it has any) plus each attachment; an email file (.eml) is split as mail to an Intake Address is, into one Submission or one per paper (id is the first), and a text that is only a cover note costs nothing. To let Vink pick the Form, use Send a Submission in, without choosing the Form.

Parameters

NameTypeDescription
form_idrequiredstringThe Form's id, from List Forms.
filenamestringThe name the Submission shows in Vink. Defaults to the multipart file's name, else document.pdf (.jpg, .png, .heic, .docx, .xlsx, .csv) by what the file is, else an email's subject.
referencestringYour own id for this input, such as an order number or a case id: 1 to 100 characters, no line breaks or other control characters. Vink keeps it on every Submission the input becomes, shows it in review, and sends it as submission.reference in each Delivery and in Get a Submission. Left out or empty: no Reference. A reference part of a multipart body, or a reference property of an email's JSON, comes before this one.

Request body

The file or the email, with a request body of at most 10 MB in total. A file is a PDF, a JPG, PNG or HEIC image, an email file (message/rfc822 .eml, or Outlook's application/vnd.ms-outlook .msg), a Word File (.docx) or a Spreadsheet of up to 5,000 rows (.xlsx, or a text/csv .csv with ;, , or tab between the fields): send it as multipart/form-data with the file in a part named file (an optional filename part names it, an optional reference part is your own id for it), or as the body itself. Vink decides what the file is from its first bytes (a CSV, which has none, by its Content-Type or its name). A Content-Type that names one of these types and contradicts the bytes is refused (media_type_mismatch); application/octet-stream or a part without a type leaves it to the bytes. An email can also be sent as application/json (see EmailSubmission): its text and up to 10 attachments of the file types above, base64-encoded.

Responses

StatusDescription
201Vink accepted the file or email and is reading it.(SentSubmission)
400The request has no file in it (missing_file), or an email body or a reference isn't valid (invalid_request).(Error)
401The API Key is missing, unknown or revoked.(Error)
402Your Organisation has fewer Items left than the input needs.(Error)
404No Form with this id in your Organisation.(Error)
409The Form is archived. An Admin can restore it in Vink.(Error)
413The request body, an image, a Word File, a Spreadsheet or an email's text or attachments are over their limit.(Error)
415Vink can't read the file. unsupported_file_type: it is none of the file types above (or an email, Word File or Spreadsheet that can't be opened). not_a_pdf: it is sent as a PDF and isn't a PDF Vink can read. media_type_mismatch: the Content-Type names another file type than the bytes. unsupported_media_type: the body is none of the content types above.(Error)
422The PDF has more than 20 pages (too_many_pages), an email has more than 10 attachments (too_many_attachments) or no text and no attachments (empty_email), or a Spreadsheet has more than 5,000 rows (too_many_rows).(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/forms/{form_id}/submissions \
  -H "Authorization: Bearer $VINK_API_KEY" \
  -F "[email protected]"
Example answer
{
  "id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
  "ids": [
    "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb"
  ],
  "state": "processing"
}

Get a Submission

GET/v1/submissions/{id}

Access: API Key or Agent Connection

The Submission's state, its Field Values once Vink has read them, and, once it is approved, its Payload: the same envelope every Webhook gets. fields is there before Approval, with each value's Confidence and whether it is Needs Review, so you can work with the values at once. payload is null until Approval. After its data is deleted (Retention, or an Admin's delete now) fields and payload are null and data_deleted_at says when.

Parameters

NameTypeDescription
idrequiredstringThe Submission's id, from Send in a Submission or an envelope's submission.id.
waitintegerSeconds to hold the request while the Submission is processing. It answers as soon as the state leaves processing, or when the seconds are up, with the Submission as it is then (that can still be processing). At most 25: a larger value waits 25. Left out or 0, it answers at once; polling without wait works as well.

Responses

StatusDescription
200The Submission.(Submission)
400wait isn't a whole number of seconds.(Error)
401The API Key is missing, unknown or revoked.(Error)
404No Submission with that id in your Organisation.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/submissions/{id} \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
  "form_id": "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra",
  "state": "approved",
  "filename": "factuur-1042.pdf",
  "reference": "PO-2026-1042",
  "uploaded_at": "2026-10-06T09:00:00.000Z",
  "data_deleted_at": null,
  "fields": {
    "supplier": {
      "value": "Hoekstra Installatie",
      "confidence": 0.97,
      "needs_review": false,
      "pages": [
        1
      ]
    },
    "invoice_number": {
      "value": "F2026-0412",
      "confidence": 0.95,
      "needs_review": false,
      "pages": [
        1
      ]
    },
    "invoice_date": {
      "value": "2026-10-02",
      "confidence": 0.93,
      "needs_review": false,
      "pages": [
        1
      ]
    },
    "total_amount": {
      "value": 151.25,
      "confidence": 0.91,
      "needs_review": false,
      "pages": [
        1
      ]
    },
    "currency": {
      "value": "EUR",
      "confidence": 0.98,
      "needs_review": false,
      "pages": [
        1
      ]
    },
    "lines": {
      "needs_review": false,
      "entries": [
        {
          "description": {
            "value": "Kopieerpapier A4",
            "confidence": 0.96,
            "needs_review": false,
            "pages": [
              1
            ]
          },
          "quantity": {
            "value": 5,
            "confidence": 0.94,
            "needs_review": false,
            "pages": [
              1
            ]
          },
          "amount": {
            "value": 125,
            "confidence": 0.92,
            "needs_review": false,
            "pages": [
              1
            ]
          }
        }
      ]
    }
  },
  "payload": {
    "event": "submission.approved",
    "delivery_id": "sub_j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
    "test": false,
    "submission": {
      "id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
      "filename": "factuur-1042.pdf",
      "reference": "PO-2026-1042",
      "uploaded_at": "2026-10-06T09:00:00.000Z",
      "file_url": "https://files.vink.page/factuur-1042.pdf?X-Amz-Expires=86400&X-Amz-Signature=…"
    },
    "form": {
      "id": "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra",
      "version": 3
    },
    "approval": {
      "mode": "manual",
      "by": "user_2x9KqL",
      "at": "2026-10-06T09:12:00.000Z"
    },
    "data": {
      "supplier": "Hoekstra Installatie",
      "invoice_number": "F2026-0412",
      "invoice_date": "2026-10-02",
      "total_amount": 151.25,
      "currency": "EUR",
      "lines": [
        {
          "description": "Kopieerpapier A4",
          "quantity": 5,
          "amount": 125
        }
      ]
    }
  }
}

Correct Field Values

PATCH/v1/submissions/{id}/fields

Access: Agent Connection only

Corrects one or more Field Values of a Submission in needs_review, all or none. Name a value by its path in fields of Get a Submission: a Field's key (invoice_number), or for a List Field the entry's place in entries, from 0, and the sub-Field's key (lines[0].quantity). A value must fit its Field's type: a number for a number Field, yyyy-mm-dd for a date, one of the options for a choice. A corrected value no longer needs review, and the Submission is never sent by Auto-Send afterwards. Needs an Agent Connection: an agent's OAuth access token, sent as Authorization: Bearer <token>. An API Key gets 403 forbidden, since a key has no user to answer for the change. The change is the connection's user's, recorded as theirs via agent, with the same rules as in Vink.

Parameters

NameTypeDescription
idrequiredstringThe Submission's id.

Request body

Responses

StatusDescription
200The Submission after the change, as Get a Submission answers.(Submission)
400The body isn't values, a path names no value, or a value doesn't fit its Field.(Error)
401The API Key is missing, unknown or revoked.(Error)
403Sent with an API Key.(Error)
404No Submission with that id in your Organisation.(Error)
409The Submission's state rules the change out.(Error)
500Something went wrong on our side.(Error)
Request
curl -X PATCH https://vink.page/v1/submissions/{id}/fields \
  -H "Authorization: Bearer $VINK_AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"values":{"invoice_number":"F2026-0412","lines[0].quantity":5}}'

Change a Submission's Form

POST/v1/submissions/{id}/form

Access: Agent Connection only

Moves a Submission to another Form before Approval, also out of no_form or failed. Its values and corrections for the old Form are dropped and Vink reads it again for the new one, so it is processing until that ends. Its Items were counted when it came in; a move counts none. Needs an Agent Connection: an agent's OAuth access token, sent as Authorization: Bearer <token>. An API Key gets 403 forbidden, since a key has no user to answer for the change. The change is the connection's user's, recorded as theirs via agent, with the same rules as in Vink.

Parameters

NameTypeDescription
idrequiredstringThe Submission's id.

Request body

Responses

StatusDescription
200The Submission after the change, as Get a Submission answers.(Submission)
400The body has no form_id.(Error)
401The API Key is missing, unknown or revoked.(Error)
403Sent with an API Key.(Error)
404No Submission, or no Form, with that id in your Organisation.(Error)
409The Submission's state rules the change out (conflict), or the Form is archived (form_archived).(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/submissions/{id}/form \
  -H "Authorization: Bearer $VINK_AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"form_id":"k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra"}'

Reject a Submission

POST/v1/submissions/{id}/reject

Access: Agent Connection only

Rules a Submission in needs_review, failed or no_form unusable: it becomes rejected, with the reason, if any. A user can reopen it in Vink. Needs an Agent Connection: an agent's OAuth access token, sent as Authorization: Bearer <token>. An API Key gets 403 forbidden, since a key has no user to answer for the change. The change is the connection's user's, recorded as theirs via agent, with the same rules as in Vink.

Parameters

NameTypeDescription
idrequiredstringThe Submission's id.

Request body

Responses

StatusDescription
200The Submission after the change, as Get a Submission answers.(Submission)
400The body isn't JSON, or reason isn't a string.(Error)
401The API Key is missing, unknown or revoked.(Error)
403Sent with an API Key.(Error)
404No Submission with that id in your Organisation.(Error)
409The Submission's state rules the change out.(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/submissions/{id}/reject \
  -H "Authorization: Bearer $VINK_AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Duplicate of F2026-0411"}'

Approve a Submission

POST/v1/submissions/{id}/approve

Access: Agent Connection only

Approves a Submission in needs_review, which sends its Payload to the Form's Integrations. An agent may approve only when an Admin has switched on Agent Approval for the Form and nothing on the Submission needs review: correct the values that do first. The Approval is the connection's user's, with approval.mode agent in the Payload. Needs an Agent Connection: an agent's OAuth access token, sent as Authorization: Bearer <token>. An API Key gets 403 forbidden, since a key has no user to answer for the change. The change is the connection's user's, recorded as theirs via agent, with the same rules as in Vink.

Parameters

NameTypeDescription
idrequiredstringThe Submission's id.

Responses

StatusDescription
200The Submission after the change, as Get a Submission answers.(Submission)
401The API Key is missing, unknown or revoked.(Error)
403Sent with an API Key, or Agent Approval is off for the Form.(Error)
404No Submission with that id in your Organisation.(Error)
409Values still need review (needs_review), or the Submission's state rules the Approval out (conflict).(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/submissions/{id}/approve \
  -H "Authorization: Bearer $VINK_AGENT_TOKEN"

Subscriptions

For automation platforms (Zapier, Make, Power Automate): hear about a Form's Approvals. A Subscription is a Webhook in Vink, so Admins see it under Integrations.

Subscribe to Approvals

POST/v1/subscriptions

Access: API Key only

From now on, every Approval of a Submission of this Form is POSTed to url as an envelope, the same one every Webhook gets: with retries, a log in Vink and the X-Vink-Signature header. Vink makes a Webhook for it, named after the API Key and attached to the Form, so the Form's Field keys are locked while the Subscription is active. It ends when you unsubscribe, when the API Key is revoked or when an Admin deletes that Webhook.

Request body

JSON with form_id, the Form to hear about (from List Forms), and url, the https URL that receives the envelopes.

Responses

StatusDescription
201The Subscription.(Subscription)
400The body isn't JSON with form_id and url.(Error)
401The API Key is missing, unknown or revoked.(Error)
404No Form with that id in your Organisation.(Error)
409The Organisation already has 50 Subscriptions (too_many_subscriptions), or the Form is archived (form_archived).(Error)
422url isn't an https URL.(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/subscriptions \
  -H "Authorization: Bearer $VINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"form_id":"k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra","url":"https://hooks.zapier.com/hooks/standard/123456/abcdef/"}'
Example answer
{
  "id": "j57a2x9kq4m1c8v3n6e5w4t8hs7bm2rb",
  "form_id": "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra",
  "url": "https://hooks.zapier.com/hooks/standard/123456/abcdef/",
  "created_at": "2026-10-06T09:00:00.000Z"
}

Unsubscribe

DELETE/v1/subscriptions/{id}

Access: API Key only

Ends the Subscription and removes its Webhook. Any API Key of the Organisation can end it. Approvals that are still being sent to it are given up. Idempotent: a Subscription that has ended already (an Admin deleted its Webhook, or its url answered 410), or an id Vink doesn't know, gets the same answer and nothing changes.

Parameters

NameTypeDescription
idrequiredstringThe Subscription's id.

Responses

StatusDescription
200The Subscription ended, or had ended already.(DeletedSubscription)
401The API Key is missing, unknown or revoked.(Error)
500Something went wrong on our side.(Error)
Request
curl -X DELETE https://vink.page/v1/subscriptions/{id} \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "id": "j57a2x9kq4m1c8v3n6e5w4t8hs7bm2rb",
  "deleted": true
}

Sample envelope

GET/v1/forms/{form_id}/sample

Access: API Key or Agent Connection

An example of the envelope a Subscription receives for this Form, with example values for the Fields of its current version: what a test-send sends. Lists are arrays with one entry. Automation platforms use it to show the fields before the first real Approval.

Parameters

NameTypeDescription
form_idrequiredstringThe Form's id, from List Forms.

Responses

StatusDescription
200The example envelope, with "test": true.(Envelope)
401The API Key is missing, unknown or revoked.(Error)
404No Form with that id in your Organisation.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/forms/{form_id}/sample \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "event": "submission.approved",
  "delivery_id": "test_3f2a7c1e-9b4d-4e8a-a1f0-6c5d2b7e9a10",
  "test": true,
  "submission": {
    "id": "test",
    "filename": "example.pdf",
    "reference": null,
    "uploaded_at": "2026-10-06T09:00:00.000Z",
    "file_url": null
  },
  "form": {
    "id": "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra",
    "version": 3
  },
  "approval": {
    "mode": "manual",
    "by": null,
    "at": "2026-10-06T09:00:00.000Z"
  },
  "data": {
    "supplier": "Example Leverancier",
    "invoice_number": "Example Factuurnummer",
    "invoice_date": "2026-01-31",
    "total_amount": 123.45,
    "currency": "EUR",
    "lines": [
      {
        "description": "Example Omschrijving",
        "quantity": 123.45,
        "amount": 123.45
      }
    ]
  }
}

Envelope schema

GET/v1/forms/{form_id}/schema

Access: API Key or Agent Connection

The JSON Schema of the envelope a Subscription receives for this Form, with one property per Field of its current version under data. Power Automate uses it to show your Fields as dynamic content.

Parameters

NameTypeDescription
form_idrequiredstringThe Form's id, from List Forms.

Responses

StatusDescription
200The schema.(EnvelopeSchema)
401The API Key is missing, unknown or revoked.(Error)
404No Form with that id in your Organisation.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/forms/{form_id}/schema \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "schema": {
    "type": "object",
    "properties": {
      "event": {
        "type": "string",
        "x-ms-summary": "Event"
      },
      "data": {
        "type": "object",
        "x-ms-summary": "Data",
        "properties": {
          "supplier": {
            "type": "string",
            "title": "Leverancier",
            "x-ms-summary": "Leverancier",
            "x-nullable": true
          }
        }
      }
    }
  }
}

Integrations

Where Vink sends a Form's Approvals: a Webhook, a Google Sheet or an Excel workbook. Admins make and change them in Vink; the API only lists them, so you can read their Deliveries.

List Integrations

GET/v1/integrations

Access: API Key or Agent Connection

Every Integration of the caller's Organisation, with the Forms it is attached to. Nothing of its configuration is in the answer: no URL, headers, secrets or sheet link. A Subscription is a Webhook too, so it is listed with its subscription_id.

Responses

StatusDescription
200The Integrations.({ data: Integration[] })
401The API Key is missing, unknown or revoked.(Error)
403An Agent Connection whose user is not an Admin.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/integrations \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "data": [
    {
      "id": "m27d4x8kq2n1c9v3b6e5w4t8hs7bm2rc",
      "name": "Bookkeeping",
      "kind": "webhook",
      "form_ids": [
        "k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra"
      ],
      "subscription_id": null,
      "needs_reconnect": false
    }
  ]
}

Deliveries

One Delivery sends one approved Submission's Payload to one Integration, with retries for about 8 hours. Read the Deliveries of a Submission or of an Integration, and send a failed one again, as an Admin can with Send again in Vink.

List an Integration's Deliveries

GET/v1/integrations/{id}/deliveries

Access: API Key or Agent Connection

The Integration's Deliveries, newest first, a page at a time. Pass next_cursor as cursor to get the next page; it is null on the last one. With state, a page can hold fewer than limit Deliveries, even none: keep going while next_cursor isn't null.

Parameters

NameTypeDescription
idrequiredstringThe Integration's id, from List Integrations.
limitintegerHow many Deliveries a page holds at most. 50 when left out.
cursorstringThe next_cursor of the page before. Left out, you get the first page.
state"pending" | "retrying" | "delivered" | "failed"Only Deliveries in this state, e.g. failed to find what to send again.

Responses

StatusDescription
200A page of Deliveries.(DeliveryList)
400limit, cursor or state isn't one Vink takes.(Error)
401The API Key is missing, unknown or revoked.(Error)
403An Agent Connection whose user is not an Admin.(Error)
404No Integration with that id in your Organisation.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/integrations/{id}/deliveries \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "data": [
    {
      "id": "n37e5x7kq1m2c8v3b6e5w4t8hs7bm2rd",
      "delivery_id": "dlv_5c1e2a7f-3b9d-4f8a-b1e0-7d6c2a9e8b41",
      "submission_id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
      "integration_id": "m27d4x8kq2n1c9v3b6e5w4t8hs7bm2rc",
      "integration_name": "Bookkeeping",
      "state": "failed",
      "failure_reason": "The receiver refused it (422)",
      "next_attempt_at": null,
      "can_retry": true,
      "created_at": "2026-10-06T09:00:00.000Z",
      "attempts": [
        {
          "at": "2026-10-06T09:00:01.000Z",
          "status": 422,
          "error": null,
          "body": "{\"error\":\"unknown supplier\"}"
        }
      ]
    }
  ],
  "next_cursor": null
}

List a Submission's Deliveries

GET/v1/submissions/{id}/deliveries

Access: API Key or Agent Connection

One Delivery per Integration the Submission's Form was attached to at Approval, oldest first. Empty before Approval, and when nothing was attached.

Parameters

NameTypeDescription
idrequiredstringThe Submission's id, from Send a Submission in.

Responses

StatusDescription
200The Deliveries.({ data: Delivery[] })
401The API Key is missing, unknown or revoked.(Error)
403An Agent Connection whose user is not an Admin.(Error)
404No Submission with that id in your Organisation.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/submissions/{id}/deliveries \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "data": [
    {
      "id": "n37e5x7kq1m2c8v3b6e5w4t8hs7bm2rd",
      "delivery_id": "dlv_5c1e2a7f-3b9d-4f8a-b1e0-7d6c2a9e8b41",
      "submission_id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
      "integration_id": "m27d4x8kq2n1c9v3b6e5w4t8hs7bm2rc",
      "integration_name": "Bookkeeping",
      "state": "failed",
      "failure_reason": "The receiver refused it (422)",
      "next_attempt_at": null,
      "can_retry": true,
      "created_at": "2026-10-06T09:00:00.000Z",
      "attempts": [
        {
          "at": "2026-10-06T09:00:01.000Z",
          "status": 422,
          "error": null,
          "body": "{\"error\":\"unknown supplier\"}"
        }
      ]
    }
  ]
}

Send a Delivery again

POST/v1/deliveries/{id}/retry

Access: API Key or Agent Connection

Sends a failed Delivery again, with the same delivery_id and the Integration's configuration as it is now: a new series of up to 6 attempts, the same as Send again in Vink. It doesn't change the Submission. Only a Delivery with can_retry: true can be sent again; read it again later to see how it went.

Parameters

NameTypeDescription
idrequiredstringThe Delivery's id, from a list of Deliveries.

Responses

StatusDescription
202The Delivery, now pending: it is sent in a moment.(Delivery)
401The API Key is missing, unknown or revoked.(Error)
403An Agent Connection whose user is not an Admin.(Error)
404No Delivery with that id in your Organisation.(Error)
409It can't be sent again: it isn't failed (not_failed), its Integration was removed (integration_removed), or its Submission's data was deleted (data_deleted).(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/deliveries/{id}/retry \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "id": "n37e5x7kq1m2c8v3b6e5w4t8hs7bm2rd",
  "delivery_id": "dlv_5c1e2a7f-3b9d-4f8a-b1e0-7d6c2a9e8b41",
  "submission_id": "j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb",
  "integration_id": "m27d4x8kq2n1c9v3b6e5w4t8hs7bm2rc",
  "integration_name": "Bookkeeping",
  "state": "pending",
  "failure_reason": null,
  "next_attempt_at": null,
  "can_retry": false,
  "created_at": "2026-10-06T09:00:00.000Z",
  "attempts": [
    {
      "at": "2026-10-06T09:00:01.000Z",
      "status": 422,
      "error": null,
      "body": "{\"error\":\"unknown supplier\"}"
    }
  ]
}

Form Proposals

Fields Vink proposes for a new Form, from a sample or a description. For agents only: an Admin saves a proposal as a Form in the app.

Propose a Form

POST/v1/form-proposals

Access: Agent Connection only

Vink proposes Fields for a new Form from one sample (a PDF, a photo or an email, sent the same ways as Send a Submission in) or from a description in words, exactly as an Admin does in the app. Only through an Agent Connection whose user is an Admin; the proposal is that user's, made via agent. A sample costs its Items once, as a Submission does; a description costs no Items, and an Organisation can describe at most 20 Forms in 24 hours. Poll Get a Form Proposal until it is ready. No endpoint saves a proposal as a Form: an Admin does that in the app. An unsaved proposal is deleted after 7 days.

Request body

A sample file, with the same bodies and limits as Send a Submission in (form_id is not used), or application/json: either { "description": "…" } (at most 2000 characters: what the document is and which data you need) or an email (EmailSubmission).

Responses

StatusDescription
201Vink is reading the sample or the description and proposing Fields.(CreatedFormProposal)
400The request has no file in it (missing_file), or the JSON isn't valid (invalid_request).(Error)
401The API Key is missing, unknown or revoked.(Error)
402Your Organisation has fewer Items left than the sample needs.(Error)
403Form Proposals are made by a user who is an Admin: an API Key, or an agent whose user is a Member, can't make or read them.(Error)
413The request body, an image or an email's text or attachments are over their limit.(Error)
415Vink can't read the sample: the same codes as Send a Submission in.(Error)
422The description is empty or too long (invalid_description), or the sample is refused as on Send a Submission in (too_many_pages, too_many_attachments, empty_email, too_many_rows).(Error)
429Your Organisation described 20 Forms in the last 24 hours.(Error)
500Something went wrong on our side.(Error)
Request
curl -X POST https://vink.page/v1/form-proposals \
  -H "Authorization: Bearer $VINK_AGENT_TOKEN" \
  -F "[email protected]"
Example answer
{
  "id": "m81d4f2ty6p0c3x9b5a7k2w4hs7bm2rc",
  "state": "processing"
}

Get a Form Proposal

GET/v1/form-proposals/{id}

Access: Agent Connection only

The proposal's state and, once it is ready, the proposed Fields in the shape of List Forms. Only through an Agent Connection whose user is an Admin.

Parameters

NameTypeDescription
idrequiredstringThe proposal's id, from Propose a Form.

Responses

StatusDescription
200The Form Proposal.(FormProposal)
401The API Key is missing, unknown or revoked.(Error)
403Form Proposals are made by a user who is an Admin: an API Key, or an agent whose user is a Member, can't make or read them.(Error)
404No Form Proposal with that id in your Organisation. It may be saved, discarded, or deleted after 7 days.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/form-proposals/{id} \
  -H "Authorization: Bearer $VINK_AGENT_TOKEN"
Example answer
{
  "id": "m81d4f2ty6p0c3x9b5a7k2w4hs7bm2rc",
  "state": "ready",
  "source": "sample",
  "filename": "factuur-1042.pdf",
  "description": null,
  "failure": null,
  "created_at": "2026-10-12T09:00:00.000Z",
  "fields": [
    {
      "key": "invoice_number",
      "label": "Factuurnummer",
      "type": "text",
      "required": false,
      "recommended": true
    },
    {
      "key": "total_amount",
      "label": "Totaalbedrag",
      "type": "number",
      "required": false,
      "recommended": true
    },
    {
      "key": "supplier_iban",
      "label": "IBAN",
      "type": "text",
      "required": false,
      "recommended": false
    }
  ]
}

Usage

The Credits your Organisation has left this period. One PDF page, email, photo, Spreadsheet or Word File costs 10 Credits.

Get usage

GET/v1/usage

Access: API Key or Agent Connection

The Organisation's Plan, the Credits left and used this period, and when they reset.

Responses

StatusDescription
200The usage.(Usage)
401The API Key is missing, unknown or revoked.(Error)
500Something went wrong on our side.(Error)
Request
curl https://vink.page/v1/usage \
  -H "Authorization: Bearer $VINK_API_KEY"
Example answer
{
  "plan": "team",
  "unlimited": false,
  "credits_left": 4210,
  "credits_used": 1790,
  "resets_at": "2026-11-12T00:00:00.000Z"
}

Objects

The objects the endpoints return.

Error

NameTypeDescription
errorrequired{ code: string, message: string }

Form

NameTypeDescription
idrequiredstringUse it in the Form's other endpoints.
namerequiredstring
descriptionrequiredstring | null
versionrequiredintegerGoes up by one every time the Form is saved.
fieldsrequiredField[]

FormWithInstructions

NameTypeDescription
idrequiredstringUse it in the Form's other endpoints.
namerequiredstring
descriptionrequiredstring | null
versionrequiredintegerGoes up by one every time the Form is saved.
fieldsrequiredField[]
general_instructionrequiredstringVink follows it on every Submission of this Form, under its own fixed rules. Empty when there is none.
guidelinesrequiredGuideline[]Instructions for one situation each, at most 20.

Guideline

NameTypeDescription
namerequiredstringUnique within the Form.
use_whenrequiredstringWhen it applies, in words: Vink uses the Guideline on a Submission only when this fits the document. Empty: always.
instructionrequiredstring
field_keysrequiredstring[]The keys of the Fields it is about; a List Field's key covers its sub-Fields. Empty: all Fields.

Field

NameTypeDescription
keyrequiredstringThe Field's name in the Payload, snake_case.
labelrequiredstringWhat users see in Vink.
typerequired"text" | "number" | "date" | "boolean" | "choice" | "list"choice has options; list has fields, the sub-Fields of each entry.
requiredrequiredboolean
optionsstring[]Only on choice: the values the Payload can hold.
fieldsSubField[]Only on list: the sub-Fields of each entry.

SubField

NameTypeDescription
keyrequiredstringThe Field's name in the Payload, snake_case.
labelrequiredstringWhat users see in Vink.
typerequired"text" | "number" | "date" | "boolean" | "choice"choice has options.
requiredrequiredboolean
optionsstring[]Only on choice: the values the Payload can hold.

SentSubmission

NameTypeDescription
idrequiredstringThe Submission's id: the first one, when there are more.
idsrequiredstring[]Every Submission the input became. More than one only for an email file that Vink split, as mail to an Intake Address is.
staterequired"processing"Always processing here: Vink is reading the file or email.

EmailSubmission

An email as JSON. At least one of body and attachments is needed. Vink reads it as one Submission: its text, then its attachments.

NameTypeDescription
subjectstringThe subject. It names the Submission in Vink.
fromstringThe sender, for example Name <[email protected]>.
datestringWhen the email was sent.
bodystringThe email's text, at most 200 KB.
attachments{ filename: string, content_base64: string }[]PDF, JPG, PNG or HEIC files, at most 10 and 12 MB together before base64. Any other type is refused.
form_idstring | nullThe Form's id. Left out or null, Vink picks the Form. Not used on the Form's own path.
filenamestringThe name the Submission shows in Vink, instead of the subject.
referencestring | nullYour own id for this input, such as an order number or a case id: 1 to 100 characters, no line breaks or other control characters. Vink keeps it on every Submission the input becomes, shows it in review, and sends it as submission.reference in each Delivery and in Get a Submission. Left out or empty: no Reference.

Submission

NameTypeDescription
idrequiredstring
form_idrequiredstring | nullThe Form it is read with; null while the Router has not picked one, and in no_form.
staterequired"processing" | "needs_review" | "approved" | "rejected" | "failed" | "no_form" | "deleted"processing: being read. needs_review: waits for a user to check it. approved: approved; the Payload is here until its data is deleted. rejected: a user ruled it unusable. failed: Vink couldn't read it. no_form: Vink read it, but none of your Forms fits; a user can move it to a Form. deleted: its data was deleted before Approval. Only approved ever has a Payload.
filenamerequiredstring
referencerequiredstring | nullYour own id for it (an order number, a case id), sent as reference to Send a Submission in or as the plus-tag of an Intake Address (<address>+po123@…, in lower case). null when none came with it.
uploaded_atrequiredstring
data_deleted_atrequiredstring | nullWhen its file and values were deleted; null while they are kept.
fieldsrequiredobject | nullThe Field Values, readable before Approval: one key per Field of the Form, in the Form's order. A Field is a FieldValue, a List Field a ListFieldValue. They include a user's corrections. null while it is processing, failed, no_form or deleted, and after the data is deleted. The Payload stays null until Approval.
payloadrequiredEnvelope | nullThe envelope a Webhook gets, with delivery_id sub_<id>. null before Approval and after the data is deleted.

FieldValue

One Field's value as Vink read it, or as a user corrected it.

NameTypeDescription
valuerequiredstring | number | boolean | nullnull for no value.
confidencerequirednumber | nullHow sure Vink is of the value, from 0 to 1; null when Vink stored no value for the Field.
needs_reviewrequiredbooleantrue while a user must still check the value.
pagesrequiredinteger[]The pages the value was read on, from 1; [] for none.

ListFieldValue

A List Field's entries; entries a user removed are left out, entries a user added are in.

NameTypeDescription
needs_reviewrequiredbooleantrue while a user must still confirm the entries are complete.
entriesrequiredobject[]One object per entry, with a FieldValue per sub-Field key; [] for none.

EnvelopeSchema

NameTypeDescription
schemarequiredobjectA JSON Schema of the envelope, in Swagger 2.0 style: one type per property, x-nullable: true where the value can be null, and each Field's label as title and x-ms-summary.

SubscriptionRequest

NameTypeDescription
form_idrequiredstringThe Form whose Approvals you want.
urlrequiredstringReceives the envelopes. https only.

Subscription

NameTypeDescription
idrequiredstringUse it to unsubscribe.
form_idrequiredstring
urlrequiredstring
created_atrequiredstring

DeletedSubscription

NameTypeDescription
idrequiredstring
deletedrequiredbooleanAlways true.

Envelope

What every Webhook receives on an Approval, signed with X-Vink-Signature.

NameTypeDescription
eventrequired"submission.approved"
delivery_idrequiredstringThe same on every retry and re-send of one Delivery: de-duplicate on it. test_… in a test; sub_<submission id> when read with Get a Submission.
testrequiredbooleantrue for a test-send or a sample.
submissionrequired{ id: string, filename: string, reference: string | null, uploaded_at: string, file_url: string | null }
formrequired{ id: string, version: integer }
approvalrequired{ mode: "manual" | "auto" | "agent", by: string | null, at: string }
datarequiredobjectOne key per Field of the Form, always present: null for no value. A List Field is an array of entries, each with every sub-Field key; [] for none.

Integration

NameTypeDescription
idrequiredstringUse it to list the Integration's Deliveries.
namerequiredstring
kindrequired"webhook" | "google_sheets" | "excel"Where it sends to. Vink may add kinds: treat a kind you don't know as opaque.
form_idsrequiredstring[]The Forms it is attached to.
subscription_idrequiredstring | nullThe Subscription this Webhook is for; null for an Integration an Admin made.
needs_reconnectrequiredbooleanIts connected account no longer lets Vink in, so its Deliveries fail until an Admin reconnects it in Vink. Always false for a Webhook.

Delivery

NameTypeDescription
idrequiredstringUse it to send the Delivery again.
delivery_idrequiredstringThe delivery_id of the envelope the receiver gets: the same on every attempt and retry.
submission_idrequiredstring
integration_idrequiredstringStill set after the Integration was removed.
integration_namerequiredstringThe Integration's name when the Delivery was made.
staterequired"pending" | "retrying" | "delivered" | "failed"pending: about to be sent. retrying: an attempt failed and another follows at next_attempt_at. delivered and failed are final, until a failed one is sent again.
failure_reasonrequiredstring | nullWhy the last attempt failed, for people.
next_attempt_atrequiredstring | nullSet while retrying.
can_retryrequiredbooleanWhether Send a Delivery again takes it: it is failed, its Integration is still there and its Submission's data is not deleted.
created_atrequiredstringWhen the Submission was approved.
attemptsrequiredDeliveryAttempt[]Oldest first.

DeliveryAttempt

NameTypeDescription
atrequiredstring
statusrequiredinteger | nullThe receiver's HTTP status; null when it didn't answer.
errorrequiredstring | nullWhy there was no answer, such as a timeout.
bodyrequiredstring | nullThe first 500 characters of the receiver's answer; null once the Submission's data is deleted.

DeliveryList

NameTypeDescription
datarequiredDelivery[]
next_cursorrequiredstring | nullPass it as cursor for the next page; null on the last page.

FormDescription

NameTypeDescription
descriptionrequiredstringWhat the document is and which data you need, at most 2000 characters.

CreatedFormProposal

NameTypeDescription
idrequiredstringThe Form Proposal's id.
staterequired"processing"Always processing here.

FormProposal

NameTypeDescription
idrequiredstring
staterequired"processing" | "ready" | "failed"processing: Vink reads the sample and proposes Fields. ready: fields holds them. failed: see failure; an Admin can retry in the app.
sourcerequired"sample" | "description"
filenamerequiredstringThe sample's name, or a description's first words.
descriptionrequiredstring | nullThe description it was made from; null for a sample.
failurerequiredstring | nullunreadable: the sample can't be read. failed: every attempt failed; a retry may work. null unless state is failed.
created_atrequiredstring
fieldsrequiredarray | nullThe proposed Fields once ready, else null. None is required; an Admin decides that when saving.

Usage

NameTypeDescription
planrequiredstring | nullThe Plan (starter, team, business, scale, custom), or null without one. Vink may add Plans.
unlimitedrequiredbooleantrue when Vink never refuses for Credits.
credits_leftrequiredinteger | nullCredits left: free Credits plus what is left of the Plan this period. null when unlimited.
credits_usedrequiredintegerCredits used this period.
resets_atrequiredstring | nullWhen the period ends and the Plan's Credits are full again; null without a Plan.