Webhook events

Silverfin supports a range of webhook events which allow you to track changes in your environment, and can function as a trigger for your own API flows based on such an event.

You subscribe to events by listing them in events when you register a webhook. A webhook's list of events can't be changed: to add or remove an event, destroy the webhook and register a new one with the full list.

Currently the API supports the following webhook events:

EventDescription
account.createdan account has been created
account.updatedan account has been updated
account.destroyedan account has been deleted
transaction_document.processeda document is processed attached to a booking (coming from the accountancy system)
transaction_document.requestedan import left the company with transaction documents awaiting upload (Sync API partners only)
permanent_document.processeda document is processed uploaded in the Silverfin documents section
permanent_entry.createda permanent document, folder or text has been created
permanent_entry.updateda permanent document, folder or text has been updated
permanent_entry.destroyeda permanent document, folder or text has been deleted
permanent_entry.restoreda permanent document, folder or text has been restored after it was deleted
comment.createda new comment is created (currently limited to remarks only, but will be extended to checks as well)
comment.updateda comment has been updated
comment.destroyeda comment has been deleted
remark.createda new remark is created (can be on any object within Silverfin: company, reconciliation, report, ...)
remark.updateda remark has been updated
remark.destroyeda remark has been deleted
custom.updateda custom property on the company is created or updated. It does not fire for custom data on reconciliations, accounts, periods or permanent texts.
period.createdwhen a period is unarchived
period.updatedwhen a period is changed from private to public or from public to private
period.destroyedwhen a period is archived
sync_state.updatedwhen a data synchronisation completes or fails, the payload contains if the sync has changed anything
financial_balances.changedwhen there are changes to financial data that might change the trial balances
company.account_mapping_list.changedwhen the company's account mapping list changes
company.mapping.updatedwhen the mapping of accounts in the company changes
export.createdwhen a new export PDF is generated
export.destroyedwhen an export has been deleted
starrings.createdwhen a reconciliation or an account is starred
starrings.destroyedwhen a reconciliation or an account is unstarred

The endpoint will send a POST request with a JSON payload to a specified target URL. It will always include the webhook, event, company and firm sections. Depending on the event, it contains one more section, described below. The document section in the example below is specific to events related to documents.


  {"webhook":
    {
      "id": 1052767521,
      "url": "http://localhost:3001/webhook",
      "events": ["transaction_document.processed", "permanent_document.processed"]
    },
  "event": "permanent_document.processed",
  "company":
    {
      "id":  398393022,
      "name": "Demo Company"
    },
  "firm":
    {
      "country":  BE,
      "id":  71238,
      "name": "Demo Firm"
    },
  "document":
    {
      "id": 147764866,
      "file_name": "permanent_test_file.docx",
      "content": "This is the content of the file",
      "download_url": "https://live.getsilverfin.com/url_of_the_actual_file",
      "permanent_document_path": ["Contract", "A private document"],
      "permanent_document_id": 411704894
    }
  }

starrings.created and starrings.destroyed

FieldContent
starrable_typereconciliation_text or account
starrablethe reconciliation or account, in the same format as the API returns it
ledger_idsthe IDs of the periods whose starring changed

Starring a reconciliation or account in one period also changes the later periods that are not locked. ledger_ids lists all of them. When a new period is created and inherits stars, the event lists only that new period.

permanent_entry.*

FieldContent
permanent_entry.idID of the document, folder or text
permanent_entry.nameits name
permanent_entry.typeits type, for example PermanentDocument
permanent_entry.content_updated_atwhen it was last updated
permanent_entry.visibilitypublic or private
permanent_entry.created_bythe user who created it
permanent_entry.documentfor documents only: the document details
permanent_entry.childrenfor destroyed and restored only: the entries inside it that were deleted or restored with it (id, type, name)

Permanent entries are the same for every period, so there is no period in the payload.

company.account_mapping_list.changed

No extra fields. Read the company's account mapping again when you receive it.

company.mapping.updated

FieldContent
account_idsthe IDs of the accounts whose mapping changed

transaction_document.requested

For Sync API partners only. It fires only for companies synced through the Sync API.

It carries no document list. Fetch the list with GET /syncs/companies/{company_id}/documents, which may already be empty if you emptied it in the meantime.

Silverfin combines events per import: batches you push while an import is still running share one event. Small batches pushed with gaps between them each count as an import of their own, so each one notifies. The event repeats on your next import for as long as any reference stays unresolved, so resolve every reference the endpoint returns: upload the document, or flag it with DELETE /syncs/companies/{company_id}/document when no document exists. References left neither uploaded nor flagged keep the event firing.


Webhook signature verification

Every request must include two signature headers: X-SF-SIGNATURE-1 and X-SF-SIGNATURE-2. These signatures are generated using your application's webhook_signing_token_1 and webhook_signing_token_2, respectively.

To confirm the authenticity of a request originating from Silverfin, you should compute its Hash-based Message Authentication Code (HMAC) using the SHA-256 digest algorithm, the request's body as data, and a webhook signing token as the key. For instance, in Ruby, you can achieve this as shown below:

OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), WEBHOOK_SIGNING_TOKEN, REQUEST_BODY)

If at least one of the computed signatures matches its respective header, you can consider the request as authentic. Matching with a single signature allows for a seamless rotation of your application's webhook signing tokens.

Retry strategy

When the endpoint doesn't reply with a 2xx code, the post will be retried with an exponential back-off over a total duration of ~48 hours. If after this time the endpoint still doesn't reply with a 2xx code, the webhook subscription will be marked as expired (disabled). Also note that an expired webhook subscription can't be revived, only deleted. To restore its functionality, the subscription will need to be re-created anew.

Throttling

Silverfin does not throttle outbound webhook events. To protect your application from occasional spikes in incoming events, you may wish to build your own solution or use a third-party service.

Timeouts

Silverfin requires the webhook receiving server to reply within a reasonable time. If the server takes too long to respond, the webhook event will be failed and be retried according to the Retry strategy described above. To avoid timeouts, you should defer processing of the payload until the server replies