# API-methoden

Volledige referentie voor elke REST API-methode met parameters, voorbeelden en responses.

## API-methoden

Volledige referentie voor elke methode die de Formstep REST API aanbiedt. Per methode vind je de parameters, voorbeeldverzoeken en de vorm van de response.

> ℹ️ **Één endpoint, veel methoden**
> <p>
>     Elke methode is <code>POST https://api.formstep.io/api/v1</code> met een JSON-body <code>{`{"method": "...", "params": {...}}`}</code>{' '}
>     en een <code>Authorization: Bearer fb_...</code>-header. Zie <a href="/nl/developers/overview">API-overzicht</a> voor authenticatie en
>     foutafhandeling, en <a href="/nl/developers/api-tokens">API-tokens</a> voor het token zelf.
>   </p>

<h2 id="conventions">Conventies</h2>

<ul>
  <li>
    <code>params</code> mag worden weggelaten; het valt terug op <code>{`{}`}</code>. Een onbekende methode geeft{' '}
    <code>404 METHOD_NOT_FOUND</code>.
  </li>
  <li>
    Een token is gebonden aan <strong>één workspace</strong>. Een andere workspace noemen, of een formulier daarin, is{' '}
    <code>403 FORBIDDEN</code>, zelfs als je tot beide behoort.
  </li>
  <li>
    <strong>Paginering.</strong> Lijstmethoden geven <code>{`{ items, nextCursor, hasMore }`}</code> terug; de meeste geven ook{' '}
    <code>canPaginate</code> terug, wat <code>false</code> is wanneer <code>hasMore</code> true is maar geen cursor verder kan (fuzzy
    search). Geef <code>nextCursor</code> terug als <code>cursor</code>. <code>limit</code> is 1–100, standaard 20 — behalve{' '}
    <code>requests.list</code>, waarvan de standaard 25 is.
  </li>
  <li>
    <strong>Rate limits.</strong> 120 aanroepen per minuut per token, gedeeld met de <a href="/nl/developers/mcp-server">MCP-server</a>;{' '}
    <code>requests.create</code> heeft zijn eigen limiet van 60 per minuut. Mislukte authenticatie wordt apart beperkt, 30 per 15 minuten
    per IP, waarna foute tokens <code>RATE_LIMITED</code> zien in plaats van <code>UNAUTHORIZED</code>.
  </li>
  <li>
    <strong>Bodygrootte.</strong> 1 MiB. Grotere bodies worden geweigerd met <code>VALIDATION_ERROR</code>.
  </li>
  <li>
    <strong>Versiebeheer.</strong> Het pad draagt de versie. Breaking changes verschijnen als <code>/api/v2</code>; nieuwe methoden en
    nieuwe responsevelden niet.
  </li>
</ul>

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="forms">Formulieren</h2>

{/* ── forms.list ──────────────────────────────────────────────────────────── */}

Geeft een lijst van formulieren in een workspace. Ondersteunt cursorpaginering en optioneel fuzzy zoeken op naam.

  
    Workspace-ID.
  
  
    Filter op map. Geef <code>null</code> door voor formulieren op rootniveau. Weglaten om alles te tonen.
  
  
    Fuzzy zoeken op naam. Resultaten zijn begrensd op <code>limit</code>; geen cursorpaginering.
  
  
    Paginagrootte (1–100).
  
  
    Paginacursor van een vorige response.
  

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "forms.list",
    "params": { "workspaceId": "ws_abc123" }
  }'
```

  
    
```
{
  "ok": true,
  "data": {
    "items": [
      {
        "id": "frm_abc123",
        "name": "Contact Form",
        "folderId": null,
        "workspaceId": "ws_abc123",
        "isPublished": true,
        "publishedAt": 1714041851000,
        "unpublishedAt": null,
        "createdAt": 1714041800000,
        "lastEditedAt": 1714042000000,
        "emoji": null
      }
    ],
    "nextCursor": null,
    "hasMore": false,
    "canPaginate": false
  }
}
```

  

{/* ── forms.get ───────────────────────────────────────────────────────────── */}

Haalt volledige details op van een enkel formulier, inclusief vragen, omslag, logo en een voorbeeld-URL.

  
    Formulier-ID.
  

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "forms.get",
    "params": { "formId": "frm_abc123" }
  }'
```

  
    
```
{
  "ok": true,
  "data": {
    "id": "frm_abc123",
    "name": "Event Feedback",
    "folderId": null,
    "workspaceId": "ws_abc123",
    "isPublished": true,
    "publishedAt": 1714041851000,
    "unpublishedAt": null,
    "createdAt": 1714041800000,
    "lastEditedAt": 1714042000000,
    "emoji": null,
    "questions": [
      {
        "id": "q_1",
        "type": "email-input",
        "inputType": "email",
        "title": "Your email",
        "metadata": null
      },
      {
        "id": "q_2",
        "type": "rating-input",
        "inputType": "rating",
        "title": "Overall experience",
        "metadata": { "kind": "rating", "maxStars": 5 }
      }
    ],
    "hasContent": true,
    "cover": null,
    "logo": null,
    "isDeleted": false,
    "trashedAt": null,
    "previewUrl": "https://formstep.io/preview/abc..."
  }
}
```

  

{/* ── forms.create ────────────────────────────────────────────────────────── */}

Maak een nieuw leeg formulier aan. Geeft het formulier en een voorbeeld-URL terug.

  
    Formuliernaam (1–255 tekens).
  
  
    Workspace-ID.
  
  
    Plaats het formulier in een map. Weglaten om op workspace-rootniveau aan te maken.
  

  
    
      
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "forms.create",
    "params": {
      "name": "Contact",
      "workspaceId": "ws_abc123"
    }
  }'
```

    
    
      
```
const res = await fetch('https://api.formstep.io/api/v1', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.FORMSTEP_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    method: 'forms.create',
    params: { name: 'Contact', workspaceId: 'ws_abc123' },
  }),
})
const { ok, data } = await res.json()
```

    
    
      
```
import os, requests
res = requests.post(
  "https://api.formstep.io/api/v1",
  headers={"Authorization": f"Bearer {os.environ['FORMSTEP_TOKEN']}"},
  json={
    "method": "forms.create",
    "params": {
      "name": "Contact",
      "workspaceId": "ws_abc123",
    },
  },
)
data = res.json()
```

  

  
    
```
{
  "ok": true,
  "data": {
    "id": "frm_new123",
    "name": "Contact",
    "workspaceId": "ws_abc123",
    "folderId": null,
    "isPublished": false,
    "createdAt": 1714041851000,
    "previewUrl": "https://formstep.io/preview/abc..."
  }
}
```

  

{/* ── forms.update ────────────────────────────────────────────────────────── */}

Werk formuliermetadata bij: naam, map, emoji, omslag of logo. Werkt de formulierinhoud niet bij (gebruik daarvoor de editor-tools).

  
    Formulier-ID.
  
  
    Nieuwe formuliernaam (1–255 tekens).
  
  
    Verplaats het formulier naar een map. Geef <code>null</code> door om naar workspace-root te verplaatsen.
  
  
    Formulier-emoji (max. 10 tekens). Geef <code>null</code> door om te wissen.
  
  
    Omslag. <code>{`{"type": "color", "color": "#ffffff"}`}</code>, <code>{`{"type": "image", "url": "https://...", "offsetY": 50}`}</code>{' '}
    (<code>offsetY</code> 0–100, standaard 50), of <code>{`{"type": "none"}`}</code> om te verwijderen. Afbeelding-URL's moeten{' '}
    <code>http(s)</code> zijn of een <code>data:image</code>-URI.
  
  
    Logo. <code>{`{"type": "icon", "name": "HeartIcon"}`}</code>, <code>{`{"type": "image", "url": "https://..."}`}</code>, of{' '}
    <code>{`{"type": "none"}`}</code> om te verwijderen. Iconnamen liggen vast: <code>QuestionMarkIcon</code>, <code>ListBulletsIcon</code>,{' '}
    <code>ChartBarIcon</code>, <code>ClockCountdownIcon</code>, <code>HeartIcon</code>, <code>LightbulbIcon</code>,{' '}
    <code>CheckCircleIcon</code>, <code>MagnifyingGlassIcon</code>, <code>TrendUpIcon</code>, <code>EnvelopeIcon</code>,{' '}
    <code>PhoneIcon</code>, <code>CalendarIcon</code>, <code>LinkIcon</code>, <code>UsersIcon</code>.
  

<p>Geef minstens één van de vijf bij te werken velden mee. Dit wijzigt de formulierinhoud niet — gebruik daarvoor de MCP-editor-tools.</p>

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "forms.update",
    "params": {
      "formId": "frm_abc123",
      "name": "Updated Name",
      "emoji": "📋"
    }
  }'
```

  
    
