For the complete documentation index, see llms.txt. This page is also available as Markdown.

Forms API

Create, edit and publish intake forms from your own code, on behalf of your own users.

Intake forms collect what you need from a prospect before you can quote them. This API lets you build and manage those forms from your own application, so your users never have to leave your product to do it.

Each form belongs to one of your users. They see their own forms and nobody else's — you don't create InsurGrid accounts for them, and you don't manage permissions. You tell InsurGrid which of your users a form belongs to, and it handles the separation.

If you'd rather your users built forms visually than through code, the same forms are available in an embeddable builder — see Embed the form builder. The two work on the same data.

Submissions don't come back through this API. When someone completes a form, the submission is delivered to your webhook endpoint. See Submissions.


Before you start

Your API key

Every request carries your key as a bearer token:

Authorization: Bearer YOUR_API_KEY

Create and revoke keys in the dashboard under Settings → API keys. Two things to know:

  • The key must belong to an agency admin, otherwise you get 403 admin_required.

  • Forms access must be enabled for the agent who owns the key. If it isn't, every call returns 403 feature_disabled — contact us to switch it on.

Revoking a key stops the API and any live embeds on their next request. See Get your API credentials.

Environments

Staging
Production

API base URL

https://phoenix-staging.insurgrid.com/api/v1

https://phoenix.insurgrid.com/api/v1

Embed script

https://dashboard-staging.insurgrid.com/embed.js

https://dashboard.insurgrid.com/embed.js

Dashboard (API keys)

https://dashboard-staging.insurgrid.com

https://dashboard.insurgrid.com

Build against staging, then change the host and the key. The two are fully separate: a staging key works only on staging, and a form created on staging doesn't exist on production. More in Environments.

Which forms this API can see

externalUserId is how you tell InsurGrid whose form this is — a stable id from your own system, such as your internal user id. Any string up to 255 characters. You set it when you create a form; it can't be changed afterwards, and it's what decides who can see the form from then on.

A form is tied to two things: that externalUserId, and the key that created it. Both have to match for a form to be visible, which has two consequences worth planning around:

  • Forms built in the InsurGrid dashboard are invisible here. They have no externalUserId, so they never appear in GET /forms, and GET /forms/{id} returns 404. Only forms created through this API or the embedded builder are reachable.

  • Keys don't share forms, even inside one agency. A form created with one admin's key returns 404 to another admin's key. Use one key consistently for a given integration, and don't expect a replacement key to inherit the forms the old one made — if you rotate, you'll be starting a new set.


Quick start

Create a draft:

Leave out steps and the form starts with a working default: a welcome step, a contact info step that already collects name, email and phone, and a confirmation step. The response carries the form's id.

Publish it:

The response now includes shareUrl — the public link you send to customers, or embed. For a walkthrough that goes further, see Quickstart C.


Endpoints

Method
Path
What it does

GET

/forms

List forms.

POST

/forms

Create a draft form.

GET

/forms/{id}

Get one form with all its steps and questions.

PATCH

/forms/{id}

Update a form.

DELETE

/forms/{id}

Delete a form.

POST

/forms/{id}/duplicate

Copy a form for the same user.

PUT

/forms/{id}/publish

Publish a form and get its shareUrl.

PUT

/forms/{id}/archive

Take a form out of use.

PUT

/forms/{id}/reactivate

Make an archived form active again.

GET

/forms/templates

Starter forms you can build from.

GET

/forms/acord-catalog?line=

ACORD forms and questions. line is required.

POST

/embed-sessions

A short-lived token for the embedded builder.

Listing forms

Everything is optional. Omit externalUserId to list across all of your users. limit runs 1–100 and defaults to 50.

Each entry carries:

Field
What it is

id

The form's id, used in the paths above.

public_id

The public identifier used in form links and embeds.

name, slug

The name, and the readable part of its web address.

status

draft, active or archived.

externalUserId

Which of your users owns it.

shareUrl

Where to send people to fill it in — null until published.

acord_numbers, policy_types, is_acord_ready

ACORD mapping, if any.

created_at, updated_at

Timestamps.

GET /forms/{id} returns all of that plus the form itself: steps, insurance_line, branding, redirect_url, auto_response_enabled, tracking and carrier_flow_enabled.

Creating a form

Field
Required
Notes

externalUserId

Yes

Whose form this is.

name

Yes

Up to 255 characters.

slug

No

