Webhooks
Webhooks
Webhook endpoint management for receiving real-time event notifications. Configure URLs, select events, and monitor delivery status.
Event types
Subscribe to any combination of these events:
| Category | Events |
|---|---|
| Invoices | invoice.created invoice.updated invoice.sent invoice.paid invoice.overdue invoice.cancelled |
| Customers | customer.created customer.updated customer.deleted |
| Payments | payment.received payment.failed |
| Estimates | estimate.created estimate.sent estimate.accepted estimate.rejected |
| Credit notes | credit_note.created credit_note.issued |
| Advance invoices | advance_invoice.created advance_invoice.paid advance_invoice.applied |
Payload format
Every webhook delivery sends a JSON body with this structure:
{ "event": "invoice.created", "data": { ... }, "timestamp": "2024-01-15T10:30:00.000Z"}Delivery headers
Each delivery includes these headers:
| Header | Description |
|---|---|
X-Webhook-Signature | HMAC-SHA256 signature: sha256=<hex> |
X-Webhook-Timestamp | Unix timestamp (seconds) when the payload was signed |
X-Webhook-Event | Event type (e.g. invoice.created) |
X-Webhook-Delivery | Unique delivery attempt ID |
X-Webhook-Id | Webhook endpoint ID |
User-Agent | SpaceInvoices-Webhook/1.0 |
Verifying signatures
Signatures use HMAC-SHA256. To verify:
- Get the raw request body (do not parse it first)
- Compute
HMAC-SHA256(secret, body)using your webhook secret - Compare the hex digest with the value after
sha256=inX-Webhook-Signature
const crypto = require('crypto');
function verifySignature(secret, payload, signature) { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return signature === `sha256=${expected}`;}Retry policy
Failed deliveries are retried up to 5 attempts with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
Webhooks are automatically disabled after all retry attempts are exhausted, and an email notification is sent to the entity owner.
HTTP status codes 400, 401, 403, 404, 405, and 410 are treated as permanent failures and are not retried.
The Webhook object
Attributes
Masked secret (only shown on create and rotate)
Default: {}
{
"id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"url": "https://example.com/webhooks",
"description": null,
"secret": "whsec_****...****",
"events": [
"invoice.created",
"invoice.paid"
],
"active": true,
"metadata": {},
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}Create a new webhook
/webhooksCreate a webhook endpoint. The response includes the full secret which is only visible on creation and when rotated.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Body parameters
The HTTPS URL to send webhook events to. Cannot target localhost, private IPs, or internal domains.
Events that trigger this webhook
Optional description for this webhook
Whether webhook is active
Default: true
Custom key-value data for your own use. Store any JSON object up to 50 properties. Values must be strings up to 250 characters. Useful for storing external IDs, tags, or integration data.
curl -X POST "https://eu.spaceinvoices.com/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks",
"events": [
"invoice.created"
]
}'Returns
Default: {}
{
"id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"url": "https://example.com/webhooks",
"description": null,
"secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"events": [
"invoice.created",
"invoice.paid"
],
"active": true,
"metadata": {},
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}List all webhooks
/webhooksRetrieve a paginated list of webhooks for the entity. Secrets are masked in the response.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Query parameters
Number of results per request.
Default: 10
Cursor to fetch the next page of results. Use the value from pagination.next_cursor in the previous response.
Cursor to fetch the previous page of results. Use the value from pagination.prev_cursor in the previous response.
Whether to include the total count of items in pagination.total.
Default is true.
When false, pagination.total returns -1 for better performance.
curl "https://eu.spaceinvoices.com/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID"Returns
{
"data": [
{
"id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"url": "https://example.com/webhooks",
"description": null,
"secret": "whsec_****...****",
"events": [
"invoice.created",
"invoice.paid"
],
"active": true,
"metadata": {},
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}
],
"pagination": {
"total": 1,
"next_cursor": null,
"prev_cursor": null,
"has_more": false
}
}Get a webhook by ID
/webhooks/{id}Retrieve a single webhook. The secret is masked in the response.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Path parameters
Unique resource identifier
curl "https://eu.spaceinvoices.com/webhooks/{id}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID"Returns
Masked secret (only shown on create and rotate)
Default: {}
{
"id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"url": "https://example.com/webhooks",
"description": null,
"secret": "whsec_****...****",
"events": [
"invoice.created",
"invoice.paid"
],
"active": true,
"metadata": {},
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}Update a webhook
/webhooks/{id}Update webhook URL, events, active status, or description.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Path parameters
Unique resource identifier
Body parameters
The HTTPS URL to send webhook events to. Cannot target localhost, private IPs, or internal domains.
Custom key-value data for your own use. Store any JSON object up to 50 properties. Values must be strings up to 250 characters. Useful for storing external IDs, tags, or integration data.
curl -X PATCH "https://eu.spaceinvoices.com/webhooks/{id}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID" \
-H "Content-Type: application/json" \
-d '{
"url": "https://new-url.example.com/webhooks"
}'Returns
Masked secret (only shown on create and rotate)
Default: {}
{
"id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"url": "https://example.com/webhooks",
"description": null,
"secret": "whsec_****...****",
"events": [
"invoice.created",
"invoice.paid"
],
"active": true,
"metadata": {},
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}Delete a webhook
/webhooks/{id}Permanently delete a webhook endpoint. Pending deliveries will be cancelled.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Path parameters
Unique resource identifier
curl -X DELETE "https://eu.spaceinvoices.com/webhooks/{id}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID"Returns
{
"success": true
}Test a webhook
/webhooks/{id}/testSend a test event to the webhook endpoint to verify connectivity.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Path parameters
Unique resource identifier
curl -X POST "https://eu.spaceinvoices.com/webhooks/{id}/test" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID"Returns
{
"id": "whd_6595a27b5d35015c3ef0c3fd",
"webhook_id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"event_type": "webhook.test",
"status": "success",
"request_body": {
"event": "webhook.test",
"data": {}
},
"response_status": 200,
"response_body": "OK",
"error_message": null,
"attempt": 1,
"max_attempts": 1,
"next_retry_at": null,
"duration_ms": 150,
"created_at": "2024-01-01T00:00:00.000Z",
"completed_at": "2024-01-01T00:00:00.150Z"
}List webhook deliveries
/webhooks/{id}/deliveriesRetrieve a paginated list of delivery attempts for a specific webhook.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Path parameters
Unique resource identifier
Query parameters
Number of results per request.
Default: 10
Cursor to fetch the next page of results. Use the value from pagination.next_cursor in the previous response.
Cursor to fetch the previous page of results. Use the value from pagination.prev_cursor in the previous response.
Whether to include the total count of items in pagination.total.
Default is true.
When false, pagination.total returns -1 for better performance.
curl "https://eu.spaceinvoices.com/webhooks/{id}/deliveries" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID"Returns
{
"data": [
{
"id": "whd_6595a27b5d35015c3ef0c3fd",
"webhook_id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"event_type": "invoice.created",
"status": "success",
"request_body": {
"event": "invoice.created",
"data": {
"id": "inv_123"
}
},
"response_status": 200,
"response_body": "OK",
"error_message": null,
"attempt": 1,
"max_attempts": 5,
"next_retry_at": null,
"duration_ms": 120,
"created_at": "2024-01-01T00:00:00.000Z",
"completed_at": "2024-01-01T00:00:00.120Z"
}
],
"pagination": {
"total": 1,
"next_cursor": null,
"prev_cursor": null,
"has_more": false
}
}Rotate webhook secret
/webhooks/{id}/rotate-secretGenerate a new signing secret for the webhook. The previous secret is immediately invalidated.
Header parameters
Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.
Path parameters
Unique resource identifier
curl -X POST "https://eu.spaceinvoices.com/webhooks/{id}/rotate-secret" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "x-entity-id: YOUR_ENTITY_ID"Returns
Default: {}
{
"id": "whk_6595a27b5d35015c3ef0c3fd",
"entity_id": "ent_6595a27b5d35015c3ef0c3fd",
"url": "https://example.com/webhooks",
"description": null,
"secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"events": [
"invoice.created",
"invoice.paid"
],
"active": true,
"metadata": {},
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
}