Webhooks
Learn how to register your application to receive and verify webhook notifications from Teller and be notified of events not represented in the Teller API itself
Teller can send you webhook events related to your application and its enrollments, e.g. when an enrollment is disconnected and the user should reconnect using Teller Connect, Teller will send you a webhook event of type enrollment.disconnected
and your application can take appropriate action.
Registering Webhooks
To register a new webhook, you need to have a URL in your app that Teller can call. You can configure a new webhook from the Teller Dashboard under Application Settings.
Now, whenever something of interest happens in your app, a webhook is fired off by Teller. In the next section, we'll look at how to consume webhooks.
Consuming Webhooks
When your app receives a webhook request from Teller, check the type
attribute to see what event caused it. The first part of the event type categorizes the payload type, e.g., enrollment
, transaction
, etc.
Example webhook payload
{
"id": "wh_oiffb5cocakqmksbkg000",
"payload": {
"enrollment_id": "enr_oiffb5cocakqmksbkg001",
"reason": "disconnected.account_locked"
},
"timestamp": "2023-07-10T03:49:29Z",
"type": "enrollment.disconnected"
}
In the example above, an enrollment has entered a disconnected state because the financial institution has completely locked the account. This may happen for legal reasons, because an account has been involved in fraud, or an attacker has repeatedly tried to login by guessing the end user's credentials.
The Webhook Object
The webhook object has the following shape:
- Name
id
- Type
- string
- Description
The id of the webhook event
- Name
payload
- Type
- object
- Description
Event specific data or an empty object if
"type": "webhook.test"
- Name
timestamp
- Type
- string
- Description
The ISO 8601 timestamp of the event.
- Name
type
- Type
- string
- Description
The type of the event, either:
enrollment.disconnected
— Sent when the enrollment disconnectedtransactions.processed
— Sent when transactions are categorized by Teller's transaction enrichmentaccount.number_verification.processed
- Sent when account details verification via microdeposit has either suceeded or expired (see 'Verify Account Details via Microdeposit')webhook.test
— A test event triggered from the Application Settings page. Use this to test your webhook implementation.
The shape of the payload
depends on the event's type
Payload shape
- Name
enrollment_id
- Type
- string
- Description
The id of the affected enrollment
- Name
reason
- Type
- string
- Description
Available when
"type": "enrollment.disconnected"
onlyThe reason the enrollment was disconnected. Possible values:
disconnected
disconnected.account_locked
disconnected.credentials_invalid
disconnected.enrollment_inactive
disconnected.user_action.captcha_required
disconnected.user_action.contact_information_required
disconnected.user_action.insufficient_permissions
disconnected.user_action.mfa_required
disconnected.user_action.web_login_required
- Name
transactions
- Type
- array
- Description
Available when
"type": "transactions.processed"
onlyAn array of categorized transactions. The shape of the transaction objects is described in the Transactions page
- Name
account_id
- Type
- string
- Description
Available when
"type": "account.number_verification.processed"
onlyThe id of the account the details of which needed to be verified
- Name
status
- Type
- string
- Description
Available when
"type": "account.number_verification.processed"
onlyThe status of the verification. Possible values:
completed
expired
Verifying Messages
Teller signs every webhook event with all non-expired signing secrets, that only you and Teller know. You can get your signing secrets from the Application Settings page.
Teller sends a signature in the Teller-Signature HTTP header:
Teller-Signature: t=signature_timestamp,v1=signature_1,v1=signature_2,v1=...
Most of the time there will be only one non-expired signing secret, so the signature header will look like this:
Teller-Signature: t=signature_timestamp,v1=signature
To verify that the payload was created by Teller, you have to calculate the signature and it must be equal to the signature extracted from the signature header.
To calculate the signature:
- Create
signed_message
by joiningsignature_timestamp
and the request's JSON body with a . character - Compute HMAC with SHA-256 using the non-expired signing secret as the key and
signed_message
as the message
To prevent replay attacks you should reject webhook events with a signature_timestamp
(Unix time) older than 3 minutes.
Expiring Secrets
When you have a policy to periodically roll secrets, Teller allows you to do it without a gap in signature verification.
To expire the current signing secret, go to the Application Settings page and select when the secret should expire, e.g. in 2 hours. When you press Save, Teller will create a new non-expired secret, and from that moment, Teller will sign all webhook events with both secrets until the old secret expires:
Teller-Signature: t=signature_timestamp,v1=signature_with_new_secret,v1=signature_with_old_secret
This gives you time to update your application with the new secret.