```
{
  "ok": true,
  "data": {
    "id": "frm_abc123",
    "name": "Updated Name",
    "folderId": null,
    "emoji": "📋"
  }
}
```

  

<p>
  <code>cover</code> en <code>logo</code> komen alleen terug wanneer je ze hebt meegestuurd. Een payload die op elk scalair veld al
  overeenkwam met de huidige staat voegt <code>noChange: true</code> toe.
</p>

{/* ── forms.publish ───────────────────────────────────────────────────────── */}

Publiceer een formulier zodat het reacties kan ontvangen, en bevries de [veldsleutels](/nl/requests/field-keys) ervan in een nieuwe snapshot.
Idempotent: een al gepubliceerd formulier geeft succes terug met `alreadyPublished: true`, en een gedepubliceerd formulier wordt opnieuw
gepubliceerd vanaf zijn laatste snapshot.

  
    Formulier-ID.
  

<p>
  Een formulier met inhoudsblokken maar geen vragen publiceert met een waarschuwing. Een formulier zonder enige inhoud kan niet worden
  gepubliceerd. Publiceren maakt geen openbare URL aan — roep daarvoor <a href="#share-links-create">shareLinks.create</a> aan.
</p>

{/* ── forms.unpublish ─────────────────────────────────────────────────────── */}

Haal een formulier offline. Respondenten kunnen het niet meer openen. Idempotent — een formulier dat niet is gepubliceerd geeft
`alreadyUnpublished: true` terug. Omkeerbaar met `forms.publish`.

  
    Formulier-ID.
  

{/* ── forms.delete ────────────────────────────────────────────────────────── */}

Verplaats een formulier naar de prullenbak. De actieve deellinks ervan worden ingetrokken, zodat hun openbare URL's stoppen met werken.

  
    Formulier-ID.
  

> ⚠️ **Herstellen brengt de links niet terug**
> <p>
>     <code>forms.restore</code> geeft het formulier terug, maar de deellinks die het introk blijven ingetrokken. Genereer nieuwe met{' '}
>     <code>shareLinks.create</code>. Een formulier dat al in de prullenbak zit geeft <code>alreadyTrashed: true</code> terug en behoudt zijn
>     oorspronkelijke verwijderdatum.
>   </p>

{/* ── forms.restore ───────────────────────────────────────────────────────── */}

Herstel een formulier uit de prullenbak.

  
    Formulier-ID.
  
  
    Waar het formulier hersteld wordt. Weglaten voor de oorspronkelijke map, <code>null</code> voor workspace-root, of een map-ID.
  

<p>
  Een formulier dat niet in de prullenbak zit geeft <code>alreadyRestored: true</code> terug.
</p>

{/* ── formSettings.get ────────────────────────────────────────────────────── */}

Lees de gedragsinstellingen van een formulier.

  
    Formulier-ID.
  

<p>
  Geeft <code>{`{ settings, isDefault, availableEmailDomains, defaultFromAddress, payment }`}</code> terug. <code>isDefault</code> is true
  wanneer het formulier nog geen opgeslagen instellingenrij heeft en je de standaardwaarden ziet. <code>availableEmailDomains</code> bevat
  de geverifieerde domein-ids die je kunt meegeven als <code>emailDomainId</code>, en <code>payment</code> meldt of Stripe is gekoppeld
  (koppelen is een stap in het dashboard).
</p>

{/* ── formSettings.update ─────────────────────────────────────────────────── */}

Werk de gedragsinstellingen van een formulier bij. Een gedeeltelijke update: alleen de velden die je meestuurt worden geschreven.

  
    Formulier-ID.
  
  
    <code>language</code> (BCP-47, standaard <code>"en"</code>), <code>requireAuthentication</code>, <code>showBranding</code>,{' '}
    <code>captchaEnabled</code>, <code>passwordEnabled</code>, <code>password</code> (4 tekens of meer; een string impliceert{' '}
    <code>passwordEnabled: true</code>, <code>null</code> heft de vergrendeling op).
  
  
    <code>notifyOnSubmission</code>, <code>notificationEmails</code> (array), <code>selfNotificationSubject</code>,{' '}
    <code>selfNotificationEmailBody</code>, <code>pdfGenerationEnabled</code>, <code>showViewSubmissionButton</code>. E-mails aan de
    eigenaar zijn niet vertaalbaar — schrijf ze in de taal die je wilt.
  
  
    <code>respondentNotificationEnabled</code>, <code>respondentNotificationTo</code>, het veld-id van een e-mailvraag of <code>null</code>,{' '}
    <code>respondentNotificationSubject</code>, <code>respondentNotificationBody</code>, <code>respondentNotificationPdfEnabled</code>.
  
  
    <code>respondentReminderEnabled</code>, <code>respondentReminderTo</code>, <code>respondentReminderSubject</code>,{' '}
    <code>respondentReminderBody</code>, <code>respondentReminderRequiredFieldIds</code>, en <code>reminderSteps</code> —
    inactiviteitsstappen zoals <code>["1d","3d","1w"]</code>, maximaal 5, gesorteerd en ontdubbeld bij opslaan, <code>[]</code> voor geen.
    Het schema geldt zowel voor verlaten reacties via een openbare link als voor aanvragen. Pro.
  
  
    <code>redirectUrl</code> (<code>http(s)</code>; <code>null</code> of <code>""</code> wist het), <code>redirectQueryParams</code> (
    <code>{`[{ paramName, fieldId }]`}</code>), <code>allowAnotherResponse</code> (sluit een omleiding wederzijds uit),{' '}
    <code>maxSubmissionsPerRespondent</code> (0 = onbeperkt, max. 1000), <code>editAfterSubmit</code>, <code>maxEdits</code> (max. 3; 0
    betekent onbeperkt bij Pro en Business, 3 bij Free).
  
  
    <code>draftRetentionDays</code> en <code>submissionRetentionDays</code> (0–36500, <code>null</code> valt terug op de standaardwaarde).
    Bewaring van inzendingen is Business, en het instellen ervan wist elke vaste verwijderdatum die in de builder is geconfigureerd.
  
  
    Een geverifieerd e-maildomein-id uit <code>formSettings.get</code>, voor een aangepast afzenderadres. <code>null</code> zet terug naar
    de standaardafzender.
  

<p>
  Onderwerpen en teksten zijn platte tekst en accepteren <code>{`{{variable}}`}</code>-plaatshouders; nieuwe regels worden alinea's. Een
  onderwerp of tekst voor respondenten aanpassen maakt het vertaalbaar, dus de sleutels ervan verschijnen meteen in{' '}
  <code>translations.listEntries</code>.
</p>

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="submissions" class="border-t border-border pt-8">
  Inzendingen
</h2>

{/* ── submissions.list ────────────────────────────────────────────────────── */}

