Webhooks Set Up
If you haven't already done so, please:
Step 1: Subscribe to receive payment status webhooks
Reach out to TxB Client Implementation team to subscribe to webhooks. When doing so, you will:
- Provide a URL to which we will send all webhooks
- Identify your preferred authentication mechanism. We offer signature verification and mTLS. You can use either or both
- Identify your preferred event grouping behavior
- Identify the events for which you want to be notified
Step 2: Receive webhooks
Once the subscription is active, you will start receiving webhook events on your URL of choice with a representative payload:
{
"deliveryId": "7a484093-f205-4004-9c5f-4c333527656e",
## Every message we send to you will be uniquely defined by a `deliveryId`
## One `deliveryId` can contain between 1 and N individual events
## The maximum number of a events in a message is configurable
"events": [
{
"eventName": "PAYMENT_STATUS.RELEASED",
## eventNames correspond to the event trigger
## for example, PAYMENT_STATUS.RELEASED indicates
## that a payment you initiated has been released to
## a payment network
"eventId": "7a484093-f205-4004-9c5f-4c333527656e",
"eventTimestamp": "2021-02-01T16:56:46.384Z",
## the time at which an event was created. Note that events
## may be delivered after the point at which they are created
"eventData": {
## event data provides the object which has changed status
## which is, in thise case, a payment
"identifiers": {
"paymentRequestId": "myuniquepaymentrequest123",
"paymentEndToEndId": "trackthispayment123",
"gsUniquePaymentId": "gsuniquetracker123",
"railReferenceId": {},
"gsPostingIds": [
"ledgerPostingId123"
]
},
"paymentExecutedValueDate": "2021-06-21",
"amount": 101,
"amountType": "PAYMENT",
"paymentCurrency": "USD",
"paymentStatus": {
"status": "RELEASED",
"statusTime": "2020-12-01T16:55:42.279Z"
},
"returns": {
"hasReturnDetails": false
},
"cancelations": {
"hasCancelationDetails": false
},
"cases": {
"hasLinkedCases": false
}
}
}
}
Step 3: Authenticate the webhooks
If you plan to authenticate webhooks via mTLS, then reach out to TxB Client Implementation to exchange certs.
If you plan to authenticate webhooks by verifying the signature in the webhook header (X-GS-Signature), then follow the below steps:
GET /v1/keys/{keyId} returns:
{
"n": "kV5sUJIqR_qONymuDKp7tZfzWbGXLyAPTEnl0HLpb5bOFN-PaukVE_D34pXXYLrMLStKosq0rqC8z_KotRfcSwlpON_AWJwHg6oxWnXRqKo9rVqtr3sj2QP9FtyakozT_PmvDeV3-syic3NtmtY26eN9O6jdVoJ5sfJD6A0whg52PU0Do4XLd7GtXUSD5DSYHfvEu7u9hR1oGXiQeHjTpSmVuj87vO8uBpfauIT-FdfvjHWjsuhS7DbXzGy_KTbwbR8pbLgIpGd194PuO2A55-0HxCNzOM47bg5S2bQkT4ejcs65IY1C-5PqnS3dS9xjcNm-IbYJq98Oio9dX4wl",
"e": "AQAB",
"use": "sig",
"alg": "RS256",
"kty": "RSA",
"kid": "abefe829-24d2-4993-b56c-e49502eea61f"
}Use the key set to confirm that the message was indeed sent by TxB. Cache the key for verification of subsequent webhooks.
Create an RSAPublicKeySpec from the modulus and exponent of the public JWK as shown below
String modulus = “qpaHppHFL4eygwPejubv48lKAGKsIIU4QtczXyxDoYN3Ec81AHgVC4emCcyGTr8VqUfBZvSCzlkJ1_A9t6rrjvAf7oEoamIuc5bC_X35YVVx7F1lo5390biCiwNnmMru0X1HDKZOtL5AZNi6IAll1MP_EGhvzFWRkGvlYe_xsBw7qa7plgtCn-PYfq9oyIyvfteKzV6b_CHObgxnLN9cq1mvr04hDD8uxNtqSna_5PtKiTt0ZUBbYK8sLCDMEA_0-5pKoW8AK3nxQFV7kkke56quwg4bRzwsU7XfWbfPE4ug9bP_VNcM7YLHkzFHdvcbXQUrqggBezlYY5tZJCOuPQ”
String exponent = "AQAB";
BigInteger n = Base64URL.from(modulus).decodeToBigInteger();
BigInteger e = Base64URL.from(exponent).decodeToBigInteger();
RSAPublicKeySpec spec = new RSAPublicKeySpec(n, e);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(spec);Generate a signature using the received payload + timestamp + key ID
String timestamp = "1615786608057";
String keyId = "134b180c-136b-4462-b3ae-1a5249854f6f";
String message = jsonPayload + "\n" + timestamp + "\n" + keyId;
byte[] rawMessage = message.getBytes(StandardCharsets.UTF_8);
Signature signatureSHA256Java = Signature.getInstance("SHA256withRSA");
signatureSHA256Java.initVerify(publicKey);
signatureSHA256Java.update(rawMessage);Verify this with the received signature (x-gs-signature header)
String signature = "V7n2Ci4kiWXrIO_XdTNxvBsL35Q1lAN6LEjBluLUTs1N-nryW1B_m1X2UBsRsxAjf_5ApQ3x-yR6i7Kbd67KL2nQl2VtpoGR_yG1WZXgDTAHDaF78qrdKTbeXjcmasyKGXHs5uSCKOSsBP96FF-5oGfR3QwDyAl6S_fjqqgyTGU0kqxX2TjOgEeyMhZxg1UOvzYKyaf2DjWZSE-NQBlFl3uPtENkILHdjDbsbuQneHPS3R0-ivpb5FsG2BsS4CP0v1T79m8DhshJ215QAAZnCgJY1svTl3yHYjwIS56EqifQRjfvZGbtM13Xmuj7ONOZZhv9dNfygqTW4rxo4BiKmQ==";
byte[] recdBytes = Base64.getUrlDecoder().decode(signature);
boolean isCorrect = signatureSHA256Java.verify(recdBytes);
Responses to a webhook
Once you receive a callback from TxB, you're expected to respond with one of the following codes:
| HTTP Response Expected | Description | Automatic Retries | Example Body of Response |
|---|---|---|---|
| 200 | Success | n/a | null |
| 207 | Partial success | No | {"eventId": "Payment1234", "errorDescription": "Payment end to end ID not found"} |
| 400 | Bad request | No | null |
| 401 | Authentication failed | No | null |
| 403 | Unauthorized to access resource | No | null |
| 404 | Resource not found | No | null |
| 408 | Time out | Yes | null |
| 429 | Too many requests | Yes | null |
| 5XX | Error | Yes | null |
If TxB receives a 408, 429, or 5XX status code, then we will automatically retry to send the event. Otherwise, please use the payment status API to poll for an update. We also suggest using the payment status API periodically to reconcile payments which have not hit a terminal state for several days.
Was this page useful?
Give feedback to help us improve developer.gs.com and serve you better.