Webhooks API
Webhooks allow external systems to trigger Formstamper workflows by sending HTTP requests.
Send Webhook Event
POST/api/workflows/{workflowId}/webhook
Trigger a workflow by sending event data to its webhook endpoint.
This endpoint does not require authentication. The unique workflow ID serves as the identifier. For production use, consider implementing payload signing in your sending application.
Request Body:
{
"tenant_name": "Jane Doe",
"unit_address": "456 Oak Ave, Unit 2B",
"rent_owed": 2400,
"arrears_from": "2026-01-01",
"arrears_to": "2026-03-31",
"sign_date": "2026-04-12"
}
Response: 202 Accepted
Webhook received
Error Responses
| Code | Body | Meaning |
|---|---|---|
202 | Webhook received | Event accepted and queued |
400 | Payload validation failed: ... | JSON schema validation error |
400 | Invalid JSON payload | Request body is not valid JSON |
400 | Invalid schema or payload: ... | Schema parsing error |
404 | Workflow not found! | No workflow with the given ID |
Get Latest Webhook Event
GET/api/workflows/{workflowId}/webhook/latest-event
Retrieve the most recently received webhook event for a workflow. Requires authentication.
Response: 200 OK
{
"eventId": "evt_abc123",
"workflowId": "wrk_01j5abc123",
"eventPayload": "{\"tenant_name\":\"Jane Doe\",...}",
"receivedAt": "2026-04-12T14:30:00"
}
Webhook Payload Format
Webhook payloads should be flat JSON objects where each key corresponds to a column name in your template's field mappings.
Recommended Structure
{
"tenant_name": "string",
"address": "string",
"amount": "number (or string)",
"date_field": "string (YYYY-MM-DD format preferred)"
}
Nested Payloads
If your external system sends nested JSON, use Compose or Select nodes in your workflow to flatten the data before it reaches the Template Node.
Incoming payload:
{
"tenant": {
"name": "Jane Doe",
"address": {
"street": "456 Oak Ave",
"unit": "2B"
}
},
"financials": {
"rent_owed": 2400
}
}
Compose Node mapping:
{
"tenant_name": "${event.tenant.name}",
"full_address": "${event.tenant.address.street}, ${event.tenant.address.unit}",
"amount": "${event.financials.rent_owed}"
}
Integration Examples
cURL
curl -X POST https://api.formstamper.com/api/workflows/wrk_01j5abc123/webhook \
-H "Content-Type: application/json" \
-d '{"tenant_name":"Jane Doe","address":"456 Oak Ave","rent_owed":2400}'
JavaScript (fetch)
await fetch('https://api.formstamper.com/api/workflows/wrk_01j5abc123/webhook', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tenant_name: 'Jane Doe',
address: '456 Oak Ave',
rent_owed: 2400,
}),
});
Python (requests)
import requests
requests.post(
'https://api.formstamper.com/api/workflows/wrk_01j5abc123/webhook',
json={
'tenant_name': 'Jane Doe',
'address': '456 Oak Ave',
'rent_owed': 2400,
}
)
C# (HttpClient)
var client = new HttpClient();
var content = new StringContent(
JsonSerializer.Serialize(new {
tenant_name = "Jane Doe",
address = "456 Oak Ave",
rent_owed = 2400
}),
Encoding.UTF8,
"application/json"
);
await client.PostAsync(
"https://api.formstamper.com/api/workflows/wrk_01j5abc123/webhook",
content
);