Adaptive Requirements Guide
Adaptive Requirements is Kota’s mechanism for collecting extra data when an intent cannot continue from the data it already has. When a workflow enters action_required, Kota gives you an adaptive requirement identifier (ar_...), or lets you list the open requirements for the parent intent. Your integration retrieves the dynamic form schema, presents it to the right user, and submits answers back to Kota.
Before starting, ensure you’ve completed:
- Authentication: API key setup, environments, and idempotency
- API Integration Overview: the intent-based pattern used across API-only flows
- Webhooks and events: receiving asynchronous status updates
Overview
Some mutating Kota API calls cannot complete in a single request. Kota may need extra information from an employer, employee, dependant, or beneficiary before it can continue. When that happens, the API does not treat the workflow as failed. Instead, the parent intent moves to action_required and exposes one or more adaptive requirements.
Building blocks
What is a requirement?
A requirement is a single outstanding data request tied to a parent workflow, such as a group quote intent, group policy intent, or enrolment intent. It has:
- An opaque ID in the form
ar_followed by 32 lowercase hexadecimal characters, for examplear_550e8400e29b41d4a716446655440000. - A schema that defines what Kota needs to collect.
- A fulfillment lifecycle that ends once the requirement is satisfied.
The ar_ requirement ID is the handle you need to carry forward. Persist it against the workflow that triggered action_required so the user can resume if they leave the flow.
Lifecycle
Fulfilling a requirement does not always mean the parent intent is complete. After the requirement is fulfilled, continue following the parent intent with webhooks or a retrieve call.
Keep requirement calls server-side
The Adaptive Requirements API uses your Kota API secret key as a Bearer token. Your secret key must never reach the browser.
Render the form in the browser, but route GET /requirements/{requirement_id} and POST /requirements/{requirement_id} through your own backend:
Pair test keys with https://test.api.kota.io and live keys with https://api.kota.io. A requirement created in one environment will not exist in the other.
Quickstart
Step 1: Detect action_required
When a parent workflow needs extra data, persist the requirement ID and route the user to your requirement form.
Some flows expose the requirement ID directly on the action payload:
Other intent flows let you list open requirements for the parent intent:
Each listed requirement includes an id (ar_...), object_type, object_id, requirement_type, and is_fulfilled. Use those fields to decide where the requirement belongs in your UI.
Step 2: Retrieve the schema
Call Kota from your backend:
Example response:
Step 3: Render the form
Install the adaptive form package:
Render the schema in your frontend. Prefer controlled mode so you can submit a JSON answers object and preserve value types:
Step 4: Submit answers
Submit answers from your backend:
Successful response when the schema is fully satisfied:
If answers are stored but more fields are still required, the response stays in_progress and lists the outstanding field IDs:
Step 5: Resume the parent flow
Once the requirement is fulfilled, the parent intent can proceed. Depending on the flow, Kota may continue automatically or your integration may need to re-check the parent intent. Use the relevant webhook or retrieve endpoint to drive the next UI state.
Retrieve a requirement
Endpoint: GET /requirements/{requirement_id}
The response includes:
is_fulfilled: whether the requirement is already completefulfilled_at: present only when fulfilledschema: the fields Kota needs you to collect (present for pending requirements, and may also be returned when fulfilled)
Pass schema into AdaptiveFormProvider.
Treat the schema as fresh on every fetch. It is versioned and Kota can publish changes as provider requirements evolve.
GET is safe to call repeatedly while the requirement is open. If is_fulfilled is true, treat that response as already done and continue the parent workflow.
Render the form
@kotaio/adaptive-form is headless: it owns the schema logic, and you own the UI. It handles visibility rules, validation, read-only and computed values, multi-step requirements, and the final answer set.
The package has peer dependencies on react and react-dom version >=18.3.1.
Wire it up
AdaptiveForm must render inside AdaptiveFormProvider.
Build field components
Common FieldInputProps:
Field types
Map every field type your schemas use to a component. Common types include text, number, email, date, textarea, select, radio, checkbox, phone, and file.
Two field types are special:
For full control over one field type, use renderField. It receives the full field state. Return null to fall back to the components map.
Controlled and uncontrolled usage
- Controlled (recommended for API submission): pass
valueandonChange, thenPOST{ answers: formData }as JSON so booleans, numbers, and arrays keep their types. - Uncontrolled: omit
value/onChange(optionally passdefaultValue) and read values through native form submission. Convert carefully if you assemble the JSON payload yourself, becauseFormDatastringifies values.
In controlled mode, define the components map outside the component or wrap it in useMemo. Inline objects can remount fields and cause users to lose focus while typing.
Multi-step forms
Some requirements have multiple steps. AdaptiveForm renders one step at a time by default, includes Previous and Next navigation, and disables Next until the current step is valid.
Use:
renderStepNavigationfor custom navigation.showAllStepsto render every step on one page.useFormInfo()for step state, such as a progress indicator.
Form library adapters
Both adapters accept optional serialize and deserialize functions. By default, Date values serialize to YYYY-MM-DD.
Submit answers
Endpoint: POST /requirements/{requirement_id}
The payload is a single answers object keyed by field ID.
Values keep their JSON types. Send booleans as true or false, numbers as numbers, and dates as YYYY-MM-DD.
Answers are merged with any previously submitted values and re-evaluated against the requirement schema. The requirement becomes fulfilled once all required fields are satisfied. Otherwise it stays in_progress and the response lists outstanding_fields. A required field that has not been submitted yet is not an error.
In practice, submit the complete answer set produced by @kotaio/adaptive-form. That keeps client and server state aligned and avoids leaving fields outstanding unintentionally.
Use an Idempotency-Key for safe retries on mutating requests:
Generate one key per logical submission and reuse it only for retries of that exact same submission. See Authentication and idempotency.
Validation
@kotaio/adaptive-form validates input as the user types. Treat client-side validation as the primary gate and disable submit until the form is valid.
Kota also validates server-side. If the API returns 400 invalid_request with an errors array, map each error back to the field with the same field_id:
Errors
Adaptive Requirements errors use application/problem+json and follow the same general shape as the rest of the Kota API.
Branch on error_code, not only HTTP status. Some statuses, especially 400 and 409, cover multiple cases.
Retry only when it is safe:
- Retry
409 idempotency_request_in_progresswith the same key afterRetry-After. - Retry
500responses with backoff. - Do not retry
400,401,404,409 requirement_already_fulfilled, or409 idempotency_errorwithout changing the workflow or request.
Best practices and gotchas
Architecture
- Keep the secret key on your server. Proxy both requirement calls through your backend.
- Persist the requirement ID immediately. The
ar_ID is the handle you need to resume. - Use the right environment and key. Test requirements return
404in production and production requirements return404in test.
Submission
- Submit the form’s answer set as JSON. Preserve booleans, numbers, and dates as typed JSON values.
- Handle already fulfilled as done. On
GET, checkis_fulfilled. OnPOST, treat409 requirement_already_fulfilledas success for the workflow. - Make retries idempotent. Send an
Idempotency-Keyand reuse it only for retries of the same submission. - Expect incremental progress. Partial submissions can return
in_progresswithoutstanding_fieldsuntil the schema is complete.
Schema handling
- Always fetch fresh. The schema is versioned and may change as provider requirements evolve.
- Let the form do the logic. Pass the schema to
@kotaio/adaptive-forminstead of rebuilding schema rules yourself. - Validate client-side before submitting. Disable submit until the form reports no errors.
- Clear hidden values. Use
clearHiddenValuesso values entered before a field is hidden are not submitted.
@kotaio/adaptive-form
- Memoize components in controlled mode. Inline component maps can remount inputs.
- Return
nullwhenisVisibleis false. Otherwise you may render fields the schema intends to hide. - Preserve boolean option values. Stringify only for display, and pass the raw value to
onChange. - Keep the package up to date. Older versions may not understand newer schema constructs.
Next steps
- Employee Enrolment: handle enrolment intent statuses and action-required states
- Employer Health Insurance Setup: handle requirements during quote and setup flows
- API Reference: Requirements: retrieve requirement schemas and submit answers
- Webhooks and events: react to parent intent status changes
- API Errors: understand error response format