Geeft de inzendingen van een formulier weer, nieuwste pagina eerst, met cursorpaginering.

  
    Formulier-ID.
  
  
    Reacties meenemen die zijn gestart maar nooit ingediend. Concepten zijn een Pro-functie: op Free worden alleen voltooide inzendingen
    weergegeven.
  
  
    Voeg opgeslagen AI-vertalingen van de antwoorden toe onder <code>items[].translation.display</code>, met dezelfde sleutels als{' '}
    <code>display</code>. <code>items[].answers</code> en <code>items[].display</code> blijven altijd het origineel.
  
  
    Paginagrootte (1–100).
  
  
    Pagineringscursor uit een vorige response.
  

  
    
```
{
  "ok": true,
  "data": {
    "formId": "frm_abc123",
    "formName": "Event Feedback",
    "items": [
      {
        "id": "sub_xyz789",
        "submittedAt": "2026-05-18 18:02:28",
        "isCompleted": true,
        "createdAt": "2026-05-18 18:02:19",
        "answers": {
          "email": "user@example.com",
          "plan": "pro",
          "contacts": [{ "name": "Ada" }, { "name": "Grace" }]
        },
        "display": {
          "email": "user@example.com",
          "plan": "Pro",
          "contacts": "Ada, Grace"
        }
      }
    ],
    "nextCursor": null,
    "hasMore": false,
    "canPaginate": false
  }
}
```

  

> ℹ️ **Dezelfde antwoorden als webhooks en callbacks**
> <p>
>     Elk item draagt <code>answers</code> geordend op <a href="/nl/requests/field-keys">veldsleutel</a> en <code>display</code> met dezelfde
>     sleutels, als leesbare tekst — de vorm die een <a href="/nl/developers/webhooks-reference">webhookpayload</a>, een{' '}
>     <a href="/nl/requests/callbacks">aanvraagcallback</a> en <code>requests.get</code> dragen. Een keuzeantwoord is zijn optiesleutel, een
>     herhalende groep een array van instanties. Roep <code>fields.list</code> aan voor de titel en optielabels van elke sleutel. Deze methode
>     geeft geen totalen terug.
>   </p>

{/* ── submissions.pdf ─────────────────────────────────────────────────────── */}

Haal een link op naar de PDF van één inzending. Gebouwd voor de Zapier-connector: het geeft alleen een resultaat terug wanneer het
formulier een actieve Zapier-integratie heeft die is ingesteld om de PDF mee te sturen, en de PDF is bewaard.

  
    Formulier-ID.
  
  
    Inzending-ID. Moet bij dat formulier horen en voltooid zijn.
  

  
    
```
{
  "ok": true,
  "data": {
    "url": "https://api.formstep.io/api/storage/...",
    "filename": "formstep-submission-sub_xyz789.pdf",
    "contentType": "application/pdf",
    "byteLength": 148213
  }
}
```

  

{/* ── submissions.sample ──────────────────────────────────────────────────── */}

Bouw een voorbeeld-inzendingspayload voor een formulier, zonder echte data. Het is precies de vorm die een levering van een inzending via
een openbare link draagt, dus connectors gebruiken het voor velddetectie; een inzending die uit een aanvraag voortkomt, bereikt een
abonnement in plaats daarvan als <code>request.completed</code>, en die bouw je met <a href="#requests-sample">requests.sample</a>.{' '}

<code>data.form.snapshotId</code> is de huidige gepubliceerde versie van het formulier, hetzelfde id dat live events dragen, of
<code>null</code> zolang het formulier ongepubliceerd is.

  
    Formulier-ID.
  

  
    
```
{
  "ok": true,
  "data": {
    "id": "evt_example000000000000",
    "type": "submission.completed",
    "createdAt": "2026-05-18T19:00:00.000Z",
    "apiVersion": "2026-09-24",
    "test": true,
    "data": {
      "form": { "id": "frm_abc123", "name": "Event Feedback", "snapshotId": "js7abc123" },
      "submission": {
        "id": "sub_example000000000000",
        "respondentEmail": "respondent@example.com",
        "submittedAt": "2026-05-18T19:00:00.000Z",
        "updatedAt": null,
        "editCount": 0,
        "pdfUrl": null,
        "language": "en"
      },
      "answers": { "your_email": "john@example.com" },
      "display": { "your_email": "john@example.com" }
    }
  }
}
```

  

<p>
  Veld- en payloadsemantiek staan één keer gedocumenteerd: de <a href="/nl/developers/webhooks-reference#payload">webhooks-referentie</a>{' '}
  beschrijft ze.
</p>

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="share-links" class="border-t border-border pt-8">
  Deellinks
</h2>

{/* ── shareLinks.list ─────────────────────────────────────────────────────── */}

Geeft een lijst van deellinks voor een formulier.

  
    Formulier-ID.
  
  
    Neem ingetrokken links op in het resultaat.
  
  
    Paginagrootte (1–100).
  
  
    Paginacursor.
  

  
    
```
{
  "ok": true,
  "data": {
    "items": [
      {
        "id": "sl_abc123",
        "code": "RPjNes52",
        "url": "https://formstep.io/RPjNes52",
        "customDomainUrl": null,
        "formId": "frm_abc123",
        "createdAt": 1714041851000,
        "expiresAt": null,
        "maxClaims": null,
        "claimedCount": 7,
        "isRevoked": false,
        "revokedAt": null,
        "customDomainId": null,
        "customSlug": null
      }
    ],
    "availableCustomDomains": [],
    "nextCursor": null,
    "hasMore": false,
    "canPaginate": false
  }
}
```

  

{/* ── shareLinks.create ───────────────────────────────────────────────────── */}

Maak een deellink aan voor een formulier. Het formulier moet eerst gepubliceerd zijn.

  
    Formulier-ID. Een formulier dat niet gepubliceerd is, of gepubliceerd was en daarna gedepubliceerd, wordt geweigerd — roep eerst{' '}
    <code>forms.publish</code> aan.
  
  
    Vervaldatum als toekomstig Unix-tijdstempel in milliseconden. In tegenstelling tot bij update wordt <code>0</code> hier niet
    geaccepteerd.
  
  
    Maximum aantal keren dat deze link gebruikt kan worden. Moet positief zijn; gebruik <code>shareLinks.update</code> om de limiet later te
    verwijderen.
  

<p>
  De response is de deellink (dezelfde vorm als een item van <code>shareLinks.list</code>) plus <code>availableCustomDomains</code>, zodat
  je kunt vervolgen met <code>shareLinks.update</code> om er een te koppelen.
</p>

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "shareLinks.create",
    "params": {
      "formId": "frm_abc123",
      "maxClaims": 100
    }
  }'
```

{/* ── shareLinks.update ───────────────────────────────────────────────────── */}

Werk een deellink bij. Je kunt de vervaldatum, het maximum aantal claims, het aangepaste domein, de slug wijzigen of de link intrekken.

  
    Deellink-ID.
  
  
    Nieuw vervaltijdstempel in milliseconden. Geef <code>0</code> door om de vervaldatum te verwijderen.
  
  
    Nieuw maximum aantal claims. Geef <code>-1</code> door om de limiet te verwijderen.
  
  
    Koppel een aangepast domein. Geef <code>null</code> door om te ontkoppelen.
  
  
    Aangepaste URL-slug (3–64 tekens, kleine letters, cijfers en koppeltekens). Verplicht samen met <code>customDomainId</code>; geef beide{' '}
    <code>null</code> door om te ontkoppelen. <code>login</code>, <code>auth-callback</code>, <code>preview</code>, <code>payment</code>,{' '}
    <code>api</code>, <code>admin</code> en <code>health</code> zijn gereserveerd.
  
  
    Stel in op <code>true</code> om de link permanent in te trekken. Kan niet worden gecombineerd met andere velden, en kan niet ongedaan
    worden gemaakt — dit is het enige verwijderpad voor een deellink.
  

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="fields" class="border-t border-border pt-8">
  Velden
</h2>

{/* ── fields.list ─────────────────────────────────────────────────────────── */}

Geef elk veld van de huidige gepubliceerde versie van een formulier terug, met de sleutel om het aan te spreken. Roep dit aan vóór
`requests.create` in plaats van sleutels hard te coderen. Zie [Veldsleutels](/nl/requests/field-keys).

  
    Formulier-id. Een formulier dat nog nooit is gepubliceerd, heeft nog geen veldsleutels en geeft <code>published: false</code> terug,
    zonder items.
  

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -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": "satisfaction", "type": "matrix", "title": "How did we do?", "required": false, "prefillable": true,
        "rows": [{ "key": "delivery_speed", "label": "Delivery speed" }],
        "columns": [{ "key": "very_good", "label": "Very good" }, { "key": "poor", "label": "Poor" }]
      },
      { "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 }
    ],
    "hasMore": false
  }
}
```

  

