SimplyFill.

Webhooks

Register, list, update, delete, and test webhook configurations.

Webhooks

Webhook configurations live under /api/v1/webhook-configs. Each configuration carries a name, a webhook_url, a list of events to subscribe to, and an auto-generated secret you use to verify incoming deliveries.

For the conceptual overview, signature verification, and retry semantics, see Webhooks concept.

Supported events

The current set of subscribable events:

EventFires when
generation.completedAn async PDF generation succeeded
generation.failedAn async PDF generation permanently failed
batch.completedA bulk envelope upload finished
batch.failedA bulk envelope upload failed before producing results

Roadmap events

template.version_published and quota.threshold_crossed events are planned for v2. Today, quota crossings are surfaced via dashboard banners and account-owner emails only.

Create a webhook configuration

POST /api/v1/webhook-configs

Permissions: API key scope write or higher.

Request body

FieldTypeRequiredDescription
namestring (1–255 chars)yesDisplay name.
webhook_urlURLyesHTTPS endpoint that will receive deliveries.
eventsarray of stringsnoDefaults to ["generation.completed", "generation.failed"].
mapping_idintegernoLimit deliveries to events triggered by this mapping. Omit for all mappings.
curl -X POST https://api.simplyfill.app/v1/webhook-configs \
  -H "Authorization: Bearer $SIMPLYFILL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ops hooks",
    "webhook_url": "https://hooks.example.com/simplyfill",
    "events": ["generation.completed", "generation.failed", "batch.completed"]
  }'
const hook = await client.webhooks.create({
  name: 'ops hooks',
  webhookUrl: 'https://hooks.example.com/simplyfill',
  events: ['generation.completed', 'generation.failed', 'batch.completed']
})
console.log(hook.secret) // Save this — it is only returned at creation
hook = client.webhooks.create(
    name="ops hooks",
    webhook_url="https://hooks.example.com/simplyfill",
    events=["generation.completed", "generation.failed", "batch.completed"],
)
print(hook.secret)  # Save this — it is only returned at creation

Response

201 Created:

{
  "id": 42,
  "name": "ops hooks",
  "webhook_url": "https://hooks.example.com/simplyfill",
  "mapping_id": null,
  "events": ["generation.completed", "generation.failed", "batch.completed"],
  "is_active": true,
  "secret": "whsec_J8s2N9b...",
  "created_at": "2026-05-17T15:40:01Z",
  "last_triggered_at": null
}

Store the secret on creation

secret is included in the create response so you can save it server-side. Subsequent GETs do not return it.

List webhook configurations

GET /api/v1/webhook-configs

Returns an array of WebhookConfigResponse objects (same shape as create response, without the secret on most rows).

Get a webhook configuration

GET /api/v1/webhook-configs/{webhook_id}

Returns one config by ID.

Update a webhook configuration

PUT /api/v1/webhook-configs/{webhook_id}

Body fields (all optional):

FieldTypeDescription
namestringNew name.
webhook_urlURLNew target URL.
eventsarrayReplace subscribed events.
is_activebooleanPause or resume deliveries.

Delete a webhook configuration

DELETE /api/v1/webhook-configs/{webhook_id}

Returns 204 No Content. Permanently removes the config and discontinues deliveries. In-flight deliveries already on the retry schedule are abandoned.

Inspect deliveries

GET /api/v1/webhook-configs/{webhook_id}/deliveries

Returns the last N delivery attempts for the named webhook, including HTTP response codes and error messages:

[
  {
    "id": 9001,
    "webhook_config_id": 42,
    "event_type": "generation.completed",
    "status": "delivered",
    "attempts": 1,
    "max_attempts": 7,
    "response_code": 200,
    "error_message": null,
    "created_at": "2026-05-17T15:41:11Z",
    "delivered_at": "2026-05-17T15:41:11Z"
  }
]

Send a test event

POST /api/v1/webhook-configs/test

Body:

{ "webhook_url": "https://hooks.example.com/simplyfill", "secret": "whsec_..." }

Fires a synthetic event and returns the response code and timing:

{
  "success": true,
  "status_code": 200,
  "response_time_ms": 127.3,
  "error": null
}

On this page