There are two types of webhooks that you can receive from Transcend:
Each of these webhooks uses the same form of authentication.
Receive a webhook by creating a route that listens for new POST requests at your pre-registered URL (please refer to either of the above guides to learn about registering your webhook URL). The webhook will contain a JSON payload in the request body and a header, x-sombra-token
, containing an asymmetrically signed token.
Endpoint reference: JWT public key
Webhooks will always be signed with an asymmetric digital signature algorithm. This is a JSON Web Token → that is signed with a private key. You will verify the token with a public key that can be on your Sombra gateway.
- Choose a JWT library for your language. It must support
ES384
. - Read the HTTP request header
x-sombra-token
. - Read the public key from Sombra at the path
/public-keys/sombra-general-signing-key
. We recommend caching this value. Note this is an authenticated route. You can read about making a request to our API here. - Using the
verify
function with the algorithmES384
, verifyx-sombra-token
against the public key.
Signature verification is an important security feature that ensures webhooks are coming from Transcend. Always make sure the signature is valid before proceeding with any operation.
It's important that you only use
ES384
as the signature verification algorithm. Allowing other algorithms can open security vulnerabilities.You can either hard code or programmatically read the public key. Both the public key as well as the public key URL are available in the Admin Dashboard. We will notify you in advance of key rotations.
// Librariesconst got = require('got');const jwt = require('jsonwebtoken');// URL of your Sombra gatewayconst SOMBRA_URL = '{{yourOrganizationSombraURL}}';// API key for Transcend API issued at https://app.transcend.io/settings#Developer// NOTE: this is a secret. Please handle with careconst TRANSCEND_API_KEY = '~~SECRET-TRANSCEND-API-KEY-SECRET~~';// Only needed if self-hosting gateway. Uses bearer auth// NOTE: this is a secret. Please handle with careconst SOMBRA_API_KEY = '~~SECRET-SOMBRA-API-KEY-SECRET~~';// Global to cache the webhook signing public keylet cachedPublicKey;/*** Helper to verify incoming webhook requests** @param {string} signedToken - the `x-sombra-token` header, which is a JSON* Web Token asymmetrically signed with ES384.** @returns {Object} - the signed body*/module.exports = async function verifyAndExtractWebhook(signedToken) {// Get the public key and cache it for next time.if (!cachedPublicKey) {try {const response = await got.get(`${SOMBRA_URL}/public-keys/sombra-general-signing-key`,{headers: {authorization: `Bearer ${TRANSCEND_API_KEY}`,// only needed if self-hosting Sombra with bearer auth enabled'x-sombra-authorization': SOMBRA_API_KEY? `Bearer ${SOMBRA_API_KEY}`: undefined,},});cachedPublicKey = response.body;} catch (err) {console.error('Failed to get public key:', err);}}// Verify webhook signature with the public key (ensure Transcend sent the request)const signedBody = jwt.verify(signedToken, cachedPublicKey, {// important to specify the algorithmalgorithms: ['ES384'],});return signedBody;};
We have working examples on GitHub.