Get Started with Webhooks
This tutorial guides you through setting up the Webhooks API and creating your first webhook subscription. Some steps are dependent on your system's security policy.
Setup Workflow
Before You Begin
Before you begin this tutorial, complete these set up tasks in Get Started with REST to enable your system to send and receive REST API messages:
- Create a merchant test account
- Create a REST API key
- Create a custom integration or install the REST Client SDK to send and receive REST API messages
- Verify that your system can send and receive API messages
Testing
A Postman collection is available for you to test the Webhooks REST API. Contact your account manager to request the collection.
Set Up Server
Set up a server with a URL to receive webhook notifications. When setting up the server, configure its security allowlist to permit these IP addresses:
Allowlist
- 198.241.206.21
- 198.241.207.21
Trust the Root Certificate
Download the Visa Corporate Root CA - G2 certificate from the Visa Public Key Infrastructure webpage, and add it to your Java keystore: https://enroll.visaca.com
OAuth Token Endpoint
If you use the OAuth or OAuth with JWT security policy, your server must also expose an OAuth token endpoint. You provide that endpoint URL when you create a subscription.
Create Shared Secret Key Pair
Every webhooks integration requires a shared secret key pair: a key pair used for HTTP signature authentication, consisting of a key and a shared secret key. API keys are used to authenticate the requests you send to . You must create separate keys for the testing and production environments.
Create Shared Secret Key
Follow these steps to create a shared secret key pair:
On the left navigation panel, choose Payment Configuration > Key Management.
Click + Generate key on the Key Management page.
Under REST APIs, choose REST – Shared Secret, and then click Generate key.
The Key Generation page appears.
If you are using a portfolio account, the Key options window appears, giving you the choice to create a meta key. For more information about how to create a meta key, see Meta Keys .
The Confirmation Key Generation window appears.
Click Generate key after reviewing the key details.
The Key Generation page appears.
Click Download key .
The .pem file downloads to your desktop.
The Key value is your key ID and the Shared Secret value is your shared secret key.
To create or submit another key, click Generate another key. To view all of your created keys, go to the Key Management page.
Test Your Shared Secret Key Pair
After creating your key certificate, you must verify that it can successfully process API requests. This task explains how to test and validate your shared secret key pair in the Developer Center and the .
Follow these steps:
Go to the API Reference page:
Under Authentication and Sandbox Credentials, go to the Authentication Type drop-down menu and choose HTTP Signature.
Enter your organization ID in the Organization ID field.
Enter your key ID in the Key field.
Enter your shared secret key in the Shared Secret Key field.
Click Update Credentials.
A confirmation message verifies that your credentials are successfully updated.
On the left navigation panel, choose Payments > POST Process a Payment.
Click Send.
A message confirms that your request is successful with the status code 201.
Log in to the .
On the left navigation panel, choose Transaction Management > Transactions.
Under Search Results, verify that the request ID from the test authorization response is listed in the Request ID column.
Request Digital Signature Key
You must create a digital signature key to enable to send notifications to your servers. The Webhooks platform retrieves your credentials from the key to digitally authenticate your notifications. Replace the digital signature key every year. When you generate a new digital signature key, your previous key becomes invalid and new transactions must use the new key.
Notifications that use message-level encryption (MLE) must also use the digital signature key.
After you set up a webhook subscription, you can validate each notification you receive using your digital signature key.
Endpoints
POST /kms/egress/v2/keys-sym
POST /kms/egress/v2/keys-sym
POST /kms/egress/v2/keys-sym
Example: Creating a Digital Signature Key
{ "clientRequestAction": "CREATE", "keyInformation": { "provider": "nrtd", "tenant": "merchantName", "keyType": "sharedSecret", "organizationId": "merchantName" }}{"submitTimeUtc": "2021-03-17T06:53:06+0000","status": "SUCCESS","keyInformation": {"provider": "NRTD","tenant": "merchantName","organizationId": "merchantName","keyId": "bdc0fe52-091e-b0d6-e053-34b8d30a0504","key": "u3qgvoaJ73rLJdPLTU3moxrXyNZA4eo5dklKtIXhsAE=","keyType": "sharedSecret","status": "Active","expirationDate": "2022-03-17T06:53:06+0000"}}Required Fields for Creating a Digital Signature Key
| Field | Description |
|---|---|
clientRequestAction | Set the value to CREATE. |
keyInformation. | Set to a number of days. We recommend 365. |
keyInformation. | Set the value to sharedSecret. |
keyInformation. | Set the value to the organization ID of the organization requesting the key. |
keyInformation. | Set the value to nrtd. |
keyInformation. | Set the value to the organization ID of the organization requesting the key. |
Validate Your Digital Signature
You can use the digital signature key to verify that the webhook notifications you receive are from . Verifying your webhook notifications validates their integrity and helps prevent replay attacks.
When you receive a webhook notification from , it contains a digital signature key. You can configure your system to compare the notification's digital signature to the digital signature you created. If the digital signatures match, the notification is validated.
Complete these tasks to validate the webhook notifications that you receive:
- Create a digital signature key by sending a create a digital signature key request to . You may have already completed this requirement while setting up your first webhook subscription.
- Extract the digital signature from the digital signature key that you created.
- Configure your system to compare your digital signature to the digital signatures in the notifications that you receive. A webhook notification is valid if the notification's digital signature matches your digital signature.
Digital Signature Format
When you receive a webhook notification from , it contains a v-c-signature header in this format:
v-c-signature: t=1617830804768;keyId=bf44c857-b182-bb05-e053-34b8d30a7a72;sig=CzHY47nzJgCSD/BREtSIb+9l/vfkaaL4qf9n8MNJ4CY=;The header contains these three parameters concatenated with semicolons:
t: The timestamp at which the digital signature key was created.keyId: The digital signature key ID.sig: The digital signature. It is encrypted using the HMAC-SHA256 algorithm.
Validating a Notification
Follow these steps to validate the integrity of your webhook notifications.
Separate the signature parameters with a semicolon (;) and extract the
t,keyId, andsigvaluesUse the
keyIdvalue to fetch the digital signature keyGenerate the payload by concatenating the timestamp and the payload from the body of the notification, using a period (.) to join them
Use the SHA-256 algorithm to encrypt the generated payload from Step 3 using the key from Step 2
Verify that the encrypted value matches the value in
sigparameter
Example: Validating a Notification
This example shows a system script that validates webhook notifications by comparing the merchant's digital signature with the webhook notification's signature. Use this example as a reference for how to configure your system.
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.nio.charset.StandardCharsets;import java.util.Arrays;import java.util.Base64;public class Validator { public static void main(String[] args) { // Sample signature header String signatureHeader = "v-c-signature: t=1617830804768;keyId=bf44c857-b182-bb05-e053-34b8d30a7a72;sig=CzHY47nzJgCSD/BREtSIb+9l/vfkaaL4qf9n8MNJ4CY="; String payload = "this is a decrypted payload"; // Convert the received signatureHeader into timestamp, keyId, and signature. DigitalSignature companySignature = new DigitalSignature(signatureHeader); // Check if the timestamp is within tolerance. if (companySignature.isValidTimestamp()) { // Client regenerates their signature using the timestamp from header and received payload. byte[] signature = regenerateSignature(companySignature.getTimestamp(), payload); // Check if the generated signature is same as signature received in header. if (isValidSignature(signature, companySignature.getSignature())) { System.out.println("Success - Signature is valid"); } else { System.out.println("Error - Signatures do not match"); } } else { System.out.println("Error - timestamp is outside of tolerance level"); } } /** * Compute HMAC with the SHA256 hash function. * key is your private key. * message is timestamp.payload. * @return */ public static byte[] regenerateSignature(long timestamp, String message) { String timestampedMessage = timestamp + "." + message; String key = getSecurityKey(); // Generate the hash using key and message. return calcHmacSHA256(Base64.getDecoder().decode(key), timestampedMessage.getBytes(StandardCharsets.UTF_8)); } /** * A mechanism to fetch the security key using keyId from a source. We're using Base64encoded version of (test_key). * @return */ private static String getSecurityKey() { return "dGVzdF9rZXk="; //test_key } /** * Generate SHA256 using secretKey and a message. * Sample Hmacgenerator to test: https://8gwifi.org/hmacgen.jsp * @param secretKey * @param message * @return */ private static byte[] calcHmacSHA256(byte[] secretKey, byte[] message) { byte[] hmacSha256 = null; try { Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "HmacSHA256"); mac.init(secretKeySpec); hmacSha256 = mac.doFinal(message); } catch (Exception e) { throw new RuntimeException("Failed to calculate hmac-sha256", e); } return hmacSha256; } /** * Compare the Base64 decoding of the signature with the signature received in the header. * @param bankSignature * @param companySignature * @return */ private static boolean isValidSignature(byte[] bankSignature, String companySignature) { return Arrays.equals(bankSignature, Base64.getDecoder().decode(companySignature)); }}import java.time.Clock;public class DigitalSignature { private long timestamp; private String keyId; private String signature; public DigitalSignature(String digitalSignature) { try { String signature = digitalSignature.split(" ")[1]; String[] signatureParts = signature.split(";"); this.timestamp = Long.parseLong(signatureParts[0].split("=")[1]); this.keyId = signatureParts[1].split("=")[1]; this.signature = signatureParts[2].split("=")[1]; } catch (Exception e) { System.out.println("Invalid digital signature format"); } } public long getTimestamp() { return timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } public String getKeyId() { return keyId; } public void setKeyId(String keyId) { this.keyId = keyId; } public String getSignature() { return signature; } public void setSignature(String signature) { this.signature = signature; } /** * Using a tolerance of 60 mins * Compute the current time in UTC and make sure the timestamp was generated within the tolerance period. * UTC millis generator to test: https://currentmillis.com/ * * @return */ public boolean isValidTimestamp() { long tolerance = 60 * 60 * 1000L; //60 mins return true; }}Enable Message-Level Encryption
Message-level encryption (MLE) encrypts the payload of a message to prevent tampering. This section explains how to create the key that is necessary to decrypt encrypted payloads.
The webhook notification service requires X.509 certificates instead of raw public keys for MLE. The service uses:
- Symmetric Encryption: AES-GCM with 256-bit keys
- Asymmetric Encryption: RSA-OAEP with 2048-bit keys
- Format: JSON Web Encryption
- Separate key pairs for request and response transactions
Before You Begin
Verify that you meet these requirements before you begin:
- OpenSSL is installed in your system.
- You have access to terminal-command line.
- You have required permissions to create the asymmetric key.
Prepare
Open a terminal and navigate to a secure location for storing your key pairs:
mkdir -p ~/webhooks-keyscd ~/webhooks-keysGenerate a Key
Run these command with no line breaks, but change these values:
- Replace
RequestKeywith the API key that you created in the API keys setup. - Replace
YourOrgwith your account's organization ID.
openssl req -x509 -newkey rsa:2048 -keyout request_private.pem -out request_certificate.pem -days 365 -nodes -subj "/CN=RequestKey/O=YourOrg/C=US" && cat request_certificate.pem | grep -v "BEGIN CERTIFICATE" | grep -v "END CERTIFICATE" | tr -d '\n' && echoRegister a Key
Use the REST API to register and store your certificate. Each webhook subscription requires its own unique asymmetric certificate.
Endpoints
POST /kms/egress/v2/keys-asym
POST /kms/egress/v2/keys-asym
POST /kms/egress/v2/keys-asym
Example: Registering Your Certificate
{ "clientRequestAction": "STORE", "keyInformation": { "provider": "<set this to your organization ID>", "tenant": "nrtd", "keyType": "publickey", "organizationId": "<set this to your organization ID>", "pub": "//this must be one line with no breaks MIIDbDCCAlQCCQD4lcSlmasmCTANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJVUzELMAkGA1UECAwCVFgxDzANBgNVBAcMBkF1c3RpbjENMAsGA1UECgwEVGVzdDEOMAwGA1UECwwFVGVzdDIxDjAMBgNVBAMMBVRlc3QzMRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMB4XDTIxMDgwOTE0MTcxNFoXDTIyMDgwOTE0MTcxNFoweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlRYMQ8wDQYDVQQHDAZBdXN0aW4xDTALBgNVBAoMBFRlc3QxDjAMBgNVBAsMBVRlc3QyMQ4wDAYDVQQDDAVUZXN0MzEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcHQWZRETqim3XzUQlAiujFEvsHIi1uJZKj+1lvPH36Ucqo3ORcoh/MM/zxVdahjhSyyp7MHuKBWnzft6bFeDEul6qKWGPAAzaxG/2xZSV3FggA9SyAZEDUpJ6mblwqm/EY4KmZi1FrNBUHfW2wwaqDexHPRDesRG6aI7Wuu4GdQUUqoTa2+Nv7kVgEDmGcfIjoWkGKHe+Yan95EITrq4jEFCE5Tg/vERnMvHfK2SovENZ13/pnwFYbeh1kfJSBzWW7yq8AyQAgAE9iqJXbJ/MAasir2vjUQ2+Hcl7WbkpoVjLqDt3rzV1T0Bsd4T9SC3wij9qjJSxa6vAgV4xn6bECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEADuMrtYW1Sf0IsZ4ZD9ipjUrFuTxqh+0M5Jk8h0QqAXEHA/MawedlU3JmE3NB/UR82/XUwdmtObGnFANuUQQ+8WMFpcNo/Sq2kg7juneHZroRh72o73UUMtHWHzo8s0fXElNal8h3SaAAnjMblCiN+gM1RvWMvhGrMTXp2XAcdIezXf8/FOZLlzOF9QylbSk1U4ayWBag6MydkxgHjkPKdShZROEm0oz/O7J/gNp/r7J8F42Rw9MmJh9qH3SFre13nQa8V7Kg+dJHZ/jpGtSlDHAxO0SSTrPXkwB+iBJ6hSkiL/J2Ep+lYHqVe3p5NXMOlTtJdbU4enHeLkD6PazKTw", "expiryDuration": "365" }}{ "submitTimeUtc": "2026-01-22T14:36:31Z", "status": "SUCCESS", "keyInformation": { "provider": "384259", "tenant": "nrtd", "organizationId": "384259", "keyId": "937dfa75-acff-4f5b-9aab-66a49455ae04", "pub": "MIIDbDCCAlQCCQD4lcSlmasmCTANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJVUzELMAkGA1UECAwCVFgxDzANBgNVBAcMBkF1c3RpbjENMAsGA1UECgwEVGVzdDEOMAwGA1UECwwFVGVzdDIxDjAMBgNVBAMMBVRlc3QzMRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMB4XDTIxMDgwOTE0MTcxNFoXDTIyMDgwOTE0MTcxNFoweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlRYMQ8wDQYDVQQHDAZBdXN0aW4xDTALBgNVBAoMBFRlc3QxDjAMBgNVBAsMBVRlc3QyMQ4wDAYDVQQDDAVUZXN0MzEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcHQWZRETqim3XzUQlAiujFEvsHIi1uJZKj+1lvPH36Ucqo3ORcoh/MM/zxVdahjhSyyp7MHuKBWnzft6bFeDEul6qKWGPAAzaxG/2xZSV3FggA9SyAZEDUpJ6mblwqm/EY4KmZi1FrNBUHfW2wwaqDexHPRDesRG6aI7Wuu4GdQUUqoTa2+Nv7kVgEDmGcfIjoWkGKHe+Yan95EITrq4jEFCE5Tg/vERnMvHfK2SovENZ13/pnwFYbeh1kfJSBzWW7yq8AyQAgAE9iqJXbJ/MAasir2vjUQ2+Hcl7WbkpoVjLqDt3rzV1T0Bsd4T9SC3wij9qjJSxa6vAgV4xn6bECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEADuMrtYW1Sf0IsZ4ZD9ipjUrFuTxqh+0M5Jk8h0QqAXEHA/MawedlU3JmE3NB/UR82/XUwdmtObGnFANuUQQ+8WMFpcNo/Sq2kg7juneHZroRh72o73UUMtHWHzo8s0fXElNal8h3SaAAnjMblCiN+gM1RvWMvhGrMTXp2XAcdIezXf8/FOZLlzOF9QylbSk1U4ayWBag6MydkxgHjkPKdShZROEm0oz/O7J/gNp/r7J8F42Rw9MmJh9qH3SFre13nQa8V7Kg+dJHZ/jpGtSlDHAxO0SSTrPXkwB+iBJ6hSkiL/J2Ep+lYHqVe3p5NXMOlTtJdbU4enHeLkD6PazKTw", "keyType": "publickey", "status": "active", "expirationDate": "2022-08-09T14:17:14Z" }}Required Fields
| Field | Description |
|---|---|
clientRequestAction | Set the value to STORE. |
keyInformation. | Set the value to the name of the organization ID of the account. |
keyInformation. | Set the value to nrtd. |
keyInformation. | Set the value to publickey. |
keyInformation. | Set the value to the name of the organization ID of the account. |
keyInformation. | Set the value to the X.509 certificate that you generated. IMPORTANT: The certificate is generated with line breaks. You must remove the line breaks before adding it to this field. Do not include the --BEGIN-- and --END-- lines. |
keyInformation. | Set the value to 365. |
Secure Your Subscription
Follow these tips to ensure that your keys remain secure.
- Store private keys in a secure location with restricted permissions.
- Never commit private keys to version control.
- Rotate certificates before expiration.
- Use environment variables or secure vaults for production deployments.
- Keep back-up copies of your private keys in a secure location.
Securing Your Private Key
Keep your request_private.pem file secure. This private key is required to decrypt incoming webhook notifications. To modify the permissions so that only the file owner can read and write to the files, use this command:
chmod 600 request_private.pemView Your Key
To verify your certificate details, use this command.
openssl x509 -in request_certificate.pem -text -nooutChoose Your Security Policy
Decide which security policy your system uses. Your security policy determines whether you submit OAuth credentials and how you format your subscription request.
Every webhooks integration uses mutual trust. You can add the OAuth or OAuth with JWT security policy in addition to mutual trust.
| Feature | Mutual Trust | OAuth | OAuth with JWT |
|---|---|---|---|
| Best for | Integrations that do not require token-based authentication | Applications that authenticate to each other using client credentials | Integrations that bypass domain headers and minimize server-side authentication checks |
| What you set up | Add to your allowlist and trust the Visa root certificate | Mutual trust, plus an OAuth token endpoint on your server and your OAuth credentials submitted to | Mutual trust, plus a P12 certificate, an OAuth token endpoint on your server, and your OAuth credentials submitted to |
Choose a Security Policy Method
Mutual Trust Workflow
Retrieve List of Enabled Products
Retrieve a list of the products and event types that are enabled for your organization. Use this list to know which products and events that you can subscribe to. A successful response lists the enabled products and events in the productId and eventTypes.eventName fields. You can use these same field values when you send a create a webhook subscription request.
If the list you retrieve does not contain an expected product or event type, the product might not be enabled for your organization. Contact your account manager for more information.
Supported Products and Event Types
Set the productId field to a value in the Product ID column, and the eventTypes field array to a value in the Event Types column:
Alternative Payment Methods
| Product ID | Event Types | Description |
|---|---|---|
alternativePaymentMethods | payments. | Notifies you that an alternative payment transaction's status was been updated. |
Decision Manager
| Product ID | Event Types | Description |
|---|---|---|
decisionManager | risk. | Notifies you that a Decision Manager case was accepted. |
decisionManager | risk. | Notifies you that a Decision Manager case was rejected. |
decisionManager | risk. | Notifies you of a profile decision to reject a transaction. |
eCheck
| Product ID | Event Types | Description |
|---|---|---|
eCheck | payments. | Notifies you of a successful eCheck credit transaction. |
eCheck | payments. | Notifies you of an eCheck credit transaction failure. |
eCheck | payments. | Notifies you of a successful eCheck debit transaction. |
eCheck | payments. | Notifies you of an eCheck debit transaction failure. |
eCheck | payments. | Notifies you of a successful eCheck void transaction. |
eCheck | payments. | Notifies you of an eCheck void transaction failure. |
Fraud Management Essentials
| Product ID | Event Types | Description |
|---|---|---|
fraudManagementEssentials | risk. | Notifies you that a Fraud Management Essentials case was accepted. |
fraudManagementEssentials | risk. | Notifies you that a note has been added to a Fraud Management Essentials case. |
fraudManagementEssentials | risk. | Notifies you that a transaction was rejected. |
fraudManagementEssentials | risk. | Notifies you that a Fraud Management Essentials case was rejected. |
fraudManagementEssentials | risk. | Notifies you of a profile decision to monitor a transaction. |
fraudManagementEssentials | risk. | Notifies you of a profile decision to review a transaction. |
Invoicing
| Product ID | Event Types | Description |
|---|---|---|
customerInvoicing | invoicing. | Notifies you that an invoice was sent. |
customerInvoicing | invoicing. | Notifies you that an invoice was cancelled. |
customerInvoicing | invoicing. | Notifies you that an invoice was paid. |
customerInvoicing | invoicing. | Notifies you that an invoice was partially paid. |
customerInvoicing | invoicing. | Notifies you 5 days before the invoice payment is due. This event is triggered if you have invoice reminders enabled in your invoice settings. |
customerInvoicing | invoicing. | Notifies you 1 day after the invoice payment is due. This event is triggered if you have invoice reminders enabled in your invoice settings. |
Pay By Link
| Product ID | Event Types | Description |
|---|---|---|
payByLink | payByLink. | Merchants can subscribe to this event type to automate how their system is informed when a customer completes a payment. |
payByLink | payByLink. | Partner resellers can subscribe to this event type to control the distribution of the payment confirmation email sent to their merchants' customers. |
Payments
| Product ID | Event Types | Description |
|---|---|---|
payments | payments. | Notifies you that a payment capture request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a payment capture was updated and its status changed from PENDING to BATCHED. |
payments | payments. | Notifies you that a refund request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a refund request was batched and its status has changed from PENDING to BATCHED. |
payments | payments. | Notifies you that a credit request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a credit request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a void request was accepted. The transaction carries the status VOIDED. |
payments | payments. | Notifies you that a void request was rejected. The transaction carries the status NOT VOIDABLE. |
payments | payments. | Notifies you that an authorization request was authorized by the issuer. The transaction carries the status AUTHORIZED. |
payments | payments. | Notifies you that an authorization request was under review by Decision Manager. The transaction carries the status AUTHORIZED_PENDING_REVIEW. |
payments | payments. | Notifies you that an authorization request was declined by the issuer or failed due to server error, timeout, or invalid request. Possible statuses include INVALID_REQUEST, SERVER_ERROR, DECLINED, SERVER_TIMEOUT, or SERVICE_TIMEOUT. |
payments | payments. | Notifies you that an authorization request was partially approved by the issuer. The transaction carries the status PARTIAL_AUTHORIZED. |
payments | payments. | Notifies you that a reversal request was approved successfully. The transaction carries the status REVERSED. |
payments | payments. | Notifies you that a reversal request was declined due to issuer rejection, system error, invalid request, or timeout. Possible statuses include REVERSED, INVALID_REQUEST, SERVER_ERROR, DECLINED, SERVER_TIMEOUT, or SERVICE_TIMEOUT. |
Recurring Billing
| Product ID | Event Types | Description |
|---|---|---|
recurringBilling | rbs. | Notifies you of a recurring payment failure. |
recurringBilling | rbs. | Notifies you of an upcoming recurring payment. |
recurringBilling | rbs. | Notifies you of successful recurring payment. |
Token Management Service
| Product ID | Event Types | Description |
|---|---|---|
tokenManagement | tms. | Notifies you of a network token's change in expiration date or status (suspend, resume, or deactivate). |
tokenManagement | tms. | Notifies you when a network token provision for an instrument identifier token has been successful. |
tokenManagement | tms. | Notifies you of the binding status of a network token with a device. |
Unified Checkout
| Product ID | Event Types | Description |
|---|---|---|
unifiedCheckout | uc. | Notifies you of the payment outcome, including the full payload response from the payment service call. |
Endpoints
Send a GET request to one of these endpoints. The {organizationId} is your organization ID.
GET /notification-subscriptions/v2/products/{organizationId}
GET /notification-subscriptions/v2/products/{organizationId}
GET /notification-subscriptions/v2/products/{organizationId}
Example: Retrieving a List of Products and Events
GET /notification-subscriptions/v2/products/demomerchant_01{}[ { "productId": "terminalManagement", "eventTypes": [ { "eventName": "terminalManagement.status.update", "payloadEncryption": false }, { "eventName": "terminalManagement.assignment.update", "payloadEncryption": false }, { "eventName": "terminalManagement.reAssignment.update", "payloadEncryption": false } ] }]Create Webhook Subscription
Follow these steps to create your first webhook subscription.
Send Subscription Request
Endpoints
Send a POST request to one of these endpoints:
POST /notification-subscriptions/v2/webhooks
POST /notification-subscriptions/v2/webhooks
POST /notification-subscriptions/v2/webhooks
Example
{ "name": "My Custom Webhook", "description": "Sample Webhook from Developer Center", "organizationId": "demomerchant_01", "products": [ { "productId": "product1.name", "eventTypes": [ "product.name.event.type", "product.name.event.type", "product.name.event.type" ] }, { "productId": "product2.name", "eventTypes": [ "product.name.event.type", "product.name.event.type", "product.name.event.type" ] } ], "webhookUrl": "https://MyWebhookServer.com:8443/simulateClient", "securityPolicy": { "securityType": "KEY" }}{ "organizationId": "demomerchant_01", "productId": "terminalManagement", "eventTypes": [ "terminalManagement.assignment.update" ], "webhookId": "ddb9bced-c3e3-1b1d-e053-9c588e0a3c42", "name": "My Custom Webhook", "webhookUrl": "https://MyWebhookServer.com:443/simulateClient", "healthCheckUrl": "https://MyWebhookServer.com:443/simulateClientHealthCheck", "createdOn": "2022-04-28T15:39:56.928Z", "status": "ACTIVE", "description": "Sample Webhook from Developer Center", "retryPolicy": { "algorithm": "ARITHMETIC", "firstRetry": "1", "interval": "1", "numberOfRetries": "3", "deactivateFlag": "false", "repeatSequenceCount": "0", "repeatSequenceWaitTime": "0" }, "securityPolicy": { "securityType": "KEY", "digitalSignatureEnabled": "yes" }, "version": "3", "notificationScope": "SELF"}Required Fields
| Field | Description |
|---|---|
description | Description of the webhook subscription. |
name | Name of the webhook subscription. |
organizationId | Set to your organization ID or merchant ID. |
products. | Set to the event types that you want to subscribe to for that product. Separate multiple values with the comma character (,). For a list of possible values, see Retrieve List of Enabled Products. |
products. | Set to the ID of a product that is enabled for your organization. For a list of possible values, see Retrieve List of Enabled Products. |
securityPolicy. | Set to KEY. |
webhookUrl | The URL in your system to which webhook notifications are sent. |
Optional Fields
| Field | Description |
|---|---|
deactivateflag | Required if the healthCheckUrl field is present. Set to true to automatically activate the subscription. |
healthCheckUrl | Set to the health check URL. Required to auto-activate the subscription. If you do not include this field, the created subscription is inactive. An inactive subscription does not send notifications. |
notificationScope. | Set to the organization IDs that you want to receive notifications for when subscribed events occur in those organizations. Concatenate each organization ID with the comma character (,). |
retryPolicy. | Set to true to withhold notifications while your webhook URL or health check URL are unresponsive. The default value is false. |
retryPolicy. | The number of minutes before the notification is resent. The default value is 1. |
retryPolicy. | The number of minutes between each retry attempt. The default value is 1. |
retryPolicy. | The number of retry attempts. The default value is 3. |
retryPolicy. | The number of times to repeat the retry sequence. The default value is 0. |
retryPolicy. | The number of minutes between each repeat sequence. The default value is 0. |
Store Subscription ID and Review Response
After sending this request, you receive a response with a subscription ID in the webhookId field. Save this ID in your system to send follow-on requests that enable you to update and manage the subscription.
Additional Response Information
The notificationScope response field indicates which organizations receive the webhook notification. By default, notifications use the DESCENDANTS setting. To modify this setting, include the notificationScope.scopeData field in your request.
These are all possible field values:
| Value | Description |
|---|---|
SELF | Only the organization creating the webhook subscription receives notifications when a subscribed event occurs. |
DESCENDANTS (default) | The organization creating the webhook subscription receives notifications when a subscribed event occurs in their organization and in any of their children/descendant accounts in their portfolio hierarchy. This is the default notification setting. |
CUSTOM | The organization creating the webhook subscription receives notifications when a subscribed event occurs in their organization and in any organization listed in the notificationScope. request field. |
When you create a subscription, its status is indicated in the status response field. If you did not include a health check URL in your request, the subscription is set to INACTIVE. If you included a health check URL and receives a response from the health check URL, the subscription status is set to ACTIVE.
These are the three possible statuses a subscription can be set to:
| Status | Description |
|---|---|
ACTIVE | The subscription is ready to send notifications or is actively sending notifications. |
INACTIVE | The subscription has not been activated. Add a health check URL to activate it. |
SUSPENDED | The subscription was active, but the webhook URL or the health check URL became unreachable. When the URL becomes reachable, the status changes to ACTIVE and notifications resume. |
Optional Setup Tasks
recommends that you include a health check URL in the subscription request. A health check URL ensures that you do not miss any notifications.
How Health Check URLs Work
Including a health check URL enables to monitor your server's status for reliability. When detects that your health check URL is unresponsive, notification deliveries are withheld until your health check URL becomes responsive again.
To add a health check URL to your create a subscription request, include these fields:
healthCheckurl: set to your health check URL.deactivateflag: set totrueto enable to withhold notifications for periods when your server becomes unresponsive.
Automatic activation
After you successfully create or update a subscription, pings your health check URL within five to ten minutes:
- If receives a response, the subscription status automatically becomes
ACTIVEand notifications are delivered. - If does not receive a response, your subscription status remains
SUSPENDEDuntil receives a response.
If you did not include a health check URL when you created the subscription, pings your webhook URL for automatic activation instead. You can also activate a subscription that is not automatically activated by sending a PUT request.
Automatic revalidation
After the subscription's initial activation, continues to monitor your server status:
- If detects that your server is unavailable, your subscription status automatically updates to
SUSPENDED, and notifications are withheld. - If detects that your server is available again, your subscription status automatically updates to
ACTIVE, and all withheld notifications are delivered.
When a webhook subscription is created or updated, the URLs associated with that subscription are evaluated through a validation and approval process.
How URL Validation Works
URL validation is designed to:
- Reduce security risk by preventing outbound calls to unapproved endpoints.
- Improve compliance through stronger review and approval controls.
- Increase transparency with clearer client-visible statuses.
- Support scale through a standardized and repeatable validation process.
URL validation applies to:
- Webhook URL (required)
- OAuth URL (if applicable)
- Health Check URL (if applicable)
Validation process:
- A webhook subscription is created or updated.
- Submitted URLs are checked against existing approval records.
- New or unknown URLs are evaluated through automated validation.
- If additional review is required, the subscription status changes to PENDING_REVIEW.
- If any URL is rejected or blocked, the subscription status changes to BLOCKED.
- If all required URLs are approved, the subscription status changes to INACTIVE.
Validation statuses: These are the statuses a subscription can be set to during URL validation:
| Status | Description |
|---|---|
| PENDING_REVIEW | One or more submitted URLs are being validated or awaiting required security approval. |
| BLOCKED | One or more URLs were rejected or identified as unsafe or non-compliant. The subscription cannot proceed until the URL(s) are updated. |
| INACTIVE | All required approvals are complete, and the subscription is ready under the existing activation flow. |
If your subscription is marked BLOCKED, one or more URLs associated with the subscription cannot be used in their current form. To continue, update the affected URLs and resubmit.
If your webhook URL or health check URL are unresponsive when sent a notification, resends the notification according to the subscription's retry policy. By default, sends you 3 notification attempts, beginning 1 minute after the initial failed attempt. Retry attempts occur in 1 minute intervals if your URL remains unresponsive.
How to Configure the Retry Policy
All subscriptions have a default retry policy. You can change the retry policy when you create a subscription or when you update the webhook subscription.
To configure a subscription's retry policy, include these required fields in the create a subscription request or an update a subscription request:
| Field | Description |
|---|---|
retryPolicy. | Set to one of these values: false — Notifications are not withheld when your webhook URL or health check URL are unresponsive. This value is the default. true — Notifications are withheld when your webhook URL or health check URL are unresponsive, and the subscription status updates to SUSPENDED. When the URLs become responsive again, the withheld notifications are sent and the subscription status updates to ACTIVE. |
retryPolicy. | The number of minutes before the notification is resent. The default value is 1. |
retryPolicy. | The number of minutes between each retry attempt. The default value is 1. |
retryPolicy. | The number of retry attempts. The default value is 3. |
retryPolicy. | The number of times to repeat the retry sequence. The default value is 0. |
retryPolicy. | The number of minutes between each repeat sequence. The default value is 0. |
Example: This example shows how to format a retry policy in a request.
"retryPolicy": { "firstRetry": "1", "interval": "1", "numberOfRetries": "3", "deactivateFlag": "false", "repeatSequenceCount": "0", "repeatSequenceWaitTime": "0" }Receive a Notification
After creating a webhook subscription, you receive a notification when a subscribed event occurs. Review the notification fields and example to know how to interpret the notification.
Notification Message Body
The message body contains fields associated with the notification and the payload of the event that generated the notification.
| Field | Description |
|---|---|
webhookId | The identifier of the webhook subscription that generated the notification. |
transactionTraceId | The identifier of the notification attempt. Every retry attempt has a unique transaction trace ID. |
productId | The identifier of the product that generated the event. |
organizationId | The identifier of the organization that is subscribed to the notification. |
eventType | The type of event that generated the notification. |
eventDate | The timestamp of when the event occurred. |
payload | The data generated by the event. |
requestType | The indicator of whether the notification is new or a retry attempt. |
Notification Payload Example
This example shows a complete Token Management Service webhook notification, including its headers and payload:
POST /test HTTP/1.1Host: test.test.comContent-Length: 537Content-Type: application/jsonv-c-event-type: product.event.typev-c-organization-id: orgidv-c-product-name: productv-c-request-type: NEWv-c-retry-count: 0v-c-signature: "t=timestamp;keyId=key-UUID;sig=calculatedDigitalSignature"v-c-transaction-trace-id: "7ac2ad9f-6a89-d3e9-e053-34b8d30aaf40"v-c-webhook-id: "e339e8b1-d540-4efd-e053-8d588e0a2de5"{ "eventType": "tms.networktoken.provisioned", "webhookId": "e339e8b1-d540-4efd-e053-8d588e0a2de5", "productId": "tokenManagement", "organizationId": "sampleSubscriptionHolder", "eventDate": "2022-07-20T11:38:45", "transactionTraceId": "7ac2ad9f-6a89-d3e9-e053-34b8d30aaf40", "retryNumber": 0, "payload": { "data": { "_links": { "paymentInstruments": [ { "href": "/tms/v1/paymentinstruments/...................." } ], "instrumentIdentifiers": [ { "href": "/tms/v1/instrumentidentifiers/...................." } ] }, "id": "...................", "type": "tokenizedCardEnrollments", "version": "1.0" }, "organizationId": "sampleSelfOrChildOrg" }, "requestType": "NEW"}Next Steps
After creating your first webhook subscription, you can now review additional events to subscribe to, manage your existing subscriptions, and troubleshoot any delivery issues.
Supported Products
Tables of all webhook-subscribable products and their event type values.
View referenceTroubleshooting
Troubleshoot webhook subscriptions and message-level encryption issues.
View guideUpdate a Subscription
Update an existing webhook subscription, such as the notification scope, health check URL, or retry policy.
View guideDelete a Subscription
Delete a webhook subscription. Deleting a subscription does not delete the history of webhook notifications.
View guideOAuth Workflow
Submit your OAuth Credentials
The OAuth security policy with client credentials is an authentication method that is designed for applications that communicate with each other. Basic authentication is the most common mechanism for authenticating a client with the client credentials. This authentication method enables services to obtain only the relevant user data without exposing the user's credentials.
You must provide your OAuth credentials to . The OAuth credentials request uses Visa's key management service to store your credentials. When sends you webhook notifications in the future, will use your OAuth credentials to access your server and deliver the notification message.
Endpoints
Send a POST request to one of these endpoints:
POST /kms/egress/v2/keys-sym
POST /kms/egress/v2/keys-sym
POST /kms/egress/v2/keys-sym
Headers
Each API request should use headers that provide your client credentials, which are the username and password of your webhooks server. Here is an example:
curl --location 'Client's OAuth URL' \--header 'Content-Type: application/x-www-form-urlencoded' \--data-urlencode 'grant_type=client_credentials' \--data-urlencode 'client_id=webhooks-server-username' \--data-urlencode 'client_secret=webhooks-server-password'Example: Providing Your OAuth Credentials
{ "clientRequestAction": "STORE", "keyInformation": { "provider": "merchantName", "tenant": "nrtd", "keyType": "oAuthClientCredentials", "organizationId": "merchantName", "clientKeyId": "Webhook server's username", "key": "Webhook server's secret key", "expiryDuration": "365" }}{ "submitTimeUtc": "2022-02-18T19:49:52Z", "status": "SUCCESS", "keyInformation": { "provider": "org1", "tenant": "nrtd", "organizationId": "org1", "clientKeyId": "ef400ac1-edfe-406e-94b3-0d73be09a1a0", "keyId": "d8512fb5-1d8c-4f2d-e053-3cb8d30a764c", "key": "KTTY1LLGYR6A2LL4XZTT9W9RGCVJ5Z4XZAP6AFTRUFWLSXX0NX4N88N9EJED3BMM", "keyType": "oAuthClientCredentials", "status": "active", "expirationDate": "2023-02-18T19:49:52Z" }}Required Fields for Providing Your OAuth Credentials
| Field | Description |
|---|---|
clientRequestAction | Set to STORE. |
keyInformation. | Set to the webhook server's username. |
keyInformation. | Set to 365. |
keyInformation. | Set to the webhooks server's secret key. |
keyInformation. | Set to oAuthClientCredentials. |
keyInformation. | Set to the organization ID or merchant ID of the organization requesting the key. |
keyInformation. | Set to the organization ID that the requesting organization belongs to. |
keyInformation. | Set to nrtd. |
Retrieve List of Enabled Products
Retrieve a list of the products and event types that are enabled for your organization. Use this list to know which products and events that you can subscribe to. A successful response lists the enabled products and events in the productId and eventTypes.eventName fields. You can use these same field values when you send a create a webhook subscription request.
If the list you retrieve does not contain an expected product or event type, the product might not be enabled for your organization. Contact your account manager for more information.
Supported Products and Event Types
Set the productId field to a value in the Product ID column, and the eventTypes field array to a value in the Event Types column:
Alternative Payment Methods
| Product ID | Event Types | Description |
|---|---|---|
alternativePaymentMethods | payments. | Notifies you that an alternative payment transaction's status was been updated. |
Decision Manager
| Product ID | Event Types | Description |
|---|---|---|
decisionManager | risk. | Notifies you that a Decision Manager case was accepted. |
decisionManager | risk. | Notifies you that a Decision Manager case was rejected. |
decisionManager | risk. | Notifies you of a profile decision to reject a transaction. |
eCheck
| Product ID | Event Types | Description |
|---|---|---|
eCheck | payments. | Notifies you of a successful eCheck credit transaction. |
eCheck | payments. | Notifies you of an eCheck credit transaction failure. |
eCheck | payments. | Notifies you of a successful eCheck debit transaction. |
eCheck | payments. | Notifies you of an eCheck debit transaction failure. |
eCheck | payments. | Notifies you of a successful eCheck void transaction. |
eCheck | payments. | Notifies you of an eCheck void transaction failure. |
Fraud Management Essentials
| Product ID | Event Types | Description |
|---|---|---|
fraudManagementEssentials | risk. | Notifies you that a Fraud Management Essentials case was accepted. |
fraudManagementEssentials | risk. | Notifies you that a note has been added to a Fraud Management Essentials case. |
fraudManagementEssentials | risk. | Notifies you that a transaction was rejected. |
fraudManagementEssentials | risk. | Notifies you that a Fraud Management Essentials case was rejected. |
fraudManagementEssentials | risk. | Notifies you of a profile decision to monitor a transaction. |
fraudManagementEssentials | risk. | Notifies you of a profile decision to review a transaction. |
Invoicing
| Product ID | Event Types | Description |
|---|---|---|
customerInvoicing | invoicing. | Notifies you that an invoice was sent. |
customerInvoicing | invoicing. | Notifies you that an invoice was cancelled. |
customerInvoicing | invoicing. | Notifies you that an invoice was paid. |
customerInvoicing | invoicing. | Notifies you that an invoice was partially paid. |
customerInvoicing | invoicing. | Notifies you 5 days before the invoice payment is due. This event is triggered if you have invoice reminders enabled in your invoice settings. |
customerInvoicing | invoicing. | Notifies you 1 day after the invoice payment is due. This event is triggered if you have invoice reminders enabled in your invoice settings. |
Pay By Link
| Product ID | Event Types | Description |
|---|---|---|
payByLink | payByLink. | Merchants can subscribe to this event type to automate how their system is informed when a customer completes a payment. |
payByLink | payByLink. | Partner resellers can subscribe to this event type to control the distribution of the payment confirmation email sent to their merchants' customers. |
Payments
| Product ID | Event Types | Description |
|---|---|---|
payments | payments. | Notifies you that a payment capture request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a payment capture was updated and its status changed from PENDING to BATCHED. |
payments | payments. | Notifies you that a refund request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a refund request was batched and its status has changed from PENDING to BATCHED. |
payments | payments. | Notifies you that a credit request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a credit request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a void request was accepted. The transaction carries the status VOIDED. |
payments | payments. | Notifies you that a void request was rejected. The transaction carries the status NOT VOIDABLE. |
payments | payments. | Notifies you that an authorization request was authorized by the issuer. The transaction carries the status AUTHORIZED. |
payments | payments. | Notifies you that an authorization request was under review by Decision Manager. The transaction carries the status AUTHORIZED_PENDING_REVIEW. |
payments | payments. | Notifies you that an authorization request was declined by the issuer or failed due to server error, timeout, or invalid request. Possible statuses include INVALID_REQUEST, SERVER_ERROR, DECLINED, SERVER_TIMEOUT, or SERVICE_TIMEOUT. |
payments | payments. | Notifies you that an authorization request was partially approved by the issuer. The transaction carries the status PARTIAL_AUTHORIZED. |
payments | payments. | Notifies you that a reversal request was approved successfully. The transaction carries the status REVERSED. |
payments | payments. | Notifies you that a reversal request was declined due to issuer rejection, system error, invalid request, or timeout. Possible statuses include REVERSED, INVALID_REQUEST, SERVER_ERROR, DECLINED, SERVER_TIMEOUT, or SERVICE_TIMEOUT. |
Recurring Billing
| Product ID | Event Types | Description |
|---|---|---|
recurringBilling | rbs. | Notifies you of a recurring payment failure. |
recurringBilling | rbs. | Notifies you of an upcoming recurring payment. |
recurringBilling | rbs. | Notifies you of successful recurring payment. |
Token Management Service
| Product ID | Event Types | Description |
|---|---|---|
tokenManagement | tms. | Notifies you of a network token's change in expiration date or status (suspend, resume, or deactivate). |
tokenManagement | tms. | Notifies you when a network token provision for an instrument identifier token has been successful. |
tokenManagement | tms. | Notifies you of the binding status of a network token with a device. |
Unified Checkout
| Product ID | Event Types | Description |
|---|---|---|
unifiedCheckout | uc. | Notifies you of the payment outcome, including the full payload response from the payment service call. |
Endpoints
Send a GET request to one of these endpoints. The {organizationId} is your organization ID.
GET /notification-subscriptions/v2/products/{organizationId}
GET /notification-subscriptions/v2/products/{organizationId}
GET /notification-subscriptions/v2/products/{organizationId}
Example: Retrieving a List of Products and Events
GET /notification-subscriptions/v2/products/demomerchant_01{}[ { "productId": "terminalManagement", "eventTypes": [ { "eventName": "terminalManagement.status.update", "payloadEncryption": false }, { "eventName": "terminalManagement.assignment.update", "payloadEncryption": false }, { "eventName": "terminalManagement.reAssignment.update", "payloadEncryption": false } ] }]Create Webhook Subscription
Follow these steps to create your first webhook subscription.
Send Subscription Request
Endpoints
Send a POST request to one of these endpoints:
POST /notification-subscriptions/v2/webhooks
POST /notification-subscriptions/v2/webhooks
POST /notification-subscriptions/v2/webhooks
Example
{ "name": "My Custom Webhook", "description": "", "organizationId": "demomerchant_01", "products": [ { "productId": "product.name", "eventTypes": [ "product.name.event.type" ] } ], "webhookUrl": "https://MyWebhookServer.com:8443/simulateClient", "securityPolicy": { "securityType": "oAuth", "config": { "oAuthTokenExpiry": 365, "oAuthURL": "https://MyWebhookServer.com:8443/oAuthToken", "oAuthTokenType": "Bearer" } }}{ "organizationId" : "demomerchant_01", "productId" : "terminalManagement", "eventTypes" : [ "terminalManagement.assignment.update"], "webhookId" : "d7399cb6-ff9f-72d9-e053-3cb8d30a62ee", "webhookUrl" : "https://mywebhookserver.com/simulateclient", "healthCheckUrl" : "https://mywebhookserver.com/simulateclient/healthcheck", "createdOn" : "2022-02-04T22:17:43.045Z", "status" : "INACTIVE", "retryPolicy" : { "algorithm" : "ARITHMETIC", "firstRetry" : "1", "interval" : "1", "numberOfRetries" : "3", "deactivateFlag" : "false", "repeatSequenceCount" : "0", "repeatSequenceWaitTime" : "0" }, "securityPolicy" : { "securityType" : "oAuth", "proxyType" : "internal", "digitalSignatureEnabled" : "yes", "config" : { "oAuthTokenExpiry" : "300", "oAuthURL" : "https://myoauthserver.com/simulator/v1/token", "oAuthTokenType" : "Bearer" } }, "version" : "3", "notificationScope" : "SELF"}Required Fields
| Field | Description |
|---|---|
description | Description of the webhook subscription. |
name | Name of the webhook subscription. |
organizationId | Set to your organization ID or merchant ID. |
products. | Set to the event types that you want to subscribe to for that product. Separate multiple values with the comma character (,). For a list of possible values, see Retrieve List of Enabled Products. |
products. | Set to the ID of a product that is enabled for your organization. For a list of possible values, see Retrieve List of Enabled Products. |
securityPolicy. | |
securityPolicy. | Set to Bearer. |
securityPolicy. | This is the URL of your OAuth server. |
securityPolicy. | Set to oAuth. |
webhookUrl | The URL in your system to which webhook notifications are sent. |
Optional Fields
| Field | Description |
|---|---|
deactivateflag | Required if the healthCheckUrl field is present. Set to true to automatically activate the subscription. |
healthCheckUrl | Set to the health check URL. Required to auto-activate the subscription. If you do not include this field, the created subscription is inactive. An inactive subscription does not send notifications. |
notificationScope. | Set to the organization IDs that you want to receive notifications for when subscribed events occur in those organizations. Concatenate each organization ID with the comma character (,). |
retryPolicy. | Set to true to withhold notifications while your webhook URL or health check URL are unresponsive. The default value is false. |
retryPolicy. | The number of minutes before the notification is resent. The default value is 1. |
retryPolicy. | The number of minutes between each retry attempt. The default value is 1. |
retryPolicy. | The number of retry attempts. The default value is 3. |
retryPolicy. | The number of times to repeat the retry sequence. The default value is 0. |
retryPolicy. | The number of minutes between each repeat sequence. The default value is 0. |
Store Subscription ID and Review Response
After sending this request, you receive a response with a subscription ID in the webhookId field. Save this ID in your system to send follow-on requests that enable you to update and manage the subscription.
Additional Response Information
The notificationScope response field indicates which organizations receive the webhook notification. By default, notifications use the DESCENDANTS setting. To modify this setting, include the notificationScope.scopeData field in your request.
These are all possible field values:
| Value | Description |
|---|---|
SELF | Only the organization creating the webhook subscription receives notifications when a subscribed event occurs. |
DESCENDANTS (default) | The organization creating the webhook subscription receives notifications when a subscribed event occurs in their organization and in any of their children/descendant accounts in their portfolio hierarchy. This is the default notification setting. |
CUSTOM | The organization creating the webhook subscription receives notifications when a subscribed event occurs in their organization and in any organization listed in the notificationScope. request field. |
When you create a subscription, its status is indicated in the status response field. If you did not include a health check URL in your request, the subscription is set to INACTIVE. If you included a health check URL and receives a response from the health check URL, the subscription status is set to ACTIVE.
These are the three possible statuses a subscription can be set to:
| Status | Description |
|---|---|
ACTIVE | The subscription is ready to send notifications or is actively sending notifications. |
INACTIVE | The subscription has not been activated. Add a health check URL to activate it. |
SUSPENDED | The subscription was active, but the webhook URL or the health check URL became unreachable. When the URL becomes reachable, the status changes to ACTIVE and notifications resume. |
Optional Setup Tasks
recommends that you include a health check URL in the subscription request. A health check URL ensures that you do not miss any notifications.
How Health Check URLs Work
Including a health check URL enables to monitor your server's status for reliability. When detects that your health check URL is unresponsive, notification deliveries are withheld until your health check URL becomes responsive again.
To add a health check URL to your create a subscription request, include these fields:
healthCheckurl: set to your health check URL.deactivateflag: set totrueto enable to withhold notifications for periods when your server becomes unresponsive.
Automatic activation
After you successfully create or update a subscription, pings your health check URL within five to ten minutes:
- If receives a response, the subscription status automatically becomes
ACTIVEand notifications are delivered. - If does not receive a response, your subscription status remains
SUSPENDEDuntil receives a response.
If you did not include a health check URL when you created the subscription, pings your webhook URL for automatic activation instead. You can also activate a subscription that is not automatically activated by sending a PUT request.
Automatic revalidation
After the subscription's initial activation, continues to monitor your server status:
- If detects that your server is unavailable, your subscription status automatically updates to
SUSPENDED, and notifications are withheld. - If detects that your server is available again, your subscription status automatically updates to
ACTIVE, and all withheld notifications are delivered.
When a webhook subscription is created or updated, the URLs associated with that subscription are evaluated through a validation and approval process.
How URL Validation Works
URL validation is designed to:
- Reduce security risk by preventing outbound calls to unapproved endpoints.
- Improve compliance through stronger review and approval controls.
- Increase transparency with clearer client-visible statuses.
- Support scale through a standardized and repeatable validation process.
URL validation applies to:
- Webhook URL (required)
- OAuth URL (if applicable)
- Health Check URL (if applicable)
Validation process:
- A webhook subscription is created or updated.
- Submitted URLs are checked against existing approval records.
- New or unknown URLs are evaluated through automated validation.
- If additional review is required, the subscription status changes to PENDING_REVIEW.
- If any URL is rejected or blocked, the subscription status changes to BLOCKED.
- If all required URLs are approved, the subscription status changes to INACTIVE.
Validation statuses: These are the statuses a subscription can be set to during URL validation:
| Status | Description |
|---|---|
| PENDING_REVIEW | One or more submitted URLs are being validated or awaiting required security approval. |
| BLOCKED | One or more URLs were rejected or identified as unsafe or non-compliant. The subscription cannot proceed until the URL(s) are updated. |
| INACTIVE | All required approvals are complete, and the subscription is ready under the existing activation flow. |
If your subscription is marked BLOCKED, one or more URLs associated with the subscription cannot be used in their current form. To continue, update the affected URLs and resubmit.
If your webhook URL or health check URL are unresponsive when sent a notification, resends the notification according to the subscription's retry policy. By default, sends you 3 notification attempts, beginning 1 minute after the initial failed attempt. Retry attempts occur in 1 minute intervals if your URL remains unresponsive.
How to Configure the Retry Policy
All subscriptions have a default retry policy. You can change the retry policy when you create a subscription or when you update the webhook subscription.
To configure a subscription's retry policy, include these required fields in the create a subscription request or an update a subscription request:
| Field | Description |
|---|---|
retryPolicy. | Set to one of these values: false — Notifications are not withheld when your webhook URL or health check URL are unresponsive. This value is the default. true — Notifications are withheld when your webhook URL or health check URL are unresponsive, and the subscription status updates to SUSPENDED. When the URLs become responsive again, the withheld notifications are sent and the subscription status updates to ACTIVE. |
retryPolicy. | The number of minutes before the notification is resent. The default value is 1. |
retryPolicy. | The number of minutes between each retry attempt. The default value is 1. |
retryPolicy. | The number of retry attempts. The default value is 3. |
retryPolicy. | The number of times to repeat the retry sequence. The default value is 0. |
retryPolicy. | The number of minutes between each repeat sequence. The default value is 0. |
Example: This example shows how to format a retry policy in a request.
"retryPolicy": { "firstRetry": "1", "interval": "1", "numberOfRetries": "3", "deactivateFlag": "false", "repeatSequenceCount": "0", "repeatSequenceWaitTime": "0" }Receive a Notification
After creating a webhook subscription, you receive a notification when a subscribed event occurs. Review the notification fields and example to know how to interpret the notification.
Notification Message Body
The message body contains fields associated with the notification and the payload of the event that generated the notification.
| Field | Description |
|---|---|
webhookId | The identifier of the webhook subscription that generated the notification. |
transactionTraceId | The identifier of the notification attempt. Every retry attempt has a unique transaction trace ID. |
productId | The identifier of the product that generated the event. |
organizationId | The identifier of the organization that is subscribed to the notification. |
eventType | The type of event that generated the notification. |
eventDate | The timestamp of when the event occurred. |
payload | The data generated by the event. |
requestType | The indicator of whether the notification is new or a retry attempt. |
Notification Payload Example
This example shows a complete Token Management Service webhook notification, including its headers and payload:
POST /test HTTP/1.1Host: test.test.comContent-Length: 537Content-Type: application/jsonv-c-event-type: product.event.typev-c-organization-id: orgidv-c-product-name: productv-c-request-type: NEWv-c-retry-count: 0v-c-signature: "t=timestamp;keyId=key-UUID;sig=calculatedDigitalSignature"v-c-transaction-trace-id: "7ac2ad9f-6a89-d3e9-e053-34b8d30aaf40"v-c-webhook-id: "e339e8b1-d540-4efd-e053-8d588e0a2de5"{ "eventType": "tms.networktoken.provisioned", "webhookId": "e339e8b1-d540-4efd-e053-8d588e0a2de5", "productId": "tokenManagement", "organizationId": "sampleSubscriptionHolder", "eventDate": "2022-07-20T11:38:45", "transactionTraceId": "7ac2ad9f-6a89-d3e9-e053-34b8d30aaf40", "retryNumber": 0, "payload": { "data": { "_links": { "paymentInstruments": [ { "href": "/tms/v1/paymentinstruments/...................." } ], "instrumentIdentifiers": [ { "href": "/tms/v1/instrumentidentifiers/...................." } ] }, "id": "...................", "type": "tokenizedCardEnrollments", "version": "1.0" }, "organizationId": "sampleSelfOrChildOrg" }, "requestType": "NEW"}Next Steps
After creating your first webhook subscription, you can now review additional events to subscribe to, manage your existing subscriptions, and troubleshoot any delivery issues.
Supported Products
Tables of all webhook-subscribable products and their event type values.
View referenceTroubleshooting
Troubleshoot webhook subscriptions and message-level encryption issues.
View guideUpdate a Subscription
Update an existing webhook subscription, such as the notification scope, health check URL, or retry policy.
View guideDelete a Subscription
Delete a webhook subscription. Deleting a subscription does not delete the history of webhook notifications.
View guideOAuth with JWT Workflow
Create P12 Certificate
The OAuth with JWT security policy requires a P12 certificate in addition to the shared secret key pair that you created earlier. A P12 certificate is a key used for JSON Web Token authentication. It consists of a .p12 file and a password that you must set to use the file. You might have already completed this requirement if your system is currently REST compliant.
Create or Submit a P12 Certificate
You can choose to create a new certificate or submit an existing P12 certificate that you created in your system.
Follow these steps to create a P12 certificate file or submit your own certificate signing request (CSR):
On the left navigation panel, choose Payment Configuration > Key Management.
Click + Generate key on the Key Management page.
Under REST APIs, choose REST – Certificate, and then click Generate key.
The Key Generation page appears.
If you are using a portfolio account, the Key options window appears, giving you the choice to create a meta key. For more information about how to create a meta key, see Meta Keys.
(Optional) You can set the Certificate Expiry Timeframe field to the number of months you want the key to remain active before it expires. Only whole numbers from 1–36 are accepted. By default, new keys expire after 12 months.
Choose from these two options:
If you are creating a new P12 Certificate, click Download key .
If you are submitting your own certificate, enter your public PEM-formatted certificate in the text box, then click Download key .
Create a password for the certificate by entering one into the New Password and Confirm Password fields. Click Generate key.
To create or submit another key, click Generate another key. To view all of your created keys, go to the Key Management page.
Extracting the Private Key from Your P12 Certificate
When you have your P12 certificate, extract the private key from the certificate. Use this key to sign your header when sending an API request.
Follow these steps to extract the private key using OpenSSL:
- Open the command-line tool and navigate to the directory that contains the P12 certificate.
- Enter this command:
openssl pkcs12 -in [certificate name] -nodes -nocerts -out [private key name]Enter the password for the certificate.
You set this password when you created the P12 certificate in the .
Testing Your Private Key
After creating your key certificate, you must verify that it can successfully process API requests. This task explains how to test and validate your private key in the Developer Center and the .
Follow these steps:
Go to the API Reference page:
Under Authentication and Sandbox Credentials, go to the Authentication Type drop-down menu and choose JSON Web Token.
Enter your organization ID in the Organization field.
Enter your Password in the Password field.
Click Browse and upload your p12 certificate from your desktop.
Click Update Credentials.
A confirmation message verifies that your credentials are successfully updated.
On the left navigation panel, choose Payments > POST Process a Payment.
Click Send.
A message confirms that your request is successful with the status code 201.
Log in to the .
On the left navigation panel, choose Transaction Management > Transactions.
Under Search Results, verify that the request ID from the test authorization response is listed in the Request ID column.
Submit your OAuth Credentials
The OAuth with JWT security policy is an authentication method in which your system sends a JSON Web Token. This method bypasses domain headers and minimizes the need for server-side authentication checks.
You must provide your OAuth credentials to . The OAuth credentials request uses Visa's key management service to store your credentials. When sends you webhook notifications in the future, will use your OAuth credentials to access your server and deliver the notification message.
Endpoints
Send a POST request to one of these endpoints:
POST /kms/egress/v2/keys-sym
POST /kms/egress/v2/keys-sym
POST /kms/egress/v2/keys-sym
Headers
Each API request should use headers that provide your client credentials, which are the username and password of your webhooks server. Here is an example:
curl --location 'Client's OAuth URL' \--header 'Content-Type: application/x-www-form-urlencoded' \--data-urlencode 'grant_type=client_credentials' \--data-urlencode 'client_id=webhooks-server-username' \--data-urlencode 'client_secret=webhooks-server-password'Example: Providing Your OAuth Credentials
{ "clientRequestAction": "STORE", "keyInformation": { "provider": "merchantName", "tenant": "nrtd", "keyType": "oAuthClientCredentials", "organizationId": "merchantName", "clientKeyId": "Webhook server's username", "key": "Webhook server's secret key", "expiryDuration": "365" }}{ "submitTimeUtc": "2022-02-18T19:49:52Z", "status": "SUCCESS", "keyInformation": { "provider": "org1", "tenant": "nrtd", "organizationId": "org1", "clientKeyId": "ef400ac1-edfe-406e-94b3-0d73be09a1a0", "keyId": "d8512fb5-1d8c-4f2d-e053-3cb8d30a764c", "key": "KTTY1LLGYR6A2LL4XZTT9W9RGCVJ5Z4XZAP6AFTRUFWLSXX0NX4N88N9EJED3BMM", "keyType": "oAuthClientCredentials", "status": "active", "expirationDate": "2023-02-18T19:49:52Z" }}Required Fields for Providing Your OAuth Credentials
| Field | Description |
|---|---|
clientRequestAction | Set to STORE. |
keyInformation. | Set to the webhook server's username. |
keyInformation. | Set to 365. |
keyInformation. | Set to the webhooks server's secret key. |
keyInformation. | Set to oAuthClientCredentials. |
keyInformation. | Set to the organization ID or merchant ID of the organization requesting the key. |
keyInformation. | Set to the organization ID that the requesting organization belongs to. |
keyInformation. | Set to nrtd. |
Retrieve List of Enabled Products
Retrieve a list of the products and event types that are enabled for your organization. Use this list to know which products and events that you can subscribe to. A successful response lists the enabled products and events in the productId and eventTypes.eventName fields. You can use these same field values when you send a create a webhook subscription request.
If the list you retrieve does not contain an expected product or event type, the product might not be enabled for your organization. Contact your account manager for more information.
Supported Products and Event Types
Set the productId field to a value in the Product ID column, and the eventTypes field array to a value in the Event Types column:
Alternative Payment Methods
| Product ID | Event Types | Description |
|---|---|---|
alternativePaymentMethods | payments. | Notifies you that an alternative payment transaction's status was been updated. |
Decision Manager
| Product ID | Event Types | Description |
|---|---|---|
decisionManager | risk. | Notifies you that a Decision Manager case was accepted. |
decisionManager | risk. | Notifies you that a Decision Manager case was rejected. |
decisionManager | risk. | Notifies you of a profile decision to reject a transaction. |
eCheck
| Product ID | Event Types | Description |
|---|---|---|
eCheck | payments. | Notifies you of a successful eCheck credit transaction. |
eCheck | payments. | Notifies you of an eCheck credit transaction failure. |
eCheck | payments. | Notifies you of a successful eCheck debit transaction. |
eCheck | payments. | Notifies you of an eCheck debit transaction failure. |
eCheck | payments. | Notifies you of a successful eCheck void transaction. |
eCheck | payments. | Notifies you of an eCheck void transaction failure. |
Fraud Management Essentials
| Product ID | Event Types | Description |
|---|---|---|
fraudManagementEssentials | risk. | Notifies you that a Fraud Management Essentials case was accepted. |
fraudManagementEssentials | risk. | Notifies you that a note has been added to a Fraud Management Essentials case. |
fraudManagementEssentials | risk. | Notifies you that a transaction was rejected. |
fraudManagementEssentials | risk. | Notifies you that a Fraud Management Essentials case was rejected. |
fraudManagementEssentials | risk. | Notifies you of a profile decision to monitor a transaction. |
fraudManagementEssentials | risk. | Notifies you of a profile decision to review a transaction. |
Invoicing
| Product ID | Event Types | Description |
|---|---|---|
customerInvoicing | invoicing. | Notifies you that an invoice was sent. |
customerInvoicing | invoicing. | Notifies you that an invoice was cancelled. |
customerInvoicing | invoicing. | Notifies you that an invoice was paid. |
customerInvoicing | invoicing. | Notifies you that an invoice was partially paid. |
customerInvoicing | invoicing. | Notifies you 5 days before the invoice payment is due. This event is triggered if you have invoice reminders enabled in your invoice settings. |
customerInvoicing | invoicing. | Notifies you 1 day after the invoice payment is due. This event is triggered if you have invoice reminders enabled in your invoice settings. |
Pay By Link
| Product ID | Event Types | Description |
|---|---|---|
payByLink | payByLink. | Merchants can subscribe to this event type to automate how their system is informed when a customer completes a payment. |
payByLink | payByLink. | Partner resellers can subscribe to this event type to control the distribution of the payment confirmation email sent to their merchants' customers. |
Payments
| Product ID | Event Types | Description |
|---|---|---|
payments | payments. | Notifies you that a payment capture request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a payment capture was updated and its status changed from PENDING to BATCHED. |
payments | payments. | Notifies you that a refund request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a refund request was batched and its status has changed from PENDING to BATCHED. |
payments | payments. | Notifies you that a credit request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a credit request was accepted. The transaction carries the status PENDING. |
payments | payments. | Notifies you that a void request was accepted. The transaction carries the status VOIDED. |
payments | payments. | Notifies you that a void request was rejected. The transaction carries the status NOT VOIDABLE. |
payments | payments. | Notifies you that an authorization request was authorized by the issuer. The transaction carries the status AUTHORIZED. |
payments | payments. | Notifies you that an authorization request was under review by Decision Manager. The transaction carries the status AUTHORIZED_PENDING_REVIEW. |
payments | payments. | Notifies you that an authorization request was declined by the issuer or failed due to server error, timeout, or invalid request. Possible statuses include INVALID_REQUEST, SERVER_ERROR, DECLINED, SERVER_TIMEOUT, or SERVICE_TIMEOUT. |
payments | payments. | Notifies you that an authorization request was partially approved by the issuer. The transaction carries the status PARTIAL_AUTHORIZED. |
payments | payments. | Notifies you that a reversal request was approved successfully. The transaction carries the status REVERSED. |
payments | payments. | Notifies you that a reversal request was declined due to issuer rejection, system error, invalid request, or timeout. Possible statuses include REVERSED, INVALID_REQUEST, SERVER_ERROR, DECLINED, SERVER_TIMEOUT, or SERVICE_TIMEOUT. |
Recurring Billing
| Product ID | Event Types | Description |
|---|---|---|
recurringBilling | rbs. | Notifies you of a recurring payment failure. |
recurringBilling | rbs. | Notifies you of an upcoming recurring payment. |
recurringBilling | rbs. | Notifies you of successful recurring payment. |
Token Management Service
| Product ID | Event Types | Description |
|---|---|---|
tokenManagement | tms. | Notifies you of a network token's change in expiration date or status (suspend, resume, or deactivate). |
tokenManagement | tms. | Notifies you when a network token provision for an instrument identifier token has been successful. |
tokenManagement | tms. | Notifies you of the binding status of a network token with a device. |
Unified Checkout
| Product ID | Event Types | Description |
|---|---|---|
unifiedCheckout | uc. | Notifies you of the payment outcome, including the full payload response from the payment service call. |
Endpoints
Send a GET request to one of these endpoints. The {organizationId} is your organization ID.
GET /notification-subscriptions/v2/products/{organizationId}
GET /notification-subscriptions/v2/products/{organizationId}
GET /notification-subscriptions/v2/products/{organizationId}
Example: Retrieving a List of Products and Events
GET /notification-subscriptions/v2/products/demomerchant_01{}[ { "productId": "terminalManagement", "eventTypes": [ { "eventName": "terminalManagement.status.update", "payloadEncryption": false }, { "eventName": "terminalManagement.assignment.update", "payloadEncryption": false }, { "eventName": "terminalManagement.reAssignment.update", "payloadEncryption": false } ] }]Create Webhook Subscription
Follow these steps to create your first webhook subscription.
Send Subscription Request
Endpoints
Send a POST request to one of these endpoints:
POST /notification-subscriptions/v2/webhooks
POST /notification-subscriptions/v2/webhooks
POST /notification-subscriptions/v2/webhooks
Example
{ "name": "My Custom Webhook", "description": "Sample Webhook from Developer Center", "organizationId": "demomerchant_01", "products": [ { "productId": "product.id", "eventTypes": [ "product.id.event.type" ] } ], "webhookUrl": "https://MyWebhookServer.com:8443/simulateClient", "securityPolicy": { "securityType": "oAuth_JWT", "config": { "oAuthTokenExpiry": "365", "oAuthURL": "https://MyWebhookServer.com:443/oAuthToken", "oAuthTokenType": "Bearer", "additionalConfig": { "aud": "idp.api.myServer.com", "client_id": "650538A1-0000-0000-0000-932ABC57AD70", "keyId": "y-00000000000000-eAZ34pR9Ts", "scope": "merchantacq:rte:write" } } }}{ "organizationId": "demomerchant_01", "productId": "product.id", "eventTypes": [ "product.id.event.type" ], "webhookId": "fe46bf08-3918-21ba-e053-a1588d0aeefa", "name": "My Custom Webhook", "webhookUrl": "https://MyWebhookServer.com:443/simulateClient", "healthCheckUrl": "https://MyWebhookServer.com:443/simulateClientHealthCheck", "createdOn": "2023-06-16T21:19:54.667Z", "status": "INACTIVE", "description": "Sample Webhook from Developer Center", "retryPolicy": { "algorithm": "ARITHMETIC", "firstRetry": 1, "interval": 1, "numberOfRetries": 3, "deactivateFlag": false, "repeatSequenceCount": 0, "repeatSequenceWaitTime": 0 }, "securityPolicy": { "securityType": "oAuth_JWT", "proxyType": "external", "digitalSignatureEnabled": "yes", "config": { "oAuthTokenExpiry": 365, "oAuthURL": "https://MyWebhookServer.com:443/oAuthToken", "oAuthTokenType": "Bearer", "additionalConfig": { "aud": "idp.api.myServer.com", "client_id": "650538A1-0000-0000-0000-932ABC57AD70", "keyId": "y-00000000000000-eAZ34pR9Ts", "scope": "merchantacq:rte:write" } } }, "version": "3", "deliveryType": "nrtdCentral", "notificationScope": "SELF"}Required Fields
| Field | Description |
|---|---|
description | Description of the webhook subscription. |
name | Name of the webhook subscription. |
organizationId | Set to your organization ID or merchant ID. |
products. | Set to the event types that you want to subscribe to for that product. Separate multiple values with the comma character (,). For a list of possible values, see Retrieve List of Enabled Products. |
products. | Set to the ID of a product that is enabled for your organization. For a list of possible values, see Retrieve List of Enabled Products. |
securityPolicy. | |
securityPolicy. | |
securityPolicy. | |
securityPolicy. | |
securityPolicy. | Set to 365. |
securityPolicy. | Set to Bearer. |
securityPolicy. | This is the URL of your OAuth server. |
securityPolicy. | Set to oAuth_JWT. |
webhookUrl | The URL in your system to which webhook notifications are sent. |
Optional Fields
| Field | Description |
|---|---|
deactivateflag | Required if the healthCheckUrl field is present. Set to true to automatically activate the subscription. |
healthCheckUrl | Set to the health check URL. Required to auto-activate the subscription. If you do not include this field, the created subscription is inactive. An inactive subscription does not send notifications. |
notificationScope. | Set to the organization IDs that you want to receive notifications for when subscribed events occur in those organizations. Concatenate each organization ID with the comma character (,). |
retryPolicy. | Set to true to withhold notifications while your webhook URL or health check URL are unresponsive. The default value is false. |
retryPolicy. | The number of minutes before the notification is resent. The default value is 1. |
retryPolicy. | The number of minutes between each retry attempt. The default value is 1. |
retryPolicy. | The number of retry attempts. The default value is 3. |
retryPolicy. | The number of times to repeat the retry sequence. The default value is 0. |
retryPolicy. | The number of minutes between each repeat sequence. The default value is 0. |
Store Subscription ID and Review Response
After sending this request, you receive a response with a subscription ID in the webhookId field. Save this ID in your system to send follow-on requests that enable you to update and manage the subscription.
Additional Response Information
The notificationScope response field indicates which organizations receive the webhook notification. By default, notifications use the DESCENDANTS setting. To modify this setting, include the notificationScope.scopeData field in your request.
These are all possible field values:
| Value | Description |
|---|---|
SELF | Only the organization creating the webhook subscription receives notifications when a subscribed event occurs. |
DESCENDANTS (default) | The organization creating the webhook subscription receives notifications when a subscribed event occurs in their organization and in any of their children/descendant accounts in their portfolio hierarchy. This is the default notification setting. |
CUSTOM | The organization creating the webhook subscription receives notifications when a subscribed event occurs in their organization and in any organization listed in the notificationScope. request field. |
When you create a subscription, its status is indicated in the status response field. If you did not include a health check URL in your request, the subscription is set to INACTIVE. If you included a health check URL and receives a response from the health check URL, the subscription status is set to ACTIVE.
These are the three possible statuses a subscription can be set to:
| Status | Description |
|---|---|
ACTIVE | The subscription is ready to send notifications or is actively sending notifications. |
INACTIVE | The subscription has not been activated. Add a health check URL to activate it. |
SUSPENDED | The subscription was active, but the webhook URL or the health check URL became unreachable. When the URL becomes reachable, the status changes to ACTIVE and notifications resume. |
Optional Setup Tasks
recommends that you include a health check URL in the subscription request. A health check URL ensures that you do not miss any notifications.
How Health Check URLs Work
Including a health check URL enables to monitor your server's status for reliability. When detects that your health check URL is unresponsive, notification deliveries are withheld until your health check URL becomes responsive again.
To add a health check URL to your create a subscription request, include these fields:
healthCheckurl: set to your health check URL.deactivateflag: set totrueto enable to withhold notifications for periods when your server becomes unresponsive.
Automatic activation
After you successfully create or update a subscription, pings your health check URL within five to ten minutes:
- If receives a response, the subscription status automatically becomes
ACTIVEand notifications are delivered. - If does not receive a response, your subscription status remains
SUSPENDEDuntil receives a response.
If you did not include a health check URL when you created the subscription, pings your webhook URL for automatic activation instead. You can also activate a subscription that is not automatically activated by sending a PUT request.
Automatic revalidation
After the subscription's initial activation, continues to monitor your server status:
- If detects that your server is unavailable, your subscription status automatically updates to
SUSPENDED, and notifications are withheld. - If detects that your server is available again, your subscription status automatically updates to
ACTIVE, and all withheld notifications are delivered.
When a webhook subscription is created or updated, the URLs associated with that subscription are evaluated through a validation and approval process.
How URL Validation Works
URL validation is designed to:
- Reduce security risk by preventing outbound calls to unapproved endpoints.
- Improve compliance through stronger review and approval controls.
- Increase transparency with clearer client-visible statuses.
- Support scale through a standardized and repeatable validation process.
URL validation applies to:
- Webhook URL (required)
- OAuth URL (if applicable)
- Health Check URL (if applicable)
Validation process:
- A webhook subscription is created or updated.
- Submitted URLs are checked against existing approval records.
- New or unknown URLs are evaluated through automated validation.
- If additional review is required, the subscription status changes to PENDING_REVIEW.
- If any URL is rejected or blocked, the subscription status changes to BLOCKED.
- If all required URLs are approved, the subscription status changes to INACTIVE.
Validation statuses: These are the statuses a subscription can be set to during URL validation:
| Status | Description |
|---|---|
| PENDING_REVIEW | One or more submitted URLs are being validated or awaiting required security approval. |
| BLOCKED | One or more URLs were rejected or identified as unsafe or non-compliant. The subscription cannot proceed until the URL(s) are updated. |
| INACTIVE | All required approvals are complete, and the subscription is ready under the existing activation flow. |
If your subscription is marked BLOCKED, one or more URLs associated with the subscription cannot be used in their current form. To continue, update the affected URLs and resubmit.
If your webhook URL or health check URL are unresponsive when sent a notification, resends the notification according to the subscription's retry policy. By default, sends you 3 notification attempts, beginning 1 minute after the initial failed attempt. Retry attempts occur in 1 minute intervals if your URL remains unresponsive.
How to Configure the Retry Policy
All subscriptions have a default retry policy. You can change the retry policy when you create a subscription or when you update the webhook subscription.
To configure a subscription's retry policy, include these required fields in the create a subscription request or an update a subscription request:
| Field | Description |
|---|---|
retryPolicy. | Set to one of these values: false — Notifications are not withheld when your webhook URL or health check URL are unresponsive. This value is the default. true — Notifications are withheld when your webhook URL or health check URL are unresponsive, and the subscription status updates to SUSPENDED. When the URLs become responsive again, the withheld notifications are sent and the subscription status updates to ACTIVE. |
retryPolicy. | The number of minutes before the notification is resent. The default value is 1. |
retryPolicy. | The number of minutes between each retry attempt. The default value is 1. |
retryPolicy. | The number of retry attempts. The default value is 3. |
retryPolicy. | The number of times to repeat the retry sequence. The default value is 0. |
retryPolicy. | The number of minutes between each repeat sequence. The default value is 0. |
Example: This example shows how to format a retry policy in a request.
"retryPolicy": { "firstRetry": "1", "interval": "1", "numberOfRetries": "3", "deactivateFlag": "false", "repeatSequenceCount": "0", "repeatSequenceWaitTime": "0" }Receive a Notification
After creating a webhook subscription, you receive a notification when a subscribed event occurs. Review the notification fields and example to know how to interpret the notification.
Notification Message Body
The message body contains fields associated with the notification and the payload of the event that generated the notification.
| Field | Description |
|---|---|
webhookId | The identifier of the webhook subscription that generated the notification. |
transactionTraceId | The identifier of the notification attempt. Every retry attempt has a unique transaction trace ID. |
productId | The identifier of the product that generated the event. |
organizationId | The identifier of the organization that is subscribed to the notification. |
eventType | The type of event that generated the notification. |
eventDate | The timestamp of when the event occurred. |
payload | The data generated by the event. |
requestType | The indicator of whether the notification is new or a retry attempt. |
Notification Payload Example
This example shows a complete Token Management Service webhook notification, including its headers and payload:
POST /test HTTP/1.1Host: test.test.comContent-Length: 537Content-Type: application/jsonv-c-event-type: product.event.typev-c-organization-id: orgidv-c-product-name: productv-c-request-type: NEWv-c-retry-count: 0v-c-signature: "t=timestamp;keyId=key-UUID;sig=calculatedDigitalSignature"v-c-transaction-trace-id: "7ac2ad9f-6a89-d3e9-e053-34b8d30aaf40"v-c-webhook-id: "e339e8b1-d540-4efd-e053-8d588e0a2de5"{ "eventType": "tms.networktoken.provisioned", "webhookId": "e339e8b1-d540-4efd-e053-8d588e0a2de5", "productId": "tokenManagement", "organizationId": "sampleSubscriptionHolder", "eventDate": "2022-07-20T11:38:45", "transactionTraceId": "7ac2ad9f-6a89-d3e9-e053-34b8d30aaf40", "retryNumber": 0, "payload": { "data": { "_links": { "paymentInstruments": [ { "href": "/tms/v1/paymentinstruments/...................." } ], "instrumentIdentifiers": [ { "href": "/tms/v1/instrumentidentifiers/...................." } ] }, "id": "...................", "type": "tokenizedCardEnrollments", "version": "1.0" }, "organizationId": "sampleSelfOrChildOrg" }, "requestType": "NEW"}Next Steps
After creating your first webhook subscription, you can now review additional events to subscribe to, manage your existing subscriptions, and troubleshoot any delivery issues.
Supported Products
Tables of all webhook-subscribable products and their event type values.
View referenceTroubleshooting
Troubleshoot webhook subscriptions and message-level encryption issues.
View guideUpdate a Subscription
Update an existing webhook subscription, such as the notification scope, health check URL, or retry policy.
View guideDelete a Subscription
Delete a webhook subscription. Deleting a subscription does not delete the history of webhook notifications.
View guideThanks for your feedback!
Last published: October 28, 2026