> ℹ️ **De vlaggen lezen**
> <p>
>     <code>context: true</code> is een verborgen veld — de waarde hoort in <code>context</code>, nooit in <code>prefill</code>.{' '}
>     <code>prefillable: false</code> markeert een veld waarvoor niemand een waarde kan opgeven (bestand, handtekening, betaling, afspraak,
>     documenten). Stuur voor een keuzevraag de <strong>sleutel</strong> van de optie, niet het label; een matrix somt zijn <code>rows</code>{' '}
>     en <code>columns</code> op dezelfde manier op en neemt <code>{'{ "row_key": "column_key" }'}</code>. <code>calculated: true</code> is
>     een berekend veld: het formulier berekent de waarde, je leest die terug in <code>answers</code>, en niets kan het versturen.
>   </p>

<p>
  Een herhalende groep is <code>type: "group"</code> met <code>repeating: true</code> en een <code>members</code>-array. Een Documentenblok
  is <code>type: "documents"</code> en draagt <code>documents: [{`{ name }`}]</code>, de aangeleverde bestanden die elke respondent al ziet.
</p>

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="requests" class="border-t border-border pt-8">
  Aanvragen
</h2>

Een aanvraag wijst één gepubliceerd formulier toe aan één persoon en roept je terug wanneer hij eindigt. De conceptuele uitleg staat in
[Een aanvraag maken](/nl/requests/creating-requests); dit is de parameterlijst.

{/* ── requests.create ─────────────────────────────────────────────────────── */}

