curl --request POST \
--url https://app.thinnest.ai/api/v1/forms \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Delivery address",
"category": "CONTACT_US",
"form": {
"title": "Where should we deliver?",
"submitLabel": "Send",
"fields": [
{
"name": "address",
"label": "Full address",
"kind": "paragraph",
"required": true
},
{
"name": "pincode",
"label": "PIN code",
"kind": "number",
"required": true
},
{
"name": "slot",
"label": "Delivery slot",
"kind": "choice",
"options": [
"Morning",
"Evening"
]
},
{
"name": "order",
"label": "Order number",
"kind": "text",
"prefill": true
}
]
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Delivery address',
category: 'CONTACT_US',
form: {
title: 'Where should we deliver?',
submitLabel: 'Send',
fields: [
{name: 'address', label: 'Full address', kind: 'paragraph', required: true},
{name: 'pincode', label: 'PIN code', kind: 'number', required: true},
{
name: 'slot',
label: 'Delivery slot',
kind: 'choice',
options: ['Morning', 'Evening']
},
{name: 'order', label: 'Order number', kind: 'text', prefill: true}
]
}
})
};
fetch('https://app.thinnest.ai/api/v1/forms', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.thinnest.ai/api/v1/forms"
payload = {
"name": "Delivery address",
"category": "CONTACT_US",
"form": {
"title": "Where should we deliver?",
"submitLabel": "Send",
"fields": [
{
"name": "address",
"label": "Full address",
"kind": "paragraph",
"required": True
},
{
"name": "pincode",
"label": "PIN code",
"kind": "number",
"required": True
},
{
"name": "slot",
"label": "Delivery slot",
"kind": "choice",
"options": ["Morning", "Evening"]
},
{
"name": "order",
"label": "Order number",
"kind": "text",
"prefill": True
}
]
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "form_9e2c4a7b-1d5f-4c38-8b6e-0a3f7d2c9e15",
"name": "Delivery address",
"agent": "ag_2c7e9a14-5b3d-4f8e-a1c6-7d9b0e3f5a21",
"category": "CONTACT_US",
"form": {
"title": "Where should we deliver?",
"submitLabel": "Send",
"fields": [
{
"name": "address",
"label": "Full address",
"kind": "paragraph",
"required": true
},
{
"name": "pincode",
"label": "PIN code",
"kind": "number",
"required": true
},
{
"name": "slot",
"label": "Delivery slot",
"kind": "choice",
"required": false,
"options": [
"Morning",
"Evening"
]
},
{
"name": "order",
"label": "Order number",
"kind": "text",
"required": false,
"prefill": true
}
]
},
"published": false,
"publishedAt": null,
"createdAt": "2026-10-06T10:20:51.093Z",
"updatedAt": "2026-10-06T10:20:51.093Z"
}{
"error": "\"Delivery slot\" is a choice, so it needs at least 2 options."
}{
"error": "Send a valid API key as `Authorization: Bearer <key>`."
}{
"error": "This API key is read-only: it can read everything but change nothing."
}{
"error": "That agent was not found."
}{
"error": "A form with that name already exists."
}{
"error": "Over 240 requests a minute. Slow down and retry."
}Create Form
Saves a form, unpublished — it cannot be sent until Publish Form succeeds. Up to 8 questions; field names are what each answer comes back under. Without agent, the form goes to the agent holding your WhatsApp number, else your oldest agent. No connected number is needed to build one. A build key may do this.
curl --request POST \
--url https://app.thinnest.ai/api/v1/forms \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Delivery address",
"category": "CONTACT_US",
"form": {
"title": "Where should we deliver?",
"submitLabel": "Send",
"fields": [
{
"name": "address",
"label": "Full address",
"kind": "paragraph",
"required": true
},
{
"name": "pincode",
"label": "PIN code",
"kind": "number",
"required": true
},
{
"name": "slot",
"label": "Delivery slot",
"kind": "choice",
"options": [
"Morning",
"Evening"
]
},
{
"name": "order",
"label": "Order number",
"kind": "text",
"prefill": true
}
]
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Delivery address',
category: 'CONTACT_US',
form: {
title: 'Where should we deliver?',
submitLabel: 'Send',
fields: [
{name: 'address', label: 'Full address', kind: 'paragraph', required: true},
{name: 'pincode', label: 'PIN code', kind: 'number', required: true},
{
name: 'slot',
label: 'Delivery slot',
kind: 'choice',
options: ['Morning', 'Evening']
},
{name: 'order', label: 'Order number', kind: 'text', prefill: true}
]
}
})
};
fetch('https://app.thinnest.ai/api/v1/forms', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.thinnest.ai/api/v1/forms"
payload = {
"name": "Delivery address",
"category": "CONTACT_US",
"form": {
"title": "Where should we deliver?",
"submitLabel": "Send",
"fields": [
{
"name": "address",
"label": "Full address",
"kind": "paragraph",
"required": True
},
{
"name": "pincode",
"label": "PIN code",
"kind": "number",
"required": True
},
{
"name": "slot",
"label": "Delivery slot",
"kind": "choice",
"options": ["Morning", "Evening"]
},
{
"name": "order",
"label": "Order number",
"kind": "text",
"prefill": True
}
]
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "form_9e2c4a7b-1d5f-4c38-8b6e-0a3f7d2c9e15",
"name": "Delivery address",
"agent": "ag_2c7e9a14-5b3d-4f8e-a1c6-7d9b0e3f5a21",
"category": "CONTACT_US",
"form": {
"title": "Where should we deliver?",
"submitLabel": "Send",
"fields": [
{
"name": "address",
"label": "Full address",
"kind": "paragraph",
"required": true
},
{
"name": "pincode",
"label": "PIN code",
"kind": "number",
"required": true
},
{
"name": "slot",
"label": "Delivery slot",
"kind": "choice",
"required": false,
"options": [
"Morning",
"Evening"
]
},
{
"name": "order",
"label": "Order number",
"kind": "text",
"required": false,
"prefill": true
}
]
},
"published": false,
"publishedAt": null,
"createdAt": "2026-10-06T10:20:51.093Z",
"updatedAt": "2026-10-06T10:20:51.093Z"
}{
"error": "\"Delivery slot\" is a choice, so it needs at least 2 options."
}{
"error": "Send a valid API key as `Authorization: Bearer <key>`."
}{
"error": "This API key is read-only: it can read everything but change nothing."
}{
"error": "That agent was not found."
}{
"error": "A form with that name already exists."
}{
"error": "Over 240 requests a minute. Slow down and retry."
}Authorizations
Your API key (ta_live_…) from Settings → API keys, sent as Authorization: Bearer <key>. Keep it on a server: it can message every customer you have. A key is full, build or read-only; a request its level does not allow is refused with 403.
Headers
Developers only: the customer workspace this request acts in — its org_… id from POST /customers. Leave it out to act in your own workspace.
"org_3fKq9TzQ1mN8vB2xR7cLpA"
Body
What you call it, unique per agent. Customers never see it — but Reply to Conversation can send a form by this name.
2 - 120"Delivery address"
Show child attributes
Show child attributes
WhatsApp's category for it. Affects reporting only.
SIGN_UP, APPOINTMENT_BOOKING, LEAD_GENERATION, CONTACT_US, CUSTOMER_SUPPORT, SURVEY, OTHER "CONTACT_US"
The agent it belongs to (ag_…). Leave it out for the agent holding your WhatsApp number, else your oldest agent. Cannot be changed later.
"ag_2c7e9a14-5b3d-4f8e-a1c6-7d9b0e3f5a21"
Response
The saved form, not yet published.
The form's id (form_…).
What you call it. Customers never see it.
The agent it belongs to (ag_…).
WhatsApp's category for it. Affects reporting only.
SIGN_UP, APPOINTMENT_BOOKING, LEAD_GENERATION, CONTACT_US, CUSTOMER_SUPPORT, SURVEY, OTHER Show child attributes
Show child attributes
Whether it can be sent. False until published, and again after any edit until it is republished.
When it was last published.
When it was created.
When it was last changed.