Aanvragen
Een aanvraag maken
Twee API-aanroepen: vraag het formulier wat je kunt opgeven, en wijs het dan toe aan één persoon met de waarden die je al kent.
Begin in het deelvenster

Open je gepubliceerde formulier, klik op Delen, en kies het tabblad Aanvragen. De kaart daar geeft je alles wat je nodig hebt om de eerste aanroep te doen:
Het formulier-id, met een kopieerknop.
Een curl-fragment en een MCP-prompt, allebei opgebouwd uit de echte veldsleutels van je formulier — zodat het voorbeeld al gericht is op de velden die dit formulier daadwerkelijk heeft.
Een tabblad Handmatig dat met de hand één aanvraag aanmaakt, en Probeer het zelf, dat omzet wat je daar hebt ingevuld naar een aanvraag in testmodus en je de link ervan geeft.
Een link naar de pagina Aanvragen, gefilterd op dit formulier.
Publiceer eerst
Een niet-gepubliceerd formulier kan niet worden aangevraagd, en de fragmenten blijven uitgeschakeld totdat je publiceert. Veldsleutels
worden bevroren bij de eerste publicatie — dat is wat je automatisering in staat stelt company_name een jaar later nog
steeds aan te spreken. Zie Veldsleutels.
Stap 1 — De velden ontdekken
fields.list geeft elk veld terug van de huidige gepubliceerde versie van het formulier, met de sleutel om het aan te spreken,
de waardevorm die het aanneemt, en tot welk vak het behoort.
curl -X POST https://api.formbase.so/api/v1 \
-H "Authorization: Bearer $FORMBASE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"method":"fields.list","params":{"formId":"j57..."}}'{
"ok": true,
"data": {
"published": true,
"items": [
{ "key": "company_name", "type": "text", "title": "Company", "required": true, "prefillable": true },
{
"key": "company_size", "type": "select", "title": "Company size", "required": false, "prefillable": true,
"options": [
{ "key": "1_50", "label": "1–50" },
{ "key": "51_200", "label": "51–200" }
]
},
{ "key": "case_id", "type": "hidden", "title": "Case", "required": false, "prefillable": false, "context": true },
{ "key": "total", "type": "number", "title": "Total", "required": false, "prefillable": false, "calculated": true },
{ "key": "signature", "type": "signature", "title": "Sign here", "required": true, "prefillable": false }
],
"hasMore": false
}
}context: truemarkeert een verborgen veld. De waarde ervan komt incontext, nooit inprefill; de sleutel van een verborgen veld inprefillwordt geweigerd metUNKNOWN_FIELD_KEY.calculated: truemarkeert een berekend veld. Het formulier berekent de waarde zelf, dus niemand kan er een versturen; je leest hem terug onder zijn sleutel inanswers.prefillable: falsemarkeert een veld waarvoor niemand een waarde kan opgeven: bestandsupload, handtekening, betaling, afspraak boeken, en Documentenblokken. De ontvanger vult die vragen zelf in. Verborgen velden en berekende velden tonen ookprefillable: false: verborgen velden nemencontextaan, berekende velden nemen niets aan.optionstoont de keuzes voor een keuzevraag. Stuur de sleutel van de optie, niet het label; het label is er zodat je de keuze die je kent kunt koppelen aan de sleutel. Een matrix toont zijnrowsencolumnsop dezelfde manier.Herhaalgroepen komen terug als één item met
type: “group”,repeating: true, en een lijst vanmembers.
Stap 2 — De aanvraag aanmaken
curl -X POST https://api.formbase.so/api/v1 \
-H "Authorization: Bearer $FORMBASE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"method":"requests.create","params":{
"formId":"j57...",
"recipient":{"email":"ada@acme.com","name":"Ada"},
"context":{"case_id":"CASE-9"},
"prefill":{"company_name":"Acme","company_size":"51_200"},
"readonly":["company_name"],
"delivery":"email",
"externalId":"run-42",
"callbackUrl":"https://automation.example/webhook/resume-abc",
"idempotencyKey":"run-42"}}'{
"ok": true,
"data": {
"id": "kd7...",
"status": "pending",
"url": "https://form.formbase.so/r/rq_...",
"deliveryStatus": "queued",
"expiresAt": 1794787200000,
"createdAt": 1789379200000,
"externalId": "run-42",
"deduplicated": false
}
}deliveryStatus is “queued” wanneer formbase de uitnodiging mailt en “not_requested” wanneer je de
link zelf aflevert.
Vooraf invullen, vergrendelde velden en context
Drie verschillende dingen kunnen aan een aanvraag worden gekoppeld, en ze door elkaar halen is de meest voorkomende beginnersfout.
| Komt in | De ontvanger… | Komt terug in de callback | |
|---|---|---|---|
| Vooraf invullen | prefill | Ziet het en kan het wijzigen | Ja, als antwoord |
| Vergrendeld veld | prefill + readonly | Ziet het, kan het niet wijzigen | Ja, als antwoord |
| Context | context | Kan het niet wijzigen; ziet het alleen waar je het noemt | Ja, in het aanvraagblok en als antwoord |
| Metadata | metadata | Ziet het nooit, het formulier ook niet | Ja, in het aanvraagblok |
Vooraf invullen
Beginantwoorden voor de zichtbare vragen, zodat de ontvanger controleert en corrigeert in plaats van vanaf nul te typen. Alles wat je al van hen weet hoort hier thuis — de bedrijfsnaam uit je CRM, het bedrag van de factuur, de antwoorden van vorig jaar.
Vergrendelde velden
Zet een vooraf ingevulde sleutel in readonly en de ontvanger ziet de waarde maar kan hem niet wijzigen. Gebruik dit voor de
feiten die ze bevestigen in plaats van aanleveren — het contractnummer, de afgesproken prijs. Vergrendelen is per aanvraag: het formulier
zelf blijft onaangeroerd, en hetzelfde veld is bij de volgende aanvraag weer vrij bewerkbaar.
Elke vergrendelde sleutel moet ook vooraf ingevuld zijn, en een vergrendeld verplicht veld moet vooraf worden ingevuld met iets niet-leegs — anders zou de ontvanger een formulier krijgen dat ze nooit zouden kunnen indienen, en weigert formbase de aanroep in plaats van die val te creëren.
Context
Vertrouwde waarden voor de verborgen velden van het formulier — een dossiernummer, een workflow-run-id, een bedrag. Context voedt variabelen, voorwaardelijke logica, berekende velden en e-mailtekst, komt onveranderd terug in de callback, en de ontvanger kan het niet aanpassen. Dat laatste is het verschil met het vullen van een verborgen veld via een URL op een openbare link, waar iedereen de querystring kan bewerken; aanvraaglinks negeren URL-queryparameters volledig. Contextwaarden moeten een string, getal of boolean zijn.
Context is niet vrij invoerbaar: elke sleutel moet een verborgen veld zijn op de gepubliceerde versie van het formulier, en elke andere
sleutel wordt geweigerd met UNKNOWN_FIELD_KEY. Administratie zonder verborgen veld, zoals een uitvoerings-id, hoort in
metadata.
Verborgen velden worden niet op het formulier getoond, maar een contextwaarde is niet geheim voor de ontvanger. Hij ziet hem overal waar
het formulier of de uitnodiging hem toont: een vermelding in de forminhoud of e-mailtekst,
of een zichtbare vraag die dat verborgen veld als standaardwaarde
gebruikt. In dat laatste geval ziet de ontvanger de contextwaarde vooraf ingevuld in die vraag en kan hij het antwoord bewerken. De
contextwaarde zelf blijft ongewijzigd. Een prefill voor de eigen sleutel van die vraag heeft voorrang boven de
standaardwaarde.
Metadata
Je eigen administratie — een uitvoerings-id, een CRM-record-id. Het bereikt het formulier nooit, dus het kan niet in tekst worden gepiped of door logica worden gelezen; het rijdt gewoon mee en komt terug in elke callback en statusuitlezing.
Waardevormen
Stuur waarden in de vorm die het type uit fields.list vraagt. Een verkeerde vorm komt terug als een
validatiefout die de sleutel, het verwachte type, en — voor keuzevragen — de waarden noemt die geaccepteerd zouden zijn.
| Type | Stuur |
|---|---|
| text, email, phone, url, textarea | Een string |
| number, rating, scale | Een getal |
| switch | true of false |
| date | "2026-03-04" |
| time | "09:30" of "09:30:00" |
| radio, select | De optiesleutel, niet het label |
| checkbox, ranking, picture-choice | Een array van optiesleutels |
| matrix | Een object van rijsleutel naar kolomsleutel: { "row_key": "column_key" } |
| group (herhalend) | Een array van instanties, maximaal 100: [{ "member_key": value }, …] |
| file, signature, payment, schedule-appointment | Niets — de ontvanger levert deze zelf aan |
| elk veld met calculated: true | Niets — het formulier berekent het zelf |
| documents | Niets in prefill — gebruik de optie Documenten hieronder |
Documenten
Een Documentenblok geeft bestanden door aan de ontvanger. De aangeleverde bestanden zijn voor iedereen hetzelfde en blijven altijd staan; een aanvraag voegt bestanden toe voor die ene ontvanger, eronder — het eigen huurcontract van de klant, een kopie van een identiteitsbewijs om te controleren. Bytes reizen nooit mee in de API-aanroep zelf: upload eerst, verwijs daarna.
- 1
Reserveer de upload
Roep documents.create aan met formId, name (1–200 tekens), contentType (PDF of afbeelding), de exacte grootte in bytes, en optioneel een sha256 van het bestand (64 hex-tekens). Je krijgt een id en een uploadUrl terug die één uur geldig is.
- 2
Upload de bytes
PUT het bestand naar uploadUrl met dezelfde Content-Type. Er wordt nog niets geverifieerd.
- 3
Verwijs ernaar op de aanvraag
Geef documents: [{ documentId, name? }] mee aan requests.create. formbase controleert het geüploade object (grootte, bestandssignatuur, sha256 als je die hebt meegestuurd) voordat de aanvraag wordt aangemaakt, en de ontvanger ziet het bestand in het blok.
"documents": [
{ "documentId": "kn7...", "name": "Your lease contract" },
{ "documentId": "kn8..." }
]name overschrijft de weergavenaam die bij de upload is opgeslagen. Heeft het formulier meer dan één documentenblok, dan wijs
je het doel aan met field, de veldsleutel van het blok (fields.list toont die, samen met de vaste documenten die
elke respondent al krijgt). De bestanden komen onder die vaste documenten te staan — een aanvraag voegt bestanden toe, hij vervangt er
nooit een. Eén upload kan door zoveel aanvragen worden aangehaald als je wilt — een prijslijst die je één keer uploadt, bedient
vijfhonderd aanvragen.
Limieten: alleen PDF en afbeeldingen, 25 MB per document, 100 MB per aanvraag (DOCUMENTS_TOO_LARGE), en ten hoogste 20
documenten per blok, de vaste documenten meegeteld (DOCUMENTS_TOO_MANY). De bestanden tellen mee voor je werkruimte-opslag en
komen vrij zodra de aanvragen die ernaar verwijzen buiten het bewaarvenster van het formulier vallen. De inzending registreert de lijst
die de ontvanger onder de veldsleutel van het blok te zien kreeg, dus de callback vertelt je precies welke bestanden deze persoon heeft
gekregen.
De rest van de opties
| Optie | Wat het doet |
|---|---|
| language | De taal waarin het formulier opent en waarin de uitnodiging is geschreven; een van de gepubliceerde talen van het formulier. Weggelaten, dan wordt de standaardtaal van het formulier gebruikt. De ontvanger kan nog steeds van taal wisselen, net als bij een openbare link. |
| delivery | "email" verstuurt de uitnodiging voor je en vereist een e-mailadres van de ontvanger en een Pro- of Business-abonnement, of een van de 10 gratis uitnodigingen van een Free-account; "none" (de standaard) betekent dat je de link zelf aflevert. |
| reminders | Overschrijft het herinneringsschema van het formulier voor deze ene aanvraag met maximaal vijf idle-offsets zoals ["2d", "12h", "30m"], of geef een lege lijst op om herinneringen uit te zetten. Een aangepast schema vereist een e-mailadres van de ontvanger en een Pro- of Business-abonnement; zonder e-mailadres van de ontvanger draait het eigen schema van het formulier gewoon niet. |
| expiresAt | Wanneer de link stopt met werken, als Unix-tijdstempel in milliseconden. Standaard 30 dagen; 365 dagen is het maximum. |
| externalId | Je eigen id voor deze aanvraag. Je kunt er later op filteren. |
| idempotencyKey | Zorgt dat een herhaalde run de bestaande aanvraag hergebruikt in plaats van een tweede aan te maken. |
| callbackUrl | Waar formbase de callback naartoe post zodra de aanvraag eindigt. Alleen HTTPS. |
| domainId | Genereer de link op een van je aangepaste domeinen, in plaats van het domein waarop het formulier al gepubliceerd is. |
| test | Een droogloop: er wordt niets gemaild, de callback meldt test, en de inzending telt nergens mee. Zie hieronder. |
Testmodus
Geef test: true op om de hele bedrading uit te proberen vóór een echte run. Een testaanvraag is echt in alles wat telt voor
de bedrading: de link opent en kan worden afgerond, de callback vuurt zoals gewoonlijk, en
requests.get geeft de antwoorden terug. Wat hij nooit doet, is iemand of iets bereiken dat je achteraf zou moeten opruimen:
Er wordt geen uitnodiging en geen herinnering verstuurd, wat
deliveryook zegt. Herinnering versturen wordt er geweigerd, en hij verbruikt niets van je maandelijkse quotum.De callback draagt
“test”: true, zodat je workflow kan vertakken of het event kan negeren.De inzending wordt opgeslagen maar telt niet mee: niet tegen je maandelijkse quotum (een test wordt afgerond, ook als het quotum op is), en hij verschijnt nooit in de inzendingstelling van het formulier, het tabblad Inzendingen, exports, of je integraties. Niemand wordt op de hoogte gesteld.
De aanvraag is verborgen op de pagina Aanvragen achter Testaanvragen weergeven, weggelaten uit de aanvraagfunnel in Analytics, en weggelaten uit
requests.listtenzij jeincludeTest: trueopgeeft.De link sluit binnen 24 uur, ook als
expiresAtom langer vraagt; deexpiresAtin het antwoord zegt wanneer. Op Free mag een workspace 10 testaanvragen per dag aanmaken. De volgende mislukt metRATE_LIMITEDen redenTEST_REQUEST_LIMIT_REACHED, enretryAfterMszegt wanneer je het opnieuw kunt proberen. Pro en Business hebben geen dagelijkse limiet.
Probeer het zelf in het deelvenster is deze modus met één klik: hij neemt het concept van het tabblad Handmatig over — vooraf invullen, vergrendelingen, context, callback, verloop — richt de aanvraag aan je eigen account, verstuurt geen e-mail, en geeft je de link om zelf te openen.
Wat een aanvraag kost
Elk abonnement heeft één maandelijks quotum dat door beide kanalen wordt gedeeld: een inzending via een deellink
verbruikt één eenheid, en dat doet ook elke aanvraag die je aanmaakt — of de ontvanger nu antwoordt, hem negeert, of je hem annuleert. De
inzending die een aanvraag oplevert is al betaald en telt nergens mee. Free bevat 1.000 eenheden per maand, Pro en Business 50.000; de
telling wordt gereset op de 1e van elke maand, UTC. Bij het bereiken van het quotum mislukt requests.create met
UPGRADE_REQUIRED en reden MONTHLY_ALLOWANCE_REACHED; aanvragen die je al hebt aangemaakt blijven beantwoordbaar.
Op Free verbruikt een aanvraag die met “delivery”: “email” wordt aangemaakt ook een van de
10 gratis uitnodigingen van het account. Ze worden nooit gereset;
zijn ze op, dan mislukt e-mailbezorging met UPGRADE_REQUIRED en reden FREE_INVITATIONS_USED.
Idempotentie
Geef dezelfde idempotencyKey op met dezelfde inhoud en je krijgt de oorspronkelijke aanvraag terug, met
deduplicated: true en de oorspronkelijke link — geen tweede aanvraag, geen tweede e-mail. Hergebruik de sleutel met een
andere inhoud en formbase weigert met IDEMPOTENCY_CONFLICT in plaats van te gokken welke je bedoelde. Sleutels zijn
gebonden aan de werkruimte en blijven 30 dagen geldig; daarna start dezelfde sleutel een nieuwe aanvraag.
In een workflowtool is de uitvoerings-id de natuurlijke sleutel: een run die opnieuw wordt geprobeerd na een netwerkstoring pakt de aanvraag op die al was aangemaakt.
Snelheidslimiet
requests.create en documents.create delen een budget van 60 aanroepen per minuut, geteld per
API-token (of per gebruiker, voor een aanroep zonder token). Een achterstand die je wegwerkt, moet zichzelf temporiseren; een piek boven
het budget wordt geweigerd en kan opnieuw worden geprobeerd.
Aangepaste domeinen
Als het formulier al is gepubliceerd op een van je aangepaste domeinen, worden
aanvraaglinks daar automatisch gegenereerd — https://forms.jouwbedrijf.com/r/rq_…. Geef domainId expliciet op
wanneer het formulier op meer dan één domein is gepubliceerd. Het domein moet tot dezelfde werkruimte behoren als het formulier.
Wat de ontvanger ziet
Precies het formulier dat jij hebt gemaakt — zelfde thema, zelfde logo, zelfde taal — met hun waarden ingevuld, vergrendelde velden alleen-lezen, en geen captcha om op te lossen. Wanneer ze indienen, krijgen ze jouw bedankpagina. Als ze later terugkomen op de link, krijgen ze de uitkomstpagina in plaats van een leeg formulier.
Er staat geen bericht van je automatisering op de pagina. Alles wat de ontvanger moet weten hoort in het formulier zelf, waar je het kunt personaliseren door een contextwaarde of een vooraf ingevuld veld te noemen.
Een AI-agent doorloopt dezelfde twee stappen als fields_list en request_create, met dezelfde opties — documenten
en domainId inbegrepen. Zie Aanvragen op de MCP-server.