Maak een aanvraag aan. Verbruikt één eenheid van het maandelijkse quotum van de werkruimte, of de ontvanger nu antwoordt of niet.

  
    Het gepubliceerde formulier om toe te wijzen.
  
  
    <code>{`{ email?, name? }`}</code>. Een e-mailadres is verplicht wanneer <code>delivery</code> <code>"email"</code> is; anders
    identificeert het alleen de persoon op de pagina Aanvragen en bij hun antwoorden.
  
  
    Beginantwoorden per veldsleutel. De ontvanger ziet ze en kan ze wijzigen.
  
  
    Vooraf ingevulde sleutels die de ontvanger niet kan wijzigen. Elke sleutel hier moet ook voorkomen in <code>prefill</code>, en een
    vergrendeld verplicht veld moet worden vooraf ingevuld met een niet-lege waarde.
  
  
    Waarden voor de verborgen velden van het formulier, per veldsleutel. Vertrouwd, niet te wijzigen, en teruggegeven in de callback. Een
    onbekende sleutel wordt geweigerd met <code>UNKNOWN_FIELD_KEY</code>.
  
  
    Je eigen administratie. Bereikt het formulier nooit; komt terug in callbacks en uitlezingen.
  
  
    Een van de gepubliceerde talen van het formulier. Standaard de eigen standaardtaal van het formulier.
  
  
    <code>"email"</code> om Formstep de uitnodiging te laten versturen (vereist een e-mailadres van de ontvanger, en Pro of Business of een
    van de 10 gratis uitnodigingen van een Free-account), of <code>"none"</code> om de link zelf af te leveren.
  
  
    Overschrijft het herinneringsschema van het formulier voor deze aanvraag. Een lege array zet herinneringen uit.
  
  
    Epoch-milliseconden. Standaard 30 dagen; 365 dagen is het maximum.
  
  
    Waar Formstep de callback naartoe post zodra de aanvraag eindigt. Alleen HTTPS, en de host moet naar een openbaar adres wijzen.
  
  
    Je eigen id voor deze aanvraag. Filterbaar in <code>requests.list</code>.
  
  
    Herhalen met dezelfde body geeft de oorspronkelijke aanvraag terug met <code>deduplicated: true</code>. Een andere body wordt geweigerd.
    Sleutels blijven 30 dagen geldig.
  
  
    Genereer de link op een van je aangepaste domeinen. Alleen REST API.
  
  
    <code>{`[{ documentId, field?, name? }]`}</code> — bestanden voor deze ene ontvanger, eerst geüpload met <code>documents.create</code>.
  
  
    Een droogloop: er wordt niets gemaild, de callback draagt <code>"test": true</code>, en de inzending telt nergens mee. De link sluit
    binnen 24 uur, en op Free mag een workspace 10 testaanvragen per dag aanmaken.
  

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "requests.create",
    "params": {
      "formId": "j57...",
      "recipient": { "email": "ada@acme.com", "name": "Ada" },
      "prefill": { "company_name": "Acme" },
      "readonly": ["company_name"],
      "context": { "case_id": "CASE-9" },
      "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.formstep.io/r/rq_...",
    "deliveryStatus": "queued",
    "expiresAt": 1794787200000,
    "createdAt": 1789379200000,
    "externalId": "run-42",
    "deduplicated": false
  }
}
```

  

> ⚠️ **Bewaar de url**
> <p>
>     <code>url</code> draagt het eenmalige token. <code>requests.get</code> kan hem meestal opnieuw opbouwen, maar hij komt terug als{' '}
>     <code>null</code> voor een aanvraag die is aangemaakt voordat de deployment een aanvraagtoken-sleutel had. Lever je de link zelf af,
>     bewaar hem dan bij het aanmaken.
>   </p>

<p>
  <code>deliveryStatus</code> is <code>not_requested</code> tot een uitnodiging in de wachtrij staat, dan <code>queued</code> →{' '}
  <code>sent</code> of <code>failed</code>, en <code>bounced</code> zodra de mailprovider een harde bounce of een klacht meldt.
</p>

{/* ── requests.get ────────────────────────────────────────────────────────── */}

Haal één aanvraag volledig op: status, uitkomst, wat er vooraf is ingevuld, zijn tijdlijn, en — zodra voltooid — <code>answers</code> en <code>display</code> gesorteerd op veldsleutel, dezelfde twee kaarten die de callback draagt.

  
    Aanvraag-id.
  

  
    
```
{
  "ok": true,
  "data": {
    "id": "kd7...",
    "formId": "j57...",
    "status": "completed",
    "outcome": "approve",
    "isTest": false,
    "recipient": { "email": "ada@acme.com", "name": "Ada" },
    "language": "en",
    "externalId": "run-42",
    "metadata": null,
    "context": { "case_id": "CASE-9" },
    "prefill": { "company_name": "Acme" },
    "readonlyKeys": ["company_name"],
    "delivery": "email",
    "deliveryStatus": "sent",
    "hasCallback": true,
    "callbackFailedAt": null,
    "submissionId": "kp2...",
    "url": "https://form.formstep.io/r/rq_...",
    "answers": { "company_name": "Acme", "decision": "approve" },
    "display": { "company_name": "Acme", "decision": "Approve" },
    "timeline": [
      { "id": "kd7...:created", "type": "created", "at": 1789379200000 },
      { "id": "kd7...:completed", "type": "completed", "at": 1789465600000 }
    ],
    "expiresAt": 1794787200000,
    "completedAt": 1789465600000
  }
}
```

  

> ℹ️ **outcome versus status**
> <p>
>     <code>status</code> zegt of de aanvraag is afgerond; <code>outcome</code> zegt wat de ontvanger besliste — <code>approve</code>,{' '}
>     <code>decline</code>, <code>changes</code>, of <code>null</code> bij alles behalve een voltooide aanvraag waarvan de ontvanger één van
>     de drie koos — inclusief een formulier zonder <a href="/nl/requests/decisions-and-approvals">beslissingsvraag</a>. De callback-URL zelf
>     wordt nooit teruggegeven; <code>hasCallback</code> zegt alleen of er één is ingesteld.
>   </p>

<p>
  Het bovenstaande voorbeeld is ingekort. Een volledige response draagt ook <code>workspaceId</code>, <code>formSnapshotId</code>,{' '}
  <code>createdVia</code>, <code>documents</code>, <code>reminderStep</code>, <code>remindersSent</code>, <code>reminderDueAt</code>,{' '}
  <code>dataPurgedAt</code>, en de rest van de tijdstempels (<code>updatedAt</code>, <code>openedAt</code>, <code>startedAt</code>,{' '}
  <code>lastActivityAt</code>, <code>expiredAt</code>, <code>canceledAt</code>, <code>canceledBy</code>, <code>cancelReason</code>).
</p>
<p>
  Twee velden vertellen je wanneer de kopie voor je neus de enige kopie is. <code>callbackFailedAt</code> is ingesteld terwijl de callback
  van deze aanvraag geen pogingen meer over heeft, en wordt gewist zodra er één doorkomt of je hem opnieuw afspeelt.{' '}
  <code>dataPurgedAt</code> is ingesteld zodra bewaarbeleid de aanvraag heeft gestript: <code>context</code>, <code>prefill</code> en{' '}
  <code>metadata</code> komen leeg terug, <code>readonlyKeys</code> en <code>documents</code> zijn <code>[]</code>, en{' '}
  <code>submissionId</code>, <code>answers</code> en <code>display</code> zijn <code>null</code>.
</p>
<p>
  <code>timeline</code> is afgeleid, oudste eerst. Elk item heeft een <code>id</code>, een <code>at</code>, en een <code>type</code> —{' '}
  <code>created</code>, <code>invitation</code>, <code>reminder</code>, <code>opened</code>, <code>started</code>, <code>completed</code>,{' '}
  <code>expired</code>, <code>canceled</code>, <code>callback</code>. Bezorgitems voegen <code>deliveryStatus</code> en{' '}
  <code>attemptCount</code> toe, en callbacks voegen <code>eventType</code> toe. Bezorgrijen worden 30 dagen bewaard, dus oudere tijdlijnen
  dunnen uit tot de tijdstempels.
</p>

{/* ── requests.list ───────────────────────────────────────────────────────── */}

Geef aanvragen in een werkruimte of van één formulier terug, nieuwste eerst. Testaanvragen worden weggelaten tenzij je erom vraagt.

  
    Beperk tot een werkruimte. Geef dit of <code>formId</code> mee.
  
  
    Beperk tot één formulier.
  
  
    <code>pending</code>, <code>completed</code>, <code>expired</code>, of <code>canceled</code>.
  
  
    <code>approve</code>, <code>decline</code>, of <code>changes</code>. Impliceert alleen voltooide aanvragen.
  
  
    Je eigen id, om de aanvraag te vinden die een run heeft aangemaakt.
  
  
    Neem aanvragen op die zijn aangemaakt met <code>test: true</code>.
  
  
    Paginagrootte (1–100).
  
  
    Paginatiecursor van een vorige respons.
  

  
    
```
{
  "ok": true,
  "data": {
    "items": [
      {
        "id": "kd7...",
        "formId": "j57...",
        "status": "pending",
        "outcome": null,
        "recipient": { "email": "ada@acme.com", "name": "Ada" },
        "externalId": "run-42",
        "deliveryStatus": "sent",
        "expiresAt": 1794787200000,
        "createdAt": 1789379200000
      }
    ],
    "nextCursor": null,
    "hasMore": false
  }
}
```

  

<p>
  Items in de lijst dragen dezelfde velden als <code>requests.get</code> minus <code>url</code>, <code>answers</code>, <code>display</code>,
  en <code>timeline</code>, en elk item draagt <code>isTest</code>. Geef <code>workspaceId</code> of <code>formId</code> mee — geen van
  beide geeft <code>400 VALIDATION_ERROR</code> met reden <code>SCOPE_REQUIRED</code>. <code>outcome</code> overschrijft <code>status</code>{' '}
  omdat alleen een voltooide aanvraag een oordeel heeft.
</p>

{/* ── requests.cancel ─────────────────────────────────────────────────────── */}

Trek een aanvraag in behandeling in. De link stopt met werken, de ontvanger ziet een intrekkingsmelding, en er vuurt een
`request.canceled`-callback af.

  
    Aanvraag-id.
  
  
    Je eigen notitie over waarom, bewaard op de aanvraag en meegestuurd in de callback.
  

{/* ── requests.remind ─────────────────────────────────────────────────────── */}

Mail de ontvanger nu, zonder het herinneringsschema aan te raken. Vereist een e-mailadres van de ontvanger en een Pro- of
Business-abonnement.

  
    Aanvraag-id. Moet nog in behandeling zijn, en geen testaanvraag.
  

<p>
  Er gelden twee ondergrenzen: minstens 10 minuten tussen handmatige herinneringen, en maximaal 8 herinneringen per aanvraag in totaal,
  handmatig en gepland samen. Het automatische schema blijft ongemoeid — <code>reminderStep</code> en <code>reminderDueAt</code> blijven
  zoals ze waren.
</p>

{/* ── requests.replayCallback ─────────────────────────────────────────────── */}

Stuur de callback die een aanvraag afvuurde bij het eindigen opnieuw — dezelfde payload, hetzelfde gebeurtenis-id, zodat een ontvanger die
hem al verwerkte kan dedupliceren. Gebruik dit nadat je een kapot endpoint hebt gerepareerd.

  
    Aanvraag-id. Moet voltooid, verlopen, of geannuleerd zijn.
  

  
    
```
{
  "ok": true,
  "data": { "dispatchId": "kf9...", "eventId": "evt_kf9..." }
}
```

  

{/* ── requests.sample ─────────────────────────────────────────────────────── */}

Bouw een voorbeeld van een aanvraag-event voor een formulier, zonder een echte aanvraag. Het is precies de envelop die een{' '}

<code>request\_\*</code>-abonnement, aangemaakt met <a href="#webhooks-create">webhooks.create</a>, ontvangt, dus connectors gebruiken het
voor velddetectie. Een voltooid voorbeeld draagt dezelfde voorbeeldantwoorden die <a href="#submissions-sample">submissions.sample</a>
toont; een verlopen of geannuleerd voorbeeld draagt alleen het aanvraagblok.

  
    Formulier-ID.
  
  
    Welke afloop je als voorbeeld wilt opvragen, in de spelling van <code>webhooks.create</code>. Het <code>type</code> van de envelop is de
    vorm met punten.
  

  
    
```
{
  "ok": true,
  "data": {
    "id": "evt_example000000000000",
    "type": "request.completed",
    "createdAt": "2026-05-18T19:00:00.000Z",
    "apiVersion": "2026-09-24",
    "test": true,
    "data": {
      "request": {
        "id": "req_example000000000000",
        "externalId": "order-1234",
        "status": "completed",
        "language": "en",
        "recipient": { "email": "recipient@example.com", "name": "Sample Recipient" },
        "metadata": { "source": "sample" },
        "context": {},
        "createdAt": "2026-05-18T18:00:00.000Z",
        "completedAt": "2026-05-18T19:00:00.000Z"
      },
      "form": { "id": "frm_abc123", "name": "Event Feedback", "snapshotId": "js7abc123" },
      "submission": {
        "id": "sub_example000000000000",
        "respondentEmail": "respondent@example.com",
        "submittedAt": "2026-05-18T19:00:00.000Z",
        "updatedAt": null,
        "editCount": 0,
        "pdfUrl": null,
        "language": "en"
      },
      "answers": { "your_email": "john@example.com" },
      "display": { "your_email": "john@example.com" }
    }
  }
}
```

  

<p>
  Het aanvraagblok en de uitkomst staan gedocumenteerd op de <a href="/nl/requests/callbacks#payload">pagina Callbacks</a>; de
  inzendingshelft op de <a href="/nl/developers/webhooks-reference#payload">webhooks-referentie</a>. Voorbeeld-ids zijn de vaste
  placeholders die hierboven getoond worden en <code>test</code> is <code>true</code>, zodat een ontvanger een voorbeeld van een live event
  kan onderscheiden.
</p>

{/* ── documents.create ────────────────────────────────────────────────────── */}

Reserveer een upload voor een bestand dat je aan één ontvanger geeft via het [Documentenblok](/nl/building-forms/documents-block) van het
formulier. Bytes reizen nooit via deze API: je krijgt een presigned `PUT`, je uploadt, en `requests.create` verifieert het object voordat de
aanvraag bestaat.

  
    Het formulier waarvan het Documentenblok het bestand toont. Scopet de upload naar die workspace.
  
  
    Weergavenaam die de ontvanger ziet (1–200 tekens). Overschrijfbaar per aanvraag.
  
  
    <code>application/pdf</code> of een afbeeldingstype: <code>image/png</code>, <code>image/jpeg</code>, <code>image/webp</code>,{' '}
    <code>image/gif</code>, <code>image/svg+xml</code>, <code>image/avif</code>, <code>image/bmp</code>, <code>image/tiff</code>.
    Office-documenten worden niet geaccepteerd.
  
  
    Exacte bytelengte. Maximaal 25 MB (26.214.400).
  
  
    Hex-samenvatting van de bytes. Wordt na upload geverifieerd indien meegegeven.
  

  
    
```
{
  "ok": true,
  "data": {
    "id": "kn7...",
    "name": "Lease contract draft",
    "contentType": "application/pdf",
    "size": 412000,
    "uploadUrl": "https://...",
    "expiresAt": 1792198800000
  }
}
```

  

<p>
  <code>PUT</code> de ruwe bytes naar <code>uploadUrl</code> binnen het uur, met <code>Content-Type</code> ingesteld op het type dat je hebt
  opgegeven, en verwijs dan naar het id vanuit <code>requests.create</code>:
</p>

```
{
  "method": "requests.create",
  "params": {
    "formId": "j57...",
    "documents": [
      { "documentId": "kn7...", "name": "Your lease contract" },
      { "documentId": "kn8...", "field": "attachments" }
    ]
  }
}
```

<ul>
  <li>
    <code>field</code> is de veldsleutel van het Documentenblok. Optioneel wanneer het formulier precies één blok heeft; verplicht bij twee
    of meer.
  </li>
  <li>De aangeleverde documenten van het blok blijven staan; die van jou verschijnen eronder, alleen voor deze ene ontvanger.</li>
  <li>Limieten: 25 MB per document, 100 MB aan documenten per aanvraag, 20 documenten getoond per blok inclusief de aangeleverde.</li>
  <li>
    Eén upload kan door elk aantal aanvragen worden gerefereerd. Een upload waarnaar niemand verwijst, vervalt na verloop van tijd. Bytes
    tellen mee voor de opslag van de werkruimte-eigenaar totdat de laatste aanvraag die ernaar verwijst door bewaarbeleid wordt gestript.
  </li>
</ul>

<p>
  Elke fout hier is <code>400 VALIDATION_ERROR</code> met een <code>details.reason</code>: <code>DOCUMENT_TYPE_NOT_ALLOWED</code>,{' '}
  <code>DOCUMENT_TOO_LARGE</code>, <code>INVALID_DOCUMENT_NAME</code> of <code>INVALID_DOCUMENT_SHA256</code> van deze methode, en{' '}
  <code>DOCUMENT_NOT_FOUND</code>, <code>DOCUMENT_NOT_UPLOADED</code> (je hebt de <code>PUT</code> overgeslagen),{' '}
  <code>DOCUMENT_INVALID</code>, <code>INVALID_DOCUMENT_TARGET</code>, <code>DOCUMENTS_TOO_LARGE</code> of <code>DOCUMENTS_TOO_MANY</code>{' '}
  van <code>requests.create</code>.
</p>

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="webhooks" class="border-t border-border pt-8">
  Webhooks
</h2>

{/* ── webhooks.list ───────────────────────────────────────────────────────── */}

Geeft een lijst van webhook-abonnementen voor een formulier.

  
    Formulier-ID.
  

  
    
```
{
  "ok": true,
  "data": {
    "items": [
      {
        "subscriptionId": "int_abc123",
        "formId": "frm_abc123",
        "provider": "zapier",
        "targetUrl": "https://hooks.zapier.com/...",
        "eventType": "submission_created",
        "status": "active",
        "createdAt": 1714041851000
      }
    ],
    "hasMore": false
  }
}
```

  

{/* ── webhooks.create ─────────────────────────────────────────────────────── */}

Abonneer een URL op formuliergebeurtenissen: nieuwe of verlaten inzendingen, of aanvragen op het formulier die eindigen. De URL moet HTTPS
gebruiken.

  
    Formulier-ID.
  
  
    HTTPS-URL om webhook-payloads naar te sturen.
  
  
    Bij welke tool het abonnement hoort. Het is een label voor je eigen administratie — er is geen marketplace-app om te installeren, en
    elke provider gedraagt zich hetzelfde.
  
  
    Gebeurtenistype om op te abonneren. De drie <code>submission_*</code>-typen leveren de inzendingspayload:{' '}
    <code>submission_created</code> een eerste inzending, <code>submission_updated</code> een bewerking door de respondent, en{' '}
    <code>submission_abandoned</code> een inactief concept. De drie <code>request_*</code>-typen leveren het bijbehorende{' '}
    <a href="/nl/requests/callbacks#payload">aanvraag-event</a> zodra een aanvraag op het formulier op die manier eindigt, ondertekend met
    het geheim van dit abonnement; testaanvragen bereiken geen enkel abonnement.
  
  
    Verplicht wanneer <code>eventType</code> <code>submission_abandoned</code> is; geweigerd voor elk ander type.
  
  
    Optioneel HMAC-ondertekeningsgeheim, 32–255 tekens. Indien meegegeven, dragen leveringen <code>X-Formstep-Signature</code>. Het geheim
    wordt opgeslagen maar nooit teruggegeven door de API.
  

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "webhooks.create",
    "params": {
      "formId": "frm_abc123",
      "targetUrl": "https://hooks.zapier.com/hooks/catch/...",
      "provider": "zapier",
      "eventType": "submission_created",
      "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    }
  }'
```

  
    
