Webhooks Overview
Koteshen webhooks allow you to receive real-time notifications for key events in your invoicing workflow, such as invoice creation, updates, sending, payments, and overdue status changes. Webhooks are delivered as HTTP POST requests to a URL you specify, with a JSON payload containing event details.
Key Concepts
- Events: Webhooks are triggered by specific events (e.g.,
invoice.created). You subscribe to events when creating a webhook endpoint. - Subscriptions: Manage webhook endpoints via the API to subscribe/unsubscribe from events and configure delivery URLs.
- Security: Each webhook includes a
secretfor signature verification. Use theX-Koteshen-Signatureheader (HMAC SHA256 of the payload using your secret) to validate requests. - Retries: Failed deliveries (non-2xx responses) are retried up to 5 times with exponential backoff (1min, 5min, 15min, 1hr, 3hr).
- Payload: All payloads include
event(string),data(event-specific object), andoccurred_at(ISO 8601 timestamp). - API Version: Webhooks use
v1payloads unless specified otherwise.
Supported Events
| Event Name | Description | Triggered When |
|---|---|---|
invoice.created |
A new invoice is created. | Invoice saved for the first time. |
invoice.updated |
An invoice is updated (e.g., items, status). | Any field change, excluding payments. |
invoice.sent |
An invoice is marked as sent/emailed. | Status changes to “sent”. |
invoice.paid |
An invoice receives a payment. | New payment applied (full or partial). |
invoice.overdue |
An invoice becomes overdue. | Due date passes without full payment. |
Event Payload Examples
invoice.created
{ "event": "invoice.created", "data": { "id": 150, "number": "INV-8E5E-2268", "customer_id": 13, "currency": "USD", "total": { "cents": 43700, "currency_iso": "USD" }, "status": "created", "issued_at": "2025-10-12T00:00:00.000Z", "due_at": "2025-10-12T00:00:00.000Z" // Full invoice object (see Show Invoice docs for structure) }, "occurred_at": "2025-10-21T03:39:57.913Z" }
invoice.updated
{ "event": "invoice.updated", "data": { "id": 150, "number": "INV-8E5E-2268", // Changes only (diff from previous state) "status": "sent", // Example change "updated_at": "2025-10-21T04:00:00.000Z" // Full updated invoice object }, "occurred_at": "2025-10-21T04:00:00.000Z" }
invoice.sent
{ "event": "invoice.sent", "data": { "id": 150, "number": "INV-8E5E-2268", "emailed_at": "2025-10-21T04:00:00.000Z" // Full invoice object }, "occurred_at": "2025-10-21T04:00:00.000Z" }
invoice.paid
{ "event": "invoice.paid", "data": { "id": 150, "number": "INV-8E5E-2268", "balance": { "cents": 0, "currency_iso": "USD" }, // Updated balance "payments": [ { "id": 37, "reference": "Payment 123", "amount": { "cents": 34000, "currency_iso": "USD" }, "paid_at": "2025-10-12T00:00:00.000Z" } ] // Full invoice object }, "occurred_at": "2025-10-21T04:41:11.901Z" }
invoice.overdue
{ "event": "invoice.overdue", "data": { "id": 150, "number": "INV-8E5E-2268", "due_at": "2025-10-12T00:00:00.000Z", "balance": { "cents": 43700, "currency_iso": "USD" } // Full invoice object }, "occurred_at": "2025-10-21T10:00:00.000Z" // When overdue check runs }
Managing Subscriptions
Use the endpoints below to create, view, update, and delete webhook subscriptions. Each subscription targets a specific URL and set of events.
POST /api/v1/webhook_endpoints
Create a new webhook endpoint subscription.
Path Parameters
None.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | The HTTPS URL to receive webhook deliveries. Must support POST and return 2xx on success. |
enabled_events |
array | Yes | List of events to subscribe to (e.g., ["invoice.created", "invoice.paid"]). See supported events above. |
Example Request
{ "url": "https://your-app.com/webhooks/koteshen", "enabled_events": [ "invoice.created", "invoice.updated", "invoice.sent", "invoice.paid", "invoice.overdue" ] }
Response
| Status | Description |
|---|---|
201 Created |
Subscription created successfully. |
Response Body
{ "data": { "id": 1, "url": "https://koteshen.com/api/v1/webhook_endpoints/1.json", "enabled_events": [ "invoice.created", "invoice.updated", "invoice.sent", "invoice.paid", "invoice.overdue" ], "secret": "7410cb06136ce53dd5c5f7a270f5652743e1f17c", "api_version": "v1", "enabled": true, "created_at": "2025-10-17T23:56:10.396Z", "updated_at": "2025-10-18T05:12:54.125Z" } }
secret: Use this to verify incoming webhook signatures. Keep it secure—it’s shown only once on creation.enabled: Defaults totrue. Set tofalseto pause deliveries without deleting.
Error Responses
| Status | Description | Example Body |
|---|---|---|
400 Bad Request |
Invalid URL or events. | {"error": "Invalid event: 'invalid.event'"} |
422 Unprocessable Entity |
Missing required fields. | {"error": "URL is required"} |
Usage Notes
- Limit: Up to 10 active subscriptions per business.
- HTTPS only: URLs must use HTTPS.
- Verification: On creation, a test
pingevent may be sent to validate the URL.
GET /api/v1/webhook_endpoints
List all webhook endpoint subscriptions.
Path Parameters
None.
Query Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
page |
integer | Page number for pagination. | 1 |
per_page |
integer | Items per page (1-100). | 10 |
Example Request
GET /api/v1/webhook_endpoints?page=1&per_page=5
Response
| Status | Description |
|---|---|
200 OK |
List of subscriptions. |
Response Body
{ "data": [ { "id": 1, "url": "https://your-app.com/webhooks/koteshen", "enabled_events": ["invoice.created", "invoice.paid"], "secret": "7410cb06136ce53dd5c5f7a270f5652743e1f17c", // Omitted for security in lists "api_version": "v1", "enabled": true, "created_at": "2025-10-17T23:56:10.396Z", "updated_at": "2025-10-18T05:12:54.125Z" } ], "meta": { "pagination": { "current_page": 1, "total_pages": 1, "total_count": 1 } }, "links": { "self": "https://koteshen.com/api/v1/webhook_endpoints?page=1", "first": "https://koteshen.com/api/v1/webhook_endpoints?page=1", "last": "https://koteshen.com/api/v1/webhook_endpoints?page=1" } }
Error Responses
| Status | Description | Example Body |
|---|---|---|
401 Unauthorized |
Invalid token. | {"error": "Unauthorized"} |
GET /api/v1/webhook_endpoints/{id}
Retrieve a specific webhook endpoint subscription.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes | The subscription ID. |
Example Request
GET /api/v1/webhook_endpoints/1
Response
| Status | Description |
|---|---|
200 OK |
Subscription details. |
Response Body
{ "data": { "id": 1, "url": "https://your-app.com/webhooks/koteshen", "enabled_events": ["invoice.created", "invoice.paid"], "secret": "7410cb06136ce53dd5c5f7a270f5652743e1f17c", "api_version": "v1", "enabled": true, "created_at": "2025-10-17T23:56:10.396Z", "updated_at": "2025-10-18T05:12:54.125Z" } }
Error Responses
| Status | Description | Example Body |
|---|---|---|
404 Not Found |
Subscription not found. | {"error": "Not found"} |
PATCH /api/v1/webhook_endpoints/{id}
Update an existing webhook endpoint subscription.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes | The subscription ID. |
Request Body
| Parameter | Type | Description |
|---|---|---|
url |
string | New delivery URL (optional). |
enabled_events |
array | Updated list of events (optional). |
enabled |
boolean | Enable/disable deliveries (optional). |
Example Request
{ "enabled_events": ["invoice.created", "invoice.overdue"], "enabled": true }
Response
| Status | Description |
|---|---|
200 OK |
Updated subscription. |
Response Body Same as GET /api/v1/webhook_endpoints/{id}.
Error Responses
| Status | Description | Example Body |
|---|---|---|
400 Bad Request |
Invalid events. | {"error": "Invalid event"} |
404 Not Found |
Subscription not found. | {"error": "Not found"} |
DELETE /api/v1/webhook_endpoints/{id}
Delete a webhook endpoint subscription.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes | The subscription ID. |
Example Request
DELETE /api/v1/webhook_endpoints/1
Response
| Status | Description |
|---|---|
204 No Content |
Subscription deleted. No body returned. |
Error Responses
| Status | Description | Example Body |
|---|---|---|
404 Not Found |
Subscription not found. | {"error": "Not found"} |
Usage Notes
- Deleting a subscription stops all deliveries immediately.
- No undo—use PATCH to disable instead if needed.
Integration Tips
- Verification Code: Compute
HMAC-SHA256(payload, secret)and compare toX-Koteshen-Signatureheader. - Idempotency: Use
occurred_atand event IDs to deduplicate. - Testing: Use tools like webhook.site for initial setup. Trigger test events via API (e.g., create an invoice).
- Rate Limits: Webhooks are rate-limited per subscription (1000/min).
- Support: For issues, contact support@koteshen.com with subscription ID and event samples.