e.g. home-intake. Generated from name if omitted, with a short random suffix to keep it unique. Lower-case words separated by single hyphens, up to 100 characters.

insurance_line

No

personal (default) or commercial.

steps

No

The pages and questions. See below.

redirect_url

No

Where to send the customer after they submit.

branding

No

Logo and colours.

Forms are always created as drafts. Publishing is a separate call.

Updating a form

PATCH /forms/{id} with only the fields you want to change. On update, unknown fields are rejected rather than ignored — a misspelled key is a 422. (On create they're ignored, so a typo there passes silently.)

⚠️ steps replaces rather than merges. If you send it, send the complete list — any step you leave out is deleted, including the default contact info step. See Keeping the contact block populated.

Statuses

Status
Meaning

draft

Not live. shareUrl is null.

active

Published. shareUrl is set.

archived

No longer live. shareUrl is null.


How a form is structured

A form is a list of steps — the pages someone moves through — and each step holds questions.

Step fields

Field
Required
Notes

type

Yes

welcome, contact_info, custom, confirmation or complete. Only one of each non-custom type per form.

name

Yes

Up to 255 characters.

segment

Yes

Where the step sits in the flow: before, carrier or after. Easy to miss — it has no default, and omitting it is a 422.

position

Yes

Order within the form, 0–1000.

enabled

No

Defaults to true.

questions

No

The step's questions. Up to 200.

A form must contain at least one custom or contact_info step — a form made only of welcome and confirmation pages collects nothing, and is rejected.

Question fields

Field
Required
Notes

type

Yes

One of the question types below.

label

Yes

The question text, up to 500 characters.

position

Yes

Order within the step, 0–1000.

required

No

Defaults to false.

placeholder

No

Up to 500 characters.

field_mapping

No

Tags this question as carrying a known value. This is what fills the webhook's contact block — see below.

options

For choice questions

Up to 500. Required for dropdown, single_choice and multi_choice.

initially_hidden

No

Hide the question until a rule reveals it.

rules

No

Conditional logic, up to 100 per question.

Step types: welcome, contact_info, custom, confirmation, complete

Question types: short_text, long_text, email, number, date, dropdown, single_choice, multi_choice, file_upload, address, data_table

A form can hold up to 50 steps.

Rather than assembling this by hand, start from GET /forms/templates, or build a form the way you want it in the embedded builder and fetch it with GET /forms/{id} — what comes back is exactly what you can send. (Forms built in the InsurGrid dashboard won't work for this; see Which forms this API can see.)

Carrier-connected forms — the ones that log into a carrier to pull declaration pages — can't be created or enabled through this API. Build those in the dashboard.

Keeping the contact block populated

Every submission webhook carries a contact object with the submitter's name, email and phone. InsurGrid fills it from questions tagged with field_mapping — not from a question's type, label or position.

field_mapping

Fills

FullName

contact.name

Email

contact.email

Phone

contact.phone

ServiceType

—

EventDate

—

A form created without steps gets a contact info step whose three questions are already tagged, so contact works out of the box. The moment you send your own steps, that step is gone — along with its tags — and every webhook from then on arrives with:

Nothing errors, and the answers are still there in answers[]. Only contact goes empty, so it is easy to miss until something downstream stops working.

So when you build your own structure, tag the equivalent questions:

If two questions share a mapping, the first non-empty answer wins.


Errors

Every error has the same shape:

Status
Code
What went wrong

400

invalid_request

The request is malformed.

401

invalid_api_key

The key is missing, wrong or revoked.

401

invalid_embed_token

The embed token is missing or expired.

403

admin_required

The key doesn't belong to an agency admin.

403

feature_disabled

Forms aren't enabled for the key's agent.

403

scope_required

The key isn't scoped for this API.

404

not_found

No such form, or it isn't visible to this key.

409

conflict

That slug is already taken.

422

validation_error

A field is invalid — see details.

422

external_user_required

externalUserId missing on create.

422

carrier_flow_disabled

Carrier steps aren't supported here.

429

rate_limited

Too many requests. Wait for Retry-After seconds.

503

auth_unavailable

A temporary problem. Try again.

Rate limits

  • 300 requests per minute, counted per agency and shared across every API key the agency holds.

  • 60 embed tokens per minute, counted per API key.

Calls the embedded builder makes with a token are counted separately, per end user, so they don't eat into the 300.

Over any of them you get 429 with a Retry-After header.