```
{
  "ok": true,
  "data": {
    "subscriptionId": "int_new123",
    "formId": "frm_abc123",
    "provider": "zapier",
    "targetUrl": "https://hooks.zapier.com/hooks/catch/...",
    "eventType": "submission_created"
  }
}
```

  

<p>
  Abonnementen op verlaten inzendingen geven de gekozen <code>idleWindow</code> terug, zowel van <code>webhooks.create</code> als van{' '}
  <code>webhooks.list</code>. Elk ander abonnement laat dit weg.
</p>

<p>
  Een aanvraagabonnement ontvangt dezelfde events als een <a href="/nl/requests/callbacks">callback</a>, maar als een eigen levering: een
  eigen event-id, een eigen handtekening, en een eigen budget van vijf pogingen, waarna het abonnement pauzeert. Een aanvraag die aangemaakt
  is met een <code>callbackUrl</code> op een formulier met een <code>request_completed</code>-abonnement vuurt daarom twee keer af, één keer
  naar elke ontvanger. <code>requests.replayCallback</code> stuurt alleen de callback opnieuw. Gebruik{' '}
  <a href="#requests-sample">requests.sample</a> om de payload te zien voordat er een aanvraag is geëindigd.
</p>

{/* ── webhooks.delete ─────────────────────────────────────────────────────── */}

