curl -X POST 'https://api.fitsociety.io/public/v1/n8n/accounting/webhooks' -H 'Authorization: Bearer <n8n_access_token>' -H 'Idempotency-Key: <unique_request_key>' -H 'Content-Type: application/json' -d '{"url":"https://n8n.example.com/webhook/example","events":["invoice.created"],"signingSecret":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({url: '<string>', events: ['invoice.created'], signingSecret: '<string>'})
};
fetch('https://api.fitsociety.io/public/v1/n8n/accounting/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.fitsociety.io/public/v1/n8n/accounting/webhooks"
payload = {
"url": "<string>",
"events": ["invoice.created"],
"signingSecret": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Register or reconcile an n8n webhook
Requires an active n8n accounting connection for the authenticated company, attributed company consent and n8n provider access. The token and current grant must both include the required financial scope. Health-data and private-communication consent are not required. Only subscriptions containing exactly [invoice.created] are visible or manageable; mixed-event and other-provider subscriptions are excluded. Other providers cannot use these endpoints. Requires finance_invoice_webhooks:write and Idempotency-Key. Accepts public HTTPS callbacks, including custom HTTPS ports. Credentials, fragments, private/reserved IP addresses, mixed public/private DNS answers and redirects are rejected. Repeating a callback URL within this connection atomically updates its selected events and signing key. Supply the derived lowercase hex signing secret (HMAC-SHA256 using the client secret over fitsociety:n8n:webhook:v1: followed by the stable n8n webhook ID). Use a fresh idempotency key when changing events or rotating credentials. Delivery retries retain a stable payload id; downstream actions should deduplicate by that event ID. Standard Public API rate limits apply. Only the exact single event list [invoice.created] is accepted, including Invoice and CreditNote documents. Filter data.invoiceType after verifying the signed JSON event and companyId. A same-URL subscription with other or mixed events returns 409 and is left unchanged. Document details and PDFs separately require finance_invoices:read and finance_invoice_pdfs:read. Delivery uses the existing n8n HMAC-SHA256 JSON signature, including timestamp, delivery ID, event ID and recursively sorted JSON keys; retain the raw request body for verification and compare companyId to the owning connection.
curl -X POST 'https://api.fitsociety.io/public/v1/n8n/accounting/webhooks' -H 'Authorization: Bearer <n8n_access_token>' -H 'Idempotency-Key: <unique_request_key>' -H 'Content-Type: application/json' -d '{"url":"https://n8n.example.com/webhook/example","events":["invoice.created"],"signingSecret":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({url: '<string>', events: ['invoice.created'], signingSecret: '<string>'})
};
fetch('https://api.fitsociety.io/public/v1/n8n/accounting/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.fitsociety.io/public/v1/n8n/accounting/webhooks"
payload = {
"url": "<string>",
"events": ["invoice.created"],
"signingSecret": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Authorizations
Public API access token issued by /public/v1/oauth/token. Example: Authorization: Bearer fspt_.... Each resource request rechecks the token company's current provider access. Disabling access blocks existing tokens with 403 auth.provider_unavailable.
Headers
Required for Public API write requests. Reusing the same key with the same method, path, and body replays the stored successful response; reusing it with a different request returns 409 idempotency.conflict.
1 - 200"booking-create-20260714-001"