MCP webhook tools
Use these tools to manage a form’s webhook through the Makeform MCP server. Webhook management is not available through the REST API.
Connection and authentication
Send JSON-RPC requests with POST to https://mcp.makeform.ai. Authenticate with an API key or OAuth access token in Authorization: Bearer <token>. Send Accept: application/json, text/event-stream.
Successful tool results include JSON in content[0].text and matching structuredContent. Each call attempts to append a private execution audit record, including data reads and proposals; retries may add another record.
MCP allows 60 requests per minute. Requests can be rate limited with HTTP 429; wait for the time in the Retry-After header.
MCP tool errors return HTTP 200 with result.isError: true. Business rule errors use a jsonrpc_error text envelope and may include a name such as webhook_exists. Input schema failures instead start with MCP error -32602: Input validation error.
{
"jsonrpc_error": {
"code": -32600,
"message": "This form already has a webhook. Call list_webhooks to inspect it, or delete_webhook (two-step) before creating a new one.",
"data": {
"name": "webhook_exists"
}
}
}create_webhook
Add a webhook to a form. Each form can have one webhook; if one already exists, the call returns a webhook_exists error. You need permission to manage the form’s integrations.
Input
| Name | Type | Required | Description |
|---|---|---|---|
form_id | string | Yes | Form to add the webhook to. |
url | string | Yes | Public HTTPS destination URL, up to 2,000 characters. |
headers | object | No | Up to 20 custom headers. Reserved and X-MakeForm-* names are not allowed. Values must be printable ASCII and no longer than 1,000 characters. |
signing_secret | string | No | 16–256 characters, with no whitespace. If omitted, one is generated. |
Returns
Returns { form_id, webhook, signing_secret?, message }. A generated signing secret is shown once. list_webhooks shows only whether a signing secret exists.
Example call
{
"form_id": "FORM_ID",
"url": "https://your-server.example/webhooks/makeform",
"headers": {
"X-Workspace-Source": "website"
}
}list_webhooks
List a form’s webhook configuration. This call does not change your data. It returns configuration only; there is no delivery history.
Input
| Name | Type | Required | Description |
|---|---|---|---|
form_id | string | Yes | Form whose webhook to list. |
Returns
Returns { form_id, webhooks[] }. Each webhook includes a redacted URL, header names only, has_signing_secret, and timestamps.
Example call
{
"form_id": "FORM_ID"
}test_webhook
Send one signed webhook.test event to the configured webhook. The event contains no submission data. The request is sent from Makeform’s servers, has a 10-second timeout, and the receiver’s response body is discarded. It sends one outbound request and does not change stored data.
The test request body includes event: "webhook.test", test: true, deliveryId, formId, formName, sentAt, and an empty formData object.
Input
| Name | Type | Required | Description |
|---|---|---|---|
form_id | string | Yes | Form with the webhook to test. |
webhook_id | string | Yes | Webhook to test. |
Returns
Returns { form_id, webhook_id, event, ok, status, duration_ms, signed, error?, message }. The event is webhook.test. If delivery fails, error is target_blocked, timeout, or network_error.
Example call
{
"form_id": "FORM_ID",
"webhook_id": "WEBHOOK_ID"
}Webhook deliveries
Real deliveries fire when a submission is completed, including when a previously partial submission is completed. Partial saves do not trigger a delivery. Each submission is delivered once; deliveries are not retried, including after the receiver returns a 5xx or 429 response. The delivery timeout is 30 seconds.
Deliveries use POST by default. A webhook can be stored with GET, POST, PUT, PATCH, or DELETE. A GET request has no body and no signature.
Real deliveries identify the event with the X-MakeForm-Event: form_submission header. The JSON body has no event field. It contains deliveryId, submissionId, formId, formData, submittedAt, and formName. formData contains stored answers keyed by field name. emailVerification and emailRisk are included only when they apply.
deliveryId is stable per submission, so your receiver can use it to ignore duplicates. X-MakeForm-Timestamp reports the submission time, not the send time.
When a webhook has a signing secret, Makeform sends an X-MakeForm-Signature header in the format sha256=<hex> for requests with a body. The hex value is an HMAC-SHA256 signature of the exact raw request body, keyed with the signing secret. Verify the signature against the raw request body before parsing JSON.
MCP has no action to rotate a signing secret. You can view and change the secret in the webhook settings in the dashboard; saving overwrites it.
delete_webhook
Delete a webhook in two steps. First request confirmation to get a delete_token, then confirm the deletion using that token. The token lasts 5 minutes and is bound to the action, form, user, calling credential, and proposed state. Expired or mismatched tokens are rejected.
Input
| Name | Type | Required | Description |
|---|---|---|---|
form_id | string | Yes | Form with the webhook to delete. |
webhook_id | string | Yes | Webhook to delete. |
confirm_delete | boolean | No | Set to true for the confirmation step. |
delete_token | string | No | Token returned by the confirmation request; required when confirming. |
Returns
Returns { status, form_id, webhook_id, webhook?, delete_token?, expires_at?, message }. status is confirmation_required or deleted.
Example calls
First, request confirmation:
{
"form_id": "FORM_ID",
"webhook_id": "WEBHOOK_ID"
}Then confirm with the returned token:
{
"form_id": "FORM_ID",
"webhook_id": "WEBHOOK_ID",
"confirm_delete": true,
"delete_token": "DELETE_TOKEN"
}To edit webhook headers or turn a webhook on or off, use the dashboard.