Webhooks

Webhooks allow your own applications or third-party services like Zapier to receive real-time notifications whenever something happens in your Synci account. Instead of polling our API for updates, Synci "pushes" the data to your URL as it occurs.

Written By Matias

Last updated 6 days ago

Configuring Webhook Endpoints

You can manage your webhooks through the Synci Dashboard under Developers > Webhooks or via the /api/v1/webhook-endpoints API endpoints.

Key Configuration Options

  • Endpoint URL: The HTTPS URL where Synci will send the POST requests.

  • Events: Choose exactly which types of events you want to receive.

  • Bank account filtering: Optionally restrict a webhook to only trigger for specific bank accounts.

  • Omit sensitive identifiers: When enabled, Synci will strip IBANs, BBANs, and other sensitive identifiers from the payload. This is required for Zapier integrations.

  • Signing secret: A unique whsec_ key used to verify that the request came from Synci. Automatically generated by Synci as you create a new webhook endpoint, and only shown once.


Event types & payload examples

All webhooks follow a standard wrapper structure:

{
  "event_type": "transactions.created",
  "event_id": "evt_8723456789",
  "webhook_endpoint_id": "endpoint_123456",
  "created_at": "2024-03-20T10:00:00Z",
  "data": { ... }
}

Transactions

transactions.created & transactions.updated

Triggered when new transactions are fetched or their status changes.

{
  "event_type": "transactions.created",
  "event_id": "evt_123",
  "data": {
    "bank_account": {
      "id": "acc_550",
      "name": "Main Checking",
      "currency": "EUR",
      "iban": "DE12345678901234567890"
    },
    "transactions": [
      {
        "id": "tx_999",
        "amount": -42.50,
        "currency": "EUR",
        "booked": true,
        "generated": {
          "date": "2024-03-20",
          "payee": "Coffee Shop",
          "description": "Coffee Shop Berlin"
        },
        "booking_date": "2024-03-20",
        "remittance_information": {
          "unstructured": "CARD PURCHASE COFFEE SHOP"
        }
      }
    ]
  }
}

Balance

balance.updated

Triggered when your bank account balance changes.

{
  "event_type": "balance.updated",
  "event_id": "evt_456",
  "data": {
    "bank_account": {
      "id": "acc_550",
      "name": "Main Checking",
      "currency": "EUR"
    },
    "balance": {
      "available": 1250.75,
      "cleared": 1200.00
    }
  }
}

Bank account

bank_account.created, bank_account.updated, bank_account.deleted

Triggered when account configurations or status change.

{
  "event_type": "bank_account.updated",
  "event_id": "evt_789",
  "data": {
    "id": "acc_550",
    "name": "Main Checking",
    "display_name": "My Daily Expenses",
    "enabled": true,
    "currency": "EUR",
    "integrator": "GOCARDLESS",
    "balance": {
      "available": 1250.75,
      "cleared": 1200.00
    }
  }
}

Testing webhooks

Building a reliable webhook integration requires thorough testing. Synci provides built-in tools to simulate events and verify how your application handles them, using either dummy data or real information from your connected accounts.

Triggering test events

You can trigger a test event in two ways.

Via the dashboard

Navigate to Developers > Webhooks, select your endpoint, and go to the "Test" tab. You can select the event type and an optional bank account to use for real data.

Via the API

Send a POST request to /api/v1/webhook-endpoints/{endpointId}/test. Include event (required) and bank_account_id (optional) in the JSON body.

Real data vs. dummy data

  • Real data: By selecting a bank account, Synci will pull the latest 2 transactions or the current balance from that account to populate the test payload. This is highly recommended for verifying that your field mapping matches your specific bank's data structure.

  • Dummy data: If no bank account is specified, Synci generates placeholder transactions and balances. This is useful for initial development and verifying signature validation.

Key testing rules

  • Rate limits: Testing is limited to 5 requests per minute per endpoint.

  • No retries: Unlike production events, test events are only sent once. If your server is down during a test, you must trigger a new test manually.

  • Event override: You can test any event type, even if it is not currently enabled in your webhook's settings.


Security: Verifying signatures

To ensure that a webhook was actually sent by Synci, you should verify the X-Synci-Signature HTTP header. This signature is an HMAC-SHA256 hash of the raw request body using your Signing Secret.

How to verify

  1. Capture the raw request body.

  2. Compute an HMAC-SHA256 hash of the raw body using your Signing Secret as the key.

  3. Compare your computed hash with the value in the X-Synci-Signature header. If they match, the request is authentic.

Examples

Example
$secret = 'whsec_your_secret'; $signature = $_SERVER['HTTP_X_SYNCI_SIGNATURE']; $payload = file_get_contents('php://input'); $computedSignature = hash_hmac('sha256', $payload, $secret); if (hash_equals($signature, $computedSignature)) { // Authenticated }

Rotating the signing secret

If you’ve lost a webhook signing secret, you can generate a new one by opening your webhook endpoint, and clicking “Rotate Secret”.

You can also rotate a webhook signing secret through the API, by sending a POST request to /api/v1/webhook-endpoints/{endpointId}/rotate-secret.


Delivery & retry logic

  • Retries: If the delivery fails (non-2xx status), Synci will retry up to 3 times.

  • Exponential backoff: Retries occur at 1 minute, 10 minutes, and 1 hour intervals.

  • Automatic disabling: If an endpoint returns a 410 Gone or fails persistently, it will be automatically disabled to protect the system.


Pro tips

  • Acknowledge quickly: Return a 2xx status code immediately and process the data asynchronously (e.g., using a queue).

  • Idempotency: Use the event_id to ignore duplicate notifications that might occur during retries.

  • Zapier: Ensure "Omit Sensitive Identifiers" is ON for Zapier to ensure data compatibility.