Verwijder een webhook-abonnement.

  
    Abonnements-ID uit <code>webhooks.list</code> of <code>webhooks.create</code>.
  

  
    
```
{
  "ok": true,
  "data": {
    "subscriptionId": "int_abc123",
    "deleted": true
  }
}
```

  

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="analytics" class="border-t border-border pt-8">
  Analyses
</h2>

{/* ── analytics.get ───────────────────────────────────────────────────────── */}

Haal geaggregeerde analysecijfers op voor een formulier. Ondersteunt filters op datumbereik, apparaat, verkeersbron en land.

Analyses zijn een Pro-functie, en de regel volgt het abonnement van de **eigenaar** van de workspace, net als het tabblad Analyses in het dashboard. Heeft de eigenaar geen Pro, dan geeft de aanroep `UPGRADE_REQUIRED` terug — ook voor geschiedenis die is vastgelegd toen dat wel zo was. Een Free-lid in de workspace van een Pro-eigenaar krijgt de gegevens wel.

  
    Formulier-ID.
  
  
    Begin van het datumbereik als Unix-tijdstempel in milliseconden. Moet kleiner dan of gelijk aan <code>to</code> zijn wanneer beide zijn
    ingesteld.
  
  
    Einde van het datumbereik als Unix-tijdstempel in milliseconden. Laat beide weg voor de hele periode — <code>period</code> komt dan
    terug als <code>{`{ "from": null, "to": null }`}</code>.
  
  
    Filter op apparaattype.
  
  
    Filter op verkeersbron (bijv. <code>"Direct"</code>, <code>"Google"</code>).
  
  
    Filter op tweeletterige landcode (bijv. <code>"US"</code>, <code>"DE"</code>).
  
  
    Geef ook de geanonimiseerde analyticsgebeurtenissen achter de cijfers terug, voor je eigen analyse. Geen bezoekers-id's.
  

<p>
  Percentages zijn getallen van 0 tot 100, aantallen zijn gehele getallen, en <code>totalEvents</code> is het aantal ruwe gebeurtenisrijen
  vóór deduplicatie naar unieke bezoekers.
</p>

  
    
```
{
  "ok": true,
  "data": {
    "formId": "frm_abc123",
    "period": { "from": null, "to": null },
    "totalEvents": 17,
    "metrics": {
      "views": 7,
      "uniqueVisitors": 7,
      "engaged": 6,
      "submissions": 4,
      "engagementRate": 86,
      "completionRate": 57,
      "bounceRate": 14
    },
    "breakdown": {
      "byBrowser": { "Chrome": 17 },
      "byCountry": { "US": 10, "DE": 7 },
      "byDevice": { "desktop": 14, "mobile": 3 },
      "bySource": { "Direct": 12, "Google": 5 }
    }
  }
}
```

  

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="workspaces" class="border-t border-border pt-8">
  Workspaces
</h2>

{/* ── workspaces.list ─────────────────────────────────────────────────────── */}

Geeft de workspaces weer die jouw token kan bereiken. Geen parameters.

Een API-token is gebonden aan één workspace, dus dit geeft precies die ene terug — ook als je account tot meerdere behoort.

  
    
```
{
  "ok": true,
  "data": {
    "items": [
      {
        "id": "ws_abc123",
        "name": "Acme Inc",
        "createdAt": 1714041800000,
        "role": "owner"
      }
    ],
    "nextCursor": null,
    "hasMore": false,
    "canPaginate": false
  }
}
```

  

{/* ── workspaces.createInvite ─────────────────────────────────────────────── */}

Maak een uitnodigingslink aan voor een workspace.

  
    Workspace-ID.
  
  
    Vervaldatum als toekomstig Unix-tijdstempel in milliseconden.
  
  
    Maximum aantal keren dat de uitnodiging gebruikt kan worden.
  

  
    
```
{
  "ok": true,
  "data": {
    "id": "inv_abc123",
    "workspaceId": "ws_abc123",
    "code": "aBcDeFgH",
    "expiresAt": null,
    "maxUses": null,
    "uses": 0,
    "createdAt": 1714041851000
  }
}
```

  

{/* ── workspaces.getInvite ────────────────────────────────────────────────── */}

Haal één workspace-uitnodiging op. Geeft dezelfde vorm terug als `workspaces.createInvite`.

  
    Uitnodigings-ID.
  

{/* ── workspaces.updateInvite ─────────────────────────────────────────────── */}

Werk een bestaande workspace-uitnodiging bij. Geef minstens <code>expiresAt</code> of <code>maxUses</code> mee, anders wordt de aanroep
geweigerd. Geeft de bijgewerkte uitnodiging terug.

  
    Uitnodigings-ID.
  
  
    Nieuw vervaltijdstempel in milliseconden.
  
  
    Nieuw maximum aantal gebruiken.
  

{/* ── workspaces.revokeInvite ─────────────────────────────────────────────── */}

Trek een workspace-uitnodiging permanent in.

  
    Uitnodigings-ID.
  

  
    
```
{
  "ok": true,
  "data": {
    "inviteId": "inv_abc123",
    "revoked": true
  }
}
```

  

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="folders" class="border-t border-border pt-8">
  Mappen
</h2>

{/* ── folders.list ────────────────────────────────────────────────────────── */}

Geeft een lijst van mappen in een workspace.

  
    Workspace-ID.
  
  
    Paginagrootte (1–100).
  
  
    Paginacursor.
  

  
    
```
{
  "ok": true,
  "data": {
    "items": [
      {
        "id": "fld_abc123",
        "name": "Customer Feedback",
        "workspaceId": "ws_abc123",
        "parentId": null,
        "createdAt": 1714041800000
      }
    ],
    "nextCursor": null,
    "hasMore": false,
    "canPaginate": false
  }
}
```

  

{/* ── folders.create ──────────────────────────────────────────────────────── */}

Maak een map aan in een workspace. Idempotent — geeft de bestaande map terug als er al een map met dezelfde naam bestaat.

  
    Workspace-ID.
  
  
    Mapnaam (1–255 tekens).
  
  
    Bovenliggende map-ID voor nesting. Weglaten voor rootniveau.
  

  
    
```
{
  "ok": true,
  "data": {
    "id": "fld_new123",
    "name": "Customer Feedback",
    "workspaceId": "ws_abc123",
    "parentId": null,
    "createdAt": 1714041851000,
    "alreadyExisted": false
  }
}
```

  

{/* ── folders.update ──────────────────────────────────────────────────────── */}

Hernoem een map of verplaats hem naar een andere bovenliggende map.

  
    Map-ID.
  
  
    Nieuwe mapnaam (1–255 tekens).
  
  
    Nieuwe bovenliggende map. Geef <code>null</code> door om naar root te verplaatsen.
  

{/* ── folders.delete ──────────────────────────────────────────────────────── */}

Verwijder een map en alle inhoud permanent (submappen en formulieren).

  
    Map-ID.
  

> ⚠️ **Destructieve actie**
> <p>Dit verwijdert alle submappen en formulieren in de map permanent. Deze actie kan niet ongedaan worden gemaakt.</p>

  
    
```
{
  "ok": true,
  "data": {
    "folderId": "fld_abc123",
    "deletedFolderIds": ["fld_abc123"],
    "deletedFormIds": ["frm_in_folder"],
    "message": "Folder and 1 form deleted."
  }
}
```

  

<h2 id="translations" class="border-t border-border pt-8">
  Vertalingen
</h2>

{/* ── translations.listLanguages ──────────────────────────────────────────── */}

Geeft een lijst van alle talen die zijn geconfigureerd op een formulier.

  
    Formulier-ID.
  

  
    
```
{
  "ok": true,
  "data": {
    "formId": "frm_abc123",
    "items": [
      {
        "language": "es",
        "completion": { "total": 15, "current": 12, "outdated": 2, "missing": 1, "suggested": 0 },
        "lastUpdatedAt": 1714041851000
      }
    ],
    "nextCursor": null,
    "hasMore": false,
    "canPaginate": false
  }
}
```

  

