{"openapi":"3.1.0","info":{"title":"Vink API","version":"1","description":"Send Submissions in, read their Field Values, correct and approve them, subscribe to Approvals, and follow and retry their Deliveries. Every answer is JSON with snake_case keys.\n\nEvery request needs one of two kinds of access, and each operation says which it takes. An API Key (`apiKey`) is for a program without a user: it sends Submissions in, reads their state and Field Values (the Payload only after Approval), reads Forms, manages Subscriptions, lists Integrations and their Deliveries and sends a failed Delivery again, but it can't change a Submission. An Agent Connection (`agentOAuth`) is an AI agent's OAuth access token, given by one user for one Organisation: the agent acts as that user, so it can also correct, move, reject and, where the Form allows Agent Approval, approve a Submission, and make Form Proposals; when its user is an Admin, it can also list Integrations and their Deliveries and send a failed Delivery again. It can't manage Subscriptions. Both can read the Credits left. Agents can use the same operations as tools through the MCP server at `https://vink.page/mcp`."},"servers":[{"url":"https://vink.page/v1"}],"security":[{"apiKey":[]},{"agentOAuth":[]}],"tags":[{"name":"Forms","description":"The kinds of document your Organisation reads, and their Fields."},{"name":"Submissions","description":"PDFs, photos, emails, Spreadsheets and Word Files Vink reads into a Form's Fields."},{"name":"Subscriptions","description":"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."},{"name":"Integrations","description":"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."},{"name":"Deliveries","description":"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."},{"name":"Form Proposals","description":"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."},{"name":"Usage","description":"The Credits your Organisation has left this period. One PDF page, email, photo, Spreadsheet or Word File costs 10 Credits."}],"paths":{"/forms":{"get":{"operationId":"listForms","summary":"List Forms","description":"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.","tags":["Forms"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"responses":{"200":{"description":"The Forms.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Form"}}}},"example":{"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}]}]}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/forms/{id}":{"get":{"operationId":"getForm","summary":"Get a Form","description":"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.","tags":["Forms"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Form's `id`, from List Forms.","schema":{"type":"string"}}],"responses":{"200":{"description":"The Form.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormWithInstructions"},"example":{"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"]}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No Form with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form with that id in your Organisation."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/submissions":{"post":{"operationId":"sendSubmissionToAnyForm","summary":"Send a Submission in, without choosing the Form","description":"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.","tags":["Submissions"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"form_id","in":"query","description":"The 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.","schema":{"type":"string"}},{"name":"filename","in":"query","description":"The 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.","schema":{"type":"string","example":"F-2026-118.pdf"}},{"name":"reference","in":"query","description":"Your 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.","schema":{"type":"string","maxLength":100,"example":"PO-2026-1042"}}],"requestBody":{"required":true,"description":"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.","content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The file: a PDF, a JPG, PNG or HEIC image, or an email file (`.eml`)."},"filename":{"type":"string","description":"The name the Submission shows in Vink."},"form_id":{"type":"string","description":"The Form's `id`. Left out or empty, Vink picks the Form. Not used on the Form's own path."},"reference":{"type":"string","maxLength":100,"description":"Your 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."}}}},"application/pdf":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/heic":{"schema":{"type":"string","format":"binary"}},"message/rfc822":{"schema":{"type":"string","format":"binary"}},"application/vnd.ms-outlook":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}},"text/csv":{"schema":{"type":"string","format":"binary"}},"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"$ref":"#/components/schemas/EmailSubmission"},"example":{"subject":"Factuur F2026-0412","from":"boekhouding@hoekstra.example","body":"Goedemiddag, bijgevoegd de factuur van oktober. Het totaal is 151,25 euro.","attachments":[{"filename":"factuur.jpg","content_base64":"/9j/4AAQSkZJRgABAQ..."}]}}}},"responses":{"201":{"description":"Vink accepted the file or email and is reading it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentSubmission"},"example":{"id":"j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb","ids":["j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb"],"state":"processing"}}}},"400":{"description":"The request has no file in it (`missing_file`), or an email body or a `reference` isn't valid (`invalid_request`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"missing_file","message":"The request has no file in it."}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Your Organisation has fewer Items left than the input needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"out_of_items","message":"You have 5 items left; this PDF needs 8."}}}}},"404":{"description":"A `form_id` was given, and no Form in your Organisation has it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form with that id in your Organisation."}}}}},"409":{"description":"The Form is archived. An Admin can restore it in Vink.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"form_archived","message":"This Form is archived. An Admin can restore it in Vink."}}}}},"413":{"description":"The request body, an image, a Word File, a Spreadsheet or an email's text or attachments are over their limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"file_too_large","message":"The file is larger than 10 MB."}}}}},"415":{"description":"Vink 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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unsupported_file_type","message":"Vink reads PDFs, photos (JPG, PNG, HEIC), emails (.eml, .msg), Spreadsheets (.xlsx, .csv) and Word Files (.docx); this file type isn't supported."}}}}},"422":{"description":"The 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`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"too_many_pages","message":"This PDF has 21 pages. Vink reads up to 20 pages per PDF."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/forms/{form_id}/submissions":{"post":{"operationId":"sendSubmission","summary":"Send a Submission in","description":"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.","tags":["Submissions"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"form_id","in":"path","required":true,"description":"The Form's `id`, from List Forms.","schema":{"type":"string"}},{"name":"filename","in":"query","description":"The 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.","schema":{"type":"string","example":"F-2026-118.pdf"}},{"name":"reference","in":"query","description":"Your 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.","schema":{"type":"string","maxLength":100,"example":"PO-2026-1042"}}],"requestBody":{"required":true,"description":"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.","content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The file: a PDF, a JPG, PNG or HEIC image, or an email file (`.eml`)."},"filename":{"type":"string","description":"The name the Submission shows in Vink."},"form_id":{"type":"string","description":"The Form's `id`. Left out or empty, Vink picks the Form. Not used on the Form's own path."},"reference":{"type":"string","maxLength":100,"description":"Your 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."}}}},"application/pdf":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/heic":{"schema":{"type":"string","format":"binary"}},"message/rfc822":{"schema":{"type":"string","format":"binary"}},"application/vnd.ms-outlook":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}},"text/csv":{"schema":{"type":"string","format":"binary"}},"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"$ref":"#/components/schemas/EmailSubmission"},"example":{"subject":"Factuur F2026-0412","from":"boekhouding@hoekstra.example","body":"Goedemiddag, bijgevoegd de factuur van oktober. Het totaal is 151,25 euro.","attachments":[{"filename":"factuur.jpg","content_base64":"/9j/4AAQSkZJRgABAQ..."}]}}}},"responses":{"201":{"description":"Vink accepted the file or email and is reading it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentSubmission"},"example":{"id":"j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb","ids":["j57b2x0sd4kq9r1m8n3c6v7w5h7bm2rb"],"state":"processing"}}}},"400":{"description":"The request has no file in it (`missing_file`), or an email body or a `reference` isn't valid (`invalid_request`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"missing_file","message":"The request has no file in it."}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Your Organisation has fewer Items left than the input needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"out_of_items","message":"You have 5 items left; this PDF needs 8."}}}}},"404":{"description":"No Form with this id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form with that id in your Organisation."}}}}},"409":{"description":"The Form is archived. An Admin can restore it in Vink.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"form_archived","message":"This Form is archived. An Admin can restore it in Vink."}}}}},"413":{"description":"The request body, an image, a Word File, a Spreadsheet or an email's text or attachments are over their limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"file_too_large","message":"The file is larger than 10 MB."}}}}},"415":{"description":"Vink 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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unsupported_file_type","message":"Vink reads PDFs, photos (JPG, PNG, HEIC), emails (.eml, .msg), Spreadsheets (.xlsx, .csv) and Word Files (.docx); this file type isn't supported."}}}}},"422":{"description":"The 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`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"too_many_pages","message":"This PDF has 21 pages. Vink reads up to 20 pages per PDF."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/submissions/{id}":{"get":{"operationId":"getSubmission","summary":"Get a Submission","description":"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.","tags":["Submissions"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Submission's id, from Send in a Submission or an envelope's `submission.id`.","schema":{"type":"string"}},{"name":"wait","in":"query","required":false,"description":"Seconds 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.","schema":{"type":"integer","minimum":0,"maximum":25}}],"responses":{"200":{"description":"The Submission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"},"example":{"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}]}}}}}},"400":{"description":"`wait` isn't a whole number of seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"`wait` must be a whole number of seconds; Vink waits at most 25."}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No Submission with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Submission with that id in your Organisation."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/submissions/{id}/fields":{"patch":{"operationId":"correctSubmissionFields","summary":"Correct Field Values","description":"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.\n\nNeeds 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.","tags":["Submissions"],"security":[{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Submission's id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["values"],"properties":{"values":{"type":"object","description":"From a value's path to its new value.","additionalProperties":{"type":["string","number","boolean","null"]}}}},"example":{"values":{"invoice_number":"F2026-0412","lines[0].quantity":5}}}}},"responses":{"200":{"description":"The Submission after the change, as Get a Submission answers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body isn't `values`, a path names no value, or a value doesn't fit its Field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"Aantal needs a number."}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Sent with an API Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"Changing a Submission needs an Agent Connection: an API Key has no user to answer for the change."}}}}},"404":{"description":"No Submission with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Submission with that id in your Organisation."}}}}},"409":{"description":"The Submission's state rules the change out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"This Submission is approved."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/submissions/{id}/form":{"post":{"operationId":"changeSubmissionForm","summary":"Change a Submission's Form","description":"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.\n\nNeeds 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.","tags":["Submissions"],"security":[{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Submission's id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["form_id"],"properties":{"form_id":{"type":"string"}}},"example":{"form_id":"k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra"}}}},"responses":{"200":{"description":"The Submission after the change, as Get a Submission answers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body has no `form_id`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"Send a JSON body with form_id, a string."}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Sent with an API Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"Changing a Submission needs an Agent Connection: an API Key has no user to answer for the change."}}}}},"404":{"description":"No Submission, or no Form, with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form with that id in your Organisation."}}}}},"409":{"description":"The Submission's state rules the change out (`conflict`), or the Form is archived (`form_archived`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"form_archived","message":"This Form is archived. An Admin can restore it in Vink."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/submissions/{id}/reject":{"post":{"operationId":"rejectSubmission","summary":"Reject a Submission","description":"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.\n\nNeeds 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.","tags":["Submissions"],"security":[{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Submission's id.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":["string","null"]}}},"example":{"reason":"Duplicate of F2026-0411"}}}},"responses":{"200":{"description":"The Submission after the change, as Get a Submission answers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body isn't JSON, or `reason` isn't a string.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"Send no body, or a JSON body with an optional reason, a string."}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Sent with an API Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"Changing a Submission needs an Agent Connection: an API Key has no user to answer for the change."}}}}},"404":{"description":"No Submission with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Submission with that id in your Organisation."}}}}},"409":{"description":"The Submission's state rules the change out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"This Submission is approved."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/submissions/{id}/approve":{"post":{"operationId":"approveSubmission","summary":"Approve a Submission","description":"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.\n\nNeeds 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.","tags":["Submissions"],"security":[{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Submission's id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The Submission after the change, as Get a Submission answers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Sent with an API Key, or Agent Approval is off for the Form.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"agent_approval_off","message":"Agent Approval is off for this Form."}}}}},"404":{"description":"No Submission with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Submission with that id in your Organisation."}}}}},"409":{"description":"Values still need review (`needs_review`), or the Submission's state rules the Approval out (`conflict`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"needs_review","message":"1 value still needs review."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/subscriptions":{"post":{"operationId":"createSubscription","summary":"Subscribe to Approvals","description":"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.","tags":["Subscriptions"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"description":"JSON with `form_id`, the Form to hear about (from List Forms), and `url`, the https URL that receives the envelopes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequest"},"example":{"form_id":"k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra","url":"https://hooks.zapier.com/hooks/standard/123456/abcdef/"}}}},"responses":{"201":{"description":"The Subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"},"example":{"id":"j57a2x9kq4m1c8v3n6e5w4t8hs7bm2rb","form_id":"k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra","url":"https://hooks.zapier.com/hooks/standard/123456/abcdef/","created_at":"2026-10-06T09:00:00.000Z"}}},"headers":{"Location":{"description":"The Subscription's URL: a `DELETE` on it unsubscribes (Power Automate does that itself).","schema":{"type":"string","example":"https://vink.page/v1/subscriptions/j57a2x9kq4m1c8v3n6e5w4t8hs7bm2rb"}}}},"400":{"description":"The body isn't JSON with `form_id` and `url`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No Form with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form with that id in your Organisation."}}}}},"409":{"description":"The Organisation already has 50 Subscriptions (`too_many_subscriptions`), or the Form is archived (`form_archived`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`url` isn't an https URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/subscriptions/{id}":{"delete":{"operationId":"deleteSubscription","summary":"Unsubscribe","description":"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.","tags":["Subscriptions"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Subscription's id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The Subscription ended, or had ended already.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedSubscription"},"example":{"id":"j57a2x9kq4m1c8v3n6e5w4t8hs7bm2rb","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/forms/{form_id}/sample":{"get":{"operationId":"getFormSample","summary":"Sample envelope","description":"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.","tags":["Subscriptions"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"form_id","in":"path","required":true,"description":"The Form's id, from List Forms.","schema":{"type":"string"}}],"responses":{"200":{"description":"The example envelope, with `\"test\": true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"},"example":{"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}]}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No Form with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form with that id in your Organisation."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/forms/{form_id}/schema":{"get":{"operationId":"getFormSchema","summary":"Envelope schema","description":"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.","tags":["Subscriptions"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"form_id","in":"path","required":true,"description":"The Form's id, from List Forms.","schema":{"type":"string"}}],"responses":{"200":{"description":"The schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvelopeSchema"},"example":{"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}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No Form with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form with that id in your Organisation."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/integrations":{"get":{"operationId":"listIntegrations","summary":"List Integrations","description":"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`.","tags":["Integrations"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"responses":{"200":{"description":"The Integrations.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Integration"}}}},"example":{"data":[{"id":"m27d4x8kq2n1c9v3b6e5w4t8hs7bm2rc","name":"Bookkeeping","kind":"webhook","form_ids":["k17c9z1fx3q8d2v0n6e5w4t8hs7bm2ra"],"subscription_id":null,"needs_reconnect":false}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"An Agent Connection whose user is not an Admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/integrations/{id}/deliveries":{"get":{"operationId":"listIntegrationDeliveries","summary":"List an Integration's Deliveries","description":"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`.","tags":["Deliveries"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Integration's `id`, from List Integrations.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many Deliveries a page holds at most. 50 when left out.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before. Left out, you get the first page.","schema":{"type":"string"}},{"name":"state","in":"query","required":false,"description":"Only Deliveries in this state, e.g. `failed` to find what to send again.","schema":{"type":"string","enum":["pending","retrying","delivered","failed"]}}],"responses":{"200":{"description":"A page of Deliveries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryList"},"example":{"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}}}},"400":{"description":"`limit`, `cursor` or `state` isn't one Vink takes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"An Agent Connection whose user is not an Admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No Integration with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Integration with that id in your Organisation."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/submissions/{id}/deliveries":{"get":{"operationId":"listSubmissionDeliveries","summary":"List a Submission's Deliveries","description":"One Delivery per Integration the Submission's Form was attached to at Approval, oldest first. Empty before Approval, and when nothing was attached.","tags":["Deliveries"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Submission's `id`, from Send a Submission in.","schema":{"type":"string"}}],"responses":{"200":{"description":"The Deliveries.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}}}},"example":{"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\"}"}]}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"An Agent Connection whose user is not an Admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No Submission with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Submission with that id in your Organisation."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/deliveries/{id}/retry":{"post":{"operationId":"retryDelivery","summary":"Send a Delivery again","description":"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.","tags":["Deliveries"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The Delivery's `id`, from a list of Deliveries.","schema":{"type":"string"}}],"responses":{"202":{"description":"The Delivery, now `pending`: it is sent in a moment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"},"example":{"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\"}"}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"An Agent Connection whose user is not an Admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No Delivery with that id in your Organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Delivery with that id in your Organisation."}}}}},"409":{"description":"It 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`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/form-proposals":{"post":{"operationId":"createFormProposal","summary":"Propose a Form","description":"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.","tags":["Form Proposals"],"security":[{"agentOAuth":[]}],"requestBody":{"required":true,"description":"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).","content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The file: a PDF, a JPG, PNG or HEIC image, or an email file (`.eml`)."},"filename":{"type":"string","description":"The name the Submission shows in Vink."},"form_id":{"type":"string","description":"The Form's `id`. Left out or empty, Vink picks the Form. Not used on the Form's own path."},"reference":{"type":"string","maxLength":100,"description":"Your 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."}}}},"application/pdf":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/heic":{"schema":{"type":"string","format":"binary"}},"message/rfc822":{"schema":{"type":"string","format":"binary"}},"application/vnd.ms-outlook":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}},"text/csv":{"schema":{"type":"string","format":"binary"}},"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/FormDescription"},{"$ref":"#/components/schemas/EmailSubmission"}]},"example":{"description":"Supplier invoices: I need the supplier, invoice number, date, total amount and the lines."}}}},"responses":{"201":{"description":"Vink is reading the sample or the description and proposing Fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedFormProposal"},"example":{"id":"m81d4f2ty6p0c3x9b5a7k2w4hs7bm2rc","state":"processing"}}}},"400":{"description":"The request has no file in it (`missing_file`), or the JSON isn't valid (`invalid_request`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"missing_file","message":"The request has no file in it."}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Your Organisation has fewer Items left than the sample needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"out_of_items","message":"You have 5 items left; this PDF needs 8."}}}}},"403":{"description":"Form 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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"Form Proposals are made by a user: use an Agent Connection, not an API Key."}}}}},"413":{"description":"The request body, an image or an email's text or attachments are over their limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"file_too_large","message":"The file is larger than 10 MB."}}}}},"415":{"description":"Vink can't read the sample: the same codes as Send a Submission in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unsupported_file_type","message":"Vink reads PDFs, photos (JPG, PNG, HEIC), emails (.eml, .msg), Spreadsheets (.xlsx, .csv) and Word Files (.docx); this file type isn't supported."}}}}},"422":{"description":"The 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`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_description","message":"Describe the document and the data you need first."}}}}},"429":{"description":"Your Organisation described 20 Forms in the last 24 hours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"too_many_descriptions","message":"Your Organisation has described 20 Forms in the last 24 hours. Try again later."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/form-proposals/{id}":{"get":{"operationId":"getFormProposal","summary":"Get a Form Proposal","description":"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.","tags":["Form Proposals"],"security":[{"agentOAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The proposal's id, from Propose a Form.","schema":{"type":"string"}}],"responses":{"200":{"description":"The Form Proposal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormProposal"},"example":{"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}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Form 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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"Form Proposals are made by a user: use an Agent Connection, not an API Key."}}}}},"404":{"description":"No Form Proposal with that id in your Organisation. It may be saved, discarded, or deleted after 7 days.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"There's no Form Proposal with that id in your Organisation."}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/usage":{"get":{"operationId":"getUsage","summary":"Get usage","description":"The Organisation's Plan, the Credits left and used this period, and when they reset.","tags":["Usage"],"security":[{"apiKey":[]},{"agentOAuth":[]}],"responses":{"200":{"description":"The usage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"},"example":{"plan":"team","unlimited":false,"credits_left":4210,"credits_used":1790,"resets_at":"2026-11-12T00:00:00.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API Key, made by an Admin under Organisation settings → API Keys. Send it as `Authorization: Bearer <key>`. For a program without a user: it sends Submissions in, reads them, manages Subscriptions, lists Integrations and their Deliveries, and sends a failed Delivery again. It can't change a Submission."},"agentOAuth":{"type":"oauth2","description":"An Agent Connection: an AI agent's OAuth access token, sent as `Authorization: Bearer <token>`. Authorization code flow with PKCE (`S256`); a client registers itself at `https://vink.page/api/auth/mcp/register` (dynamic client registration). At connect the user signs in and picks the Organisation. The agent then acts as that user, with their Membership's rights, and every change is recorded as theirs via agent.","flows":{"authorizationCode":{"authorizationUrl":"https://vink.page/api/auth/mcp/authorize","tokenUrl":"https://vink.page/api/auth/mcp/token","refreshUrl":"https://vink.page/api/auth/mcp/token","scopes":{"openid":"Sign in as the user.","profile":"The user's name.","email":"The user's email address.","offline_access":"A refresh token, to get new access tokens."}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable, snake_case. Branch on this.","example":"invalid_api_key"},"message":{"type":"string","description":"A sentence for people. It may change.","example":"This API Key doesn't exist or was revoked."}}}}},"Form":{"type":"object","required":["id","name","description","version","fields"],"properties":{"id":{"type":"string","description":"Use it in the Form's other endpoints."},"name":{"type":"string"},"description":{"type":["string","null"]},"version":{"type":"integer","description":"Goes up by one every time the Form is saved."},"fields":{"type":"array","items":{"$ref":"#/components/schemas/Field"}}}},"FormWithInstructions":{"type":"object","required":["id","name","description","version","fields","general_instruction","guidelines"],"properties":{"id":{"type":"string","description":"Use it in the Form's other endpoints."},"name":{"type":"string"},"description":{"type":["string","null"]},"version":{"type":"integer","description":"Goes up by one every time the Form is saved."},"fields":{"type":"array","items":{"$ref":"#/components/schemas/Field"}},"general_instruction":{"type":"string","description":"Vink follows it on every Submission of this Form, under its own fixed rules. Empty when there is none."},"guidelines":{"type":"array","items":{"$ref":"#/components/schemas/Guideline"},"description":"Instructions for one situation each, at most 20."}}},"Guideline":{"type":"object","required":["name","use_when","instruction","field_keys"],"properties":{"name":{"type":"string","description":"Unique within the Form.","example":"Credit notes"},"use_when":{"type":"string","description":"When it applies, in words: Vink uses the Guideline on a Submission only when this fits the document. Empty: always.","example":"The document is a credit note"},"instruction":{"type":"string","example":"Write the total as a negative amount."},"field_keys":{"type":"array","items":{"type":"string"},"description":"The keys of the Fields it is about; a List Field's key covers its sub-Fields. Empty: all Fields."}}},"Field":{"type":"object","required":["key","label","type","required"],"properties":{"key":{"type":"string","description":"The Field's name in the Payload, snake_case.","example":"invoice_number"},"label":{"type":"string","description":"What users see in Vink.","example":"Factuurnummer"},"type":{"type":"string","enum":["text","number","date","boolean","choice","list"],"description":"`choice` has `options`; `list` has `fields`, the sub-Fields of each entry."},"required":{"type":"boolean"},"options":{"type":"array","items":{"type":"string"},"description":"Only on `choice`: the values the Payload can hold."},"fields":{"type":"array","items":{"$ref":"#/components/schemas/SubField"},"description":"Only on `list`: the sub-Fields of each entry."}}},"SubField":{"type":"object","required":["key","label","type","required"],"properties":{"key":{"type":"string","description":"The Field's name in the Payload, snake_case.","example":"invoice_number"},"label":{"type":"string","description":"What users see in Vink.","example":"Factuurnummer"},"type":{"type":"string","enum":["text","number","date","boolean","choice"],"description":"`choice` has `options`."},"required":{"type":"boolean"},"options":{"type":"array","items":{"type":"string"},"description":"Only on `choice`: the values the Payload can hold."}}},"SentSubmission":{"type":"object","required":["id","ids","state"],"properties":{"id":{"type":"string","description":"The Submission's id: the first one, when there are more."},"ids":{"type":"array","items":{"type":"string"},"description":"Every Submission the input became. More than one only for an email file that Vink split, as mail to an Intake Address is."},"state":{"type":"string","enum":["processing"],"description":"Always `processing` here: Vink is reading the file or email."}}},"EmailSubmission":{"type":"object","description":"An email as JSON. At least one of `body` and `attachments` is needed. Vink reads it as one Submission: its text, then its attachments.","properties":{"subject":{"type":"string","description":"The subject. It names the Submission in Vink."},"from":{"type":"string","description":"The sender, for example `Name <name@example.com>`."},"date":{"type":"string","format":"date-time","description":"When the email was sent."},"body":{"type":"string","description":"The email's text, at most 200 KB."},"attachments":{"type":"array","description":"PDF, JPG, PNG or HEIC files, at most 10 and 12 MB together before base64. Any other type is refused.","items":{"type":"object","required":["content_base64"],"properties":{"filename":{"type":"string"},"content_base64":{"type":"string","description":"The file, base64-encoded (not a data URL)."}}}},"form_id":{"type":["string","null"],"description":"The Form's `id`. Left out or `null`, Vink picks the Form. Not used on the Form's own path."},"filename":{"type":"string","description":"The name the Submission shows in Vink, instead of the subject."},"reference":{"type":["string","null"],"maxLength":100,"description":"Your 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":{"type":"object","required":["id","form_id","state","filename","reference","uploaded_at","data_deleted_at","fields","payload"],"properties":{"id":{"type":"string"},"form_id":{"type":["string","null"],"description":"The Form it is read with; `null` while the Router has not picked one, and in `no_form`."},"state":{"type":"string","enum":["processing","needs_review","approved","rejected","failed","no_form","deleted"],"description":"`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."},"filename":{"type":"string"},"reference":{"type":["string","null"],"description":"Your 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_at":{"type":"string","format":"date-time"},"data_deleted_at":{"type":["string","null"],"format":"date-time","description":"When its file and values were deleted; `null` while they are kept."},"fields":{"type":["object","null"],"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/FieldValue"},{"$ref":"#/components/schemas/ListFieldValue"}]},"description":"The 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."},"payload":{"oneOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"null"}],"description":"The envelope a Webhook gets, with `delivery_id` `sub_<id>`. `null` before Approval and after the data is deleted."}}},"FieldValue":{"type":"object","required":["value","confidence","needs_review","pages"],"description":"One Field's value as Vink read it, or as a user corrected it.","properties":{"value":{"type":["string","number","boolean","null"],"description":"`null` for no value."},"confidence":{"type":["number","null"],"description":"How sure Vink is of the value, from 0 to 1; `null` when Vink stored no value for the Field."},"needs_review":{"type":"boolean","description":"`true` while a user must still check the value."},"pages":{"type":"array","items":{"type":"integer"},"description":"The pages the value was read on, from 1; `[]` for none."}}},"ListFieldValue":{"type":"object","required":["needs_review","entries"],"description":"A List Field's entries; entries a user removed are left out, entries a user added are in.","properties":{"needs_review":{"type":"boolean","description":"`true` while a user must still confirm the entries are complete."},"entries":{"type":"array","items":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/FieldValue"}},"description":"One object per entry, with a FieldValue per sub-Field key; `[]` for none."}}},"EnvelopeSchema":{"type":"object","required":["schema"],"properties":{"schema":{"type":"object","description":"A 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":{"type":"object","required":["form_id","url"],"properties":{"form_id":{"type":"string","description":"The Form whose Approvals you want."},"url":{"type":"string","description":"Receives the envelopes. https only."}}},"Subscription":{"type":"object","required":["id","form_id","url","created_at"],"properties":{"id":{"type":"string","description":"Use it to unsubscribe."},"form_id":{"type":"string"},"url":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"DeletedSubscription":{"type":"object","required":["id","deleted"],"properties":{"id":{"type":"string"},"deleted":{"type":"boolean","description":"Always `true`."}}},"Envelope":{"type":"object","required":["event","delivery_id","test","submission","form","approval","data"],"description":"What every Webhook receives on an Approval, signed with `X-Vink-Signature`.","properties":{"event":{"type":"string","enum":["submission.approved"]},"delivery_id":{"type":"string","description":"The 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."},"test":{"type":"boolean","description":"`true` for a test-send or a sample."},"submission":{"type":"object","required":["id","filename","reference","uploaded_at","file_url"],"properties":{"id":{"type":"string"},"filename":{"type":"string"},"reference":{"type":["string","null"],"description":"The sender's own id for the Submission (an order number, a case id): the `reference` sent to Send a Submission in, or the plus-tag of an Intake Address, in lower case. `null` when none came with it, and in a test or a sample."},"uploaded_at":{"type":"string","format":"date-time"},"file_url":{"type":["string","null"],"format":"uri","description":"A link to the Submission's file that works for 24 hours, made new each time Vink sends or you read the Payload. Fetch the file within that time; keep the file, not the link. `null` for a Submission that came in as an email, and in a test or a sample."}}},"form":{"type":"object","required":["id","version"],"properties":{"id":{"type":"string"},"version":{"type":"integer","description":"The Form Version the Submission was read with."}}},"approval":{"type":"object","required":["mode","by","at"],"properties":{"mode":{"type":"string","enum":["manual","auto","agent"],"description":"`auto` for Auto-Send; `agent` for an Approval given by an agent through an Agent Connection, where the Form allows Agent Approval."},"by":{"type":["string","null"],"description":"The approving user's id; `null` for Auto-Send."},"at":{"type":"string","format":"date-time"}}},"data":{"type":"object","description":"One 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":{"type":"object","required":["id","name","kind","form_ids","subscription_id","needs_reconnect"],"properties":{"id":{"type":"string","description":"Use it to list the Integration's Deliveries."},"name":{"type":"string"},"kind":{"type":"string","enum":["webhook","google_sheets","excel"],"description":"Where it sends to. Vink may add kinds: treat a kind you don't know as opaque."},"form_ids":{"type":"array","items":{"type":"string"},"description":"The Forms it is attached to."},"subscription_id":{"type":["string","null"],"description":"The Subscription this Webhook is for; `null` for an Integration an Admin made."},"needs_reconnect":{"type":"boolean","description":"Its connected account no longer lets Vink in, so its Deliveries fail until an Admin reconnects it in Vink. Always `false` for a Webhook."}}},"Delivery":{"type":"object","required":["id","delivery_id","submission_id","integration_id","integration_name","state","failure_reason","next_attempt_at","can_retry","created_at","attempts"],"properties":{"id":{"type":"string","description":"Use it to send the Delivery again."},"delivery_id":{"type":"string","description":"The `delivery_id` of the envelope the receiver gets: the same on every attempt and retry."},"submission_id":{"type":"string"},"integration_id":{"type":"string","description":"Still set after the Integration was removed."},"integration_name":{"type":"string","description":"The Integration's name when the Delivery was made."},"state":{"type":"string","enum":["pending","retrying","delivered","failed"],"description":"`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_reason":{"type":["string","null"],"description":"Why the last attempt failed, for people."},"next_attempt_at":{"type":["string","null"],"format":"date-time","description":"Set while `retrying`."},"can_retry":{"type":"boolean","description":"Whether Send a Delivery again takes it: it is `failed`, its Integration is still there and its Submission's data is not deleted."},"created_at":{"type":"string","format":"date-time","description":"When the Submission was approved."},"attempts":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryAttempt"},"description":"Oldest first."}}},"DeliveryAttempt":{"type":"object","required":["at","status","error","body"],"properties":{"at":{"type":"string","format":"date-time"},"status":{"type":["integer","null"],"description":"The receiver's HTTP status; `null` when it didn't answer."},"error":{"type":["string","null"],"description":"Why there was no answer, such as a timeout."},"body":{"type":["string","null"],"description":"The first 500 characters of the receiver's answer; `null` once the Submission's data is deleted."}}},"DeliveryList":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}},"next_cursor":{"type":["string","null"],"description":"Pass it as `cursor` for the next page; `null` on the last page."}}},"FormDescription":{"type":"object","required":["description"],"properties":{"description":{"type":"string","description":"What the document is and which data you need, at most 2000 characters."}}},"CreatedFormProposal":{"type":"object","required":["id","state"],"properties":{"id":{"type":"string","description":"The Form Proposal's id."},"state":{"type":"string","enum":["processing"],"description":"Always `processing` here."}}},"FormProposal":{"type":"object","required":["id","state","source","filename","description","failure","created_at","fields"],"properties":{"id":{"type":"string"},"state":{"type":"string","enum":["processing","ready","failed"],"description":"`processing`: Vink reads the sample and proposes Fields. `ready`: `fields` holds them. `failed`: see `failure`; an Admin can retry in the app."},"source":{"type":"string","enum":["sample","description"]},"filename":{"type":"string","description":"The sample's name, or a description's first words."},"description":{"type":["string","null"],"description":"The description it was made from; `null` for a sample."},"failure":{"type":["string","null"],"description":"`unreadable`: the sample can't be read. `failed`: every attempt failed; a retry may work. `null` unless `state` is `failed`."},"created_at":{"type":"string","format":"date-time"},"fields":{"type":["array","null"],"description":"The proposed Fields once `ready`, else `null`. None is required; an Admin decides that when saving.","items":{"allOf":[{"$ref":"#/components/schemas/Field"},{"type":"object","required":["recommended"],"properties":{"recommended":{"type":"boolean","description":"Vink suggests keeping this Field; the others are data it found that is seldom needed."}}}]}}}},"Usage":{"type":"object","required":["plan","unlimited","credits_left","credits_used","resets_at"],"properties":{"plan":{"type":["string","null"],"description":"The Plan (`starter`, `team`, `business`, `scale`, `custom`), or `null` without one. Vink may add Plans."},"unlimited":{"type":"boolean","description":"`true` when Vink never refuses for Credits."},"credits_left":{"type":["integer","null"],"description":"Credits left: free Credits plus what is left of the Plan this period. `null` when `unlimited`."},"credits_used":{"type":"integer","description":"Credits used this period."},"resets_at":{"type":["string","null"],"format":"date-time","description":"When the period ends and the Plan's Credits are full again; `null` without a Plan."}}}},"responses":{"Unauthorized":{"description":"The API Key is missing, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_api_key","message":"This API Key doesn't exist or was revoked."}}}}},"InternalError":{"description":"Something went wrong on our side.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"internal_error","message":"Something went wrong on our side. Try again later."}}}}}}}}