{/* ── translations.addLanguage ────────────────────────────────────────────── */}

Registreer een taal op een formulier. Elke andere vertaalmethode faalt met `404 NOT_FOUND` totdat je dit doet.

  
    Formulier-ID.
  
  
    BCP-47 taalcode (bijv. <code>"es"</code>, <code>"pt-BR"</code>).
  

  
    
```
{
  "ok": true,
  "data": {
    "formId": "frm_abc123",
    "language": "es",
    "rowId": "tl_new123"
  }
}
```

  

{/* ── translations.removeLanguage ─────────────────────────────────────────── */}

Verwijder een taal en alle bijbehorende vertalingen van een formulier.

  
    Formulier-ID.
  
  
    BCP-47 taalcode.
  

{/* ── translations.listEntries ────────────────────────────────────────────── */}

Geeft elke bronsleutel voor één taal op een formulier weer, met zijn huidige status. Zo ontdek je de `key`-waarden die
`translations.setEntry` verwacht.

  
    Formulier-ID.
  
  
    BCP-47 taalcode. Moet al op het formulier staan.
  

  
    
```
{
  "ok": true,
  "data": {
    "formId": "frm_abc123",
    "language": "es",
    "completion": { "total": 15, "current": 12, "outdated": 2, "missing": 1, "suggested": 0 },
    "items": [
      {
        "key": "block_q_1.title",
        "status": "current",
        "value": "[{\"text\":\"Tu correo electrónico\"}]",
        "sourceFragment": "[{\"text\":\"Your email\"}]",
        "updatedAt": 1714041851000,
        "block": { "id": "q_1", "type": "email-input", "label": "Your email" }
      }
    ],
    "hasMore": false
  }
}
```

  

<p>
  <code>status</code> is <code>missing</code> (niets opgeslagen), <code>outdated</code> (de bron is sindsdien gewijzigd),{' '}
  <code>current</code>, of <code>suggested</code> (een AI-suggestie klaargezet maar niet geaccepteerd). Sleutels dekken formulierinhoud (
  <code>block_&lt;id&gt;.*</code>) en, zodra een auteur ze heeft aangepast, de bevestigings- en herinnerings-e-mails voor de respondent (
  <code>email.confirmation.*</code>, <code>email.reminder.*</code>).
</p>

{/* ── translations.setEntry ───────────────────────────────────────────────── */}

Stel een enkel vertaalitem in. De taal moet eerst zijn toegevoegd via <code>translations.addLanguage</code>.

  
    Formulier-ID.
  
  
    BCP-47 taalcode.
  
  
    Een sleutel uit <code>translations.listEntries</code>. Bouw er geen zelf op.
  
  
    Het vertaalde fragment, als JSON-string. De markstructuur ervan moet overeenkomen met het bronfragment.
  

  
```
curl -X POST https://api.formstep.io/api/v1 \
  -H "Authorization: Bearer fb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method": "translations.setEntry",
    "params": {
      "formId": "frm_abc123",
      "language": "es",
      "key": "block_q_1.title",
      "value": "[{\"text\":\"Tu correo electrónico\"}]"
    }
  }'
```

> ⚠️ **Schrijven hier is live**
> <p>
>     De API heeft geen concept-dan-publiceer-stap: een <code>setEntry</code> of <code>deleteEntry</code> bereikt respondenten onmiddellijk.
>     Het dashboard en de MCP-vertaaltools gebruiken wel een concept.
>   </p>

<p>
  Geeft <code>{`{ formId, language, key }`}</code> terug.
</p>

{/* ── translations.deleteEntry ────────────────────────────────────────────── */}

Verwijder een enkel vertaalitem, waardoor die sleutel terugvalt op de standaardtaal van het formulier. Idempotent. Verdwijnt het laatste
item voor een taal, dan verdwijnt die taal uit de gepubliceerde talen van het formulier.

  
    Formulier-ID.
  
  
    BCP-47 taalcode.
  
  
    Te verwijderen vertalingssleutel.
  

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="me" class="border-t border-border pt-8">
  Account
</h2>

{/* ── me.get ──────────────────────────────────────────────────────────────── */}

Haal informatie op over de ingelogde gebruiker.

  
    
```
{
  "ok": true,
  "data": {
    "id": "usr_abc123",
    "email": "you@example.com",
    "name": "Jane Doe"
  }
}
```

  

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="meta" class="border-t border-border pt-8">
  Meta
</h2>

Geeft elke methodenaam weer die deze deployment aanbiedt, gesorteerd. Het gezaghebbende antwoord wanneer deze pagina en de server niet
overeenkomen.

  
    
```
{
  "ok": true,
  "data": {
    "methods": [
      "methods.list",
      "analytics.get",
      "folders.create",
      "folders.delete",
      "folders.list",
      "folders.update",
      "formSettings.get",
      "formSettings.update",
      "forms.create",
      "forms.delete",
      "forms.get",
      "forms.list",
      "..."
    ]
  }
}
```

  

{/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}

<h2 id="error-reference" class="border-t border-border pt-8">
  Foutenoverzicht
</h2>

Elke foutresponse heeft dezelfde vorm. De set van `code`-waarden op het hoogste niveau is bewust gesloten: een nieuwe faalwijze voegt nooit
een code toe, maar een `reason`. Vertak op `code` voor het HTTP-niveau-resultaat en op `details.reason` voor de oplossing.

```
{
  "ok": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "No field with key \"company\" on this form.",
    "details": { "reason": "UNKNOWN_FIELD_KEY", "field": "prefill.company", "validKeys": ["company_name", "contacts"] }
  }
}
```

<p>
  <code>details</code> is aanwezig wanneer de server de oorzaak kan benoemen. Naast <code>reason</code> kan het ook <code>field</code> (de
  betrokken parameter, met punten voor nesting), <code>validKeys</code>, <code>validValues</code> (de optie-<strong>waarden</strong> die een
  keuzevraag accepteert), <code>expectedType</code>, <code>feature</code> (bij <code>UPGRADE_REQUIRED</code>), en <code>retryAfterMs</code>{' '}
  (bij een gedrosselde aanroep) bevatten. Redenen voor het aanvraagoppervlak staan hierboven bij elke methode vermeld.
</p>

<p>Dit zijn alle codes:</p>

  
    Ongeldige of ontbrekende parameters in het verzoek.
  
  
    Ontbrekend of ongeldig API-token.
  
  
    Het token heeft geen toegang tot de gevraagde resource.
  
  
    Resource bestaat niet.
  
  
    Onbekende methodenaam. Gebruik <code>methods.list</code> om beschikbare methoden te bekijken.
  
  
    De resource verkeert niet in een staat die deze aanroep toelaat — een aanvraag die niet meer in behandeling is, een idempotentiesleutel
    hergebruikt met een andere body.
  
  
    Meer dan 120 aanroepen per minuut op dit token, meer dan 60 <code>requests.create</code>-aanroepen per minuut, of te veel mislukte
    authenticaties vanaf dit IP.
  
  
    Functie vereist een hoger abonnementsniveau, de werkruimte heeft dit maandelijkse quotum verbruikt (reden{' '}
    <code>MONTHLY_ALLOWANCE_REACHED</code>), of een Free-account heeft zijn 10 gratis uitnodigingen verbruikt (reden{' '}
    <code>FREE_INVITATIONS_USED</code>).
  
  
    Onverwachte serverfout. Probeer het later opnieuw.
  

<h2 id="next-steps">Volgende stappen</h2>
<div class="not-prose grid gap-3 sm:grid-cols-2">
  - [API-tokens](/nl/developers/api-tokens) — Tokens aanmaken en beheren
  - [MCP-server](/nl/developers/mcp-server) — Gebruik Formstep vanuit AI-agents
  - [Webhooks-referentie](/nl/developers/webhooks-reference) — Payloadschema en ondertekening
</div>
