Timely and automated payment status notifications
Overview
KeyBank’s payment webhooks provide timely and automated payment status notifications without the need for continuous API polling or manual checks.
We currently facilitate alerts for payment transactions status changes like ACH, RTP, and wire. You receive near real-time updates whenever a payment event occurs, such as a posted ACH transaction or a completed wire transfer.
Requirements
To subscribe to webhook alert notifications for ACH, Wire, or RTP transactions, you must be a commercial customer or fintech partner of KeyBank. Only authorized API clients can subscribe to this feature.
- Existing clients: Contact your Technical Account Manager to begin the subscription process.
- New clients: You must first complete onboarding with KeyBank (see the Get Started Guide for an overview). During the setup, you will be asked to provide additional information, including:
- The type of alert subscription you require (see alert codes)
- Whether your pre-production and production subscriptions accounts will be the same or separate
- Expected transaction volumes per day, month, and year
Authentication
To maintain system integrity and security, KeyBank recommends that your destination application use authentication that follows these guidelines:
- Use Basic Authentication (BasicAuth). Provide KeyBank with a unique username and password for your application.
- Credentials are encoded for transmission. KeyBank sends a Base64 encoded version of your credentials in the
Authorizationheader of the webhook HTTP request. - Use a secure TLS connection. This is necessary for encrypted and safe exchange of data.
If you have a specialized needs or circumstances that require secure alternatives to Basic Authentication, speak with your KeyBank Technical Account Manager. Note, using alternative methods may extend setup time.
Webhook flow
KeyBank sends you an alert (HTTP POST).
KeyBank's Enterprise Alert Platform (EAP) pushes an HTTP POST to the webhook endpoint you have registered. The POST contains an
alertNotificationRequestwith one or more alerts, including important fields likealertCode,transactionStatus, and the KeyBank-assignedeapAlertGUID.KeyBank’s webhook service may send up to 100 alert messages within a single webhook delivery.
This is event-driven. Your system does not poll. KeyBank pushes alerts whenever a transaction changes status.
Your application processes the alert.
After receiving the POST alert, your system authenticates it, parses each alert in the batch, and updates your internal records using IDs like
traceNumberandeapAlertGUID.This step is entirely on the client-side. KeyBank does not wait for your business logic, only for your acknowledgment.
You send back an acknowledgment (HTTP 200/202).
Within 10 seconds, your system must reply with an HTTP 200 OK or HTTP 202 Accepted. If there is an error, you are expected to send one of the HTTP 4xx or 5xx status codes. If KeyBank receives a 5xx status code, it triggers the retry mechanism.
If you want to send back a structured or more detailed acknowledgement, KeyBank recommends a response structure that includes key identifiers like
eapAlertGUIDand theconfirmationGUID.
Got you hooked?
Check out some more content about our webhooks:
Webhook notification request
Each webhook alert includes an alertNotification object with two components: alertHeader and alertBody. These components may differ slightly depending on whether the event relates to ACH or Wire/RTP.
alertHeader
The header contains metadata about the notification, including:
- the date and time the alert was sent
- the alert code identifying the payment rail (ACH vs Wire/RTP)
- a unique notification identifier
alertBody
The body contains detailed transaction information. All fields appear in the request even when there is no value available. Fields with no applicable data will contain the null value.
For Wire/RTP alerts, look at the tranBusnStatusCode to see where the transaction is in the process. Go to Data values > Wire and RTP webhook statuses to view the full list.
When payments talks...webhooks listen
Alert notifications are triggered by specific payment-status events and delivered as HTTP POST requests. KeyBank may include up to 100 alerts per API call.
Alert codes
Alert codes identify the payment-status event that triggered the notification. There are alert codes for Wire/RTP and ACH to monitor all payment status events related to that transaction type.
Wire/RTP alert codes
AL00901 - Full transaction details
This alert code returns the most detailed view of the transaction with identifying data for:
- the originator
- the beneficiary
- any intermediary banks
- related parties and references
AL00907 - Summary transaction details
This alert code returns a simplified status notification providing:
- transaction station
- debtor/creditor information
- reference and identification numbers
ACH alert codes
AL00906 - ACH status notification
This alert code returns ACH-specific status information for collected, posted, or returned transactions and any related references.
AL00901 - Wire/RTP alerts
Request
| HEADER FIELD | TYPE | DESCRIPTION |
|---|---|---|
| alertSentDateAndTime | string | Date and time the alert was sent. Format: (YYYY-MM-DD)T(HH:MM:SS)Z |
| alertCode | string | For Wire and RTP alerts, the alert code is AL00901. |
| eapAlertGUID | string | Unique alert notification identifier. |
| BODY FIELD | TYPE | DESCRIPTION |
|---|---|---|
| crOrDbCode | string | Identifies the transaction type as credit or debit. Valid values: C (credit), D (debit) |
| crArngNum | string | Account number of the credit account. |
| crArngTypeCode | string | Type code of the credit account. |
| crArngBankNum | string | Bank number of the credit account. |
| crTranCurrencyCode | string | Transaction currency code of the credit account. |
| dbArngTypeCode | string | Type code of the debit account |
| dbTranCurrencyCode | string | Transaction currency code of the debit account. |
| requestReferenceNumber | string | Unique identification number for an originating wire or RTP transaction. This number is limited to 32 characters. |
| crIpId | string | Customer number associated with the credit account. |
| crIpNm | string | Customer name associated with the credit account. |
| dbArngNum | string | Account number of the debit account. |
| dbArngBankNum | string | Bank number of the debit account. |
| dbIpId | string | Customer number associated with the debit account. |
| dbIpINm | string | Customer name associated with the debit account. |
| payNotifyTs | string | Timestamp of the payment event. |
| wireEventNm | string | Payment status code |
| tranAmt | string | Dollar amount of the transaction. |
| tranExecutedDt | string | Date the transaction is executed. Format: YYYYMMDD |
| federalReferNum | string | Federal reference number |
| sndngBankReferNum | string | Reference number attached to a wire, issued by the sending bank. |
| tranId | string | Unique transaction identifier |
| tranBusnStatusCode | string | Transaction business status code |
| wireDirectionCode | string | Indicates the direction of the transaction. |
| tranType | string | Type of transaction. |
| tranValueTypeCode | string | Identifies the value of a transaction. |
| wireProcessTypeCode | string | Wire processing type code |
| benefitAba | string | ABA routing number of the beneficiary. |
| benefitArngNum | string | Account number of the beneficiary. |
| benefitIpAddrLine | string | Address lines 1-7 (array) of the beneficiary. |
| benefitBicCode | string | BIC number of the beneficiary. |
| benefitBankAbaNum | string | ABA routing number of the beneficiary's bank. |
| benefitBankArngNum | string | Account number of the beneficiary's bank. |
| benefirBankAddrLine | string | Address lines 1-7 (array) of the beneficiary's bank. |
| benefitBankBicCode | string | BIC number of the beneficiary's bank. |
| benefitBankNm | string | Name of the beneficiary's bank. |
| intrmdryBankAbaNum1 | string | ABA routing number of the intermediary bank 1. |
| intrmdryBNankAddrLine1 | string | Address lines 1-7 (array) of the intermediary bank 1. |
| intrmdryBankNm1 | string | Name of the intermediary bank 1. |
| intrmdryBicCode1 | string | BIC number of the intermediary bank 1. |
| intrmdryBankAbaNum2 | string | ABA routing number of the intermediary bank 2. |
| intramdryBankAddrLine2 | string | Address lines 1-7 (array) of the intermediary bank 2. |
| intrmdryBankNm2 | string | Name of the intermediary bank 2. |
| intrmdryBicCode2 | string | BIC number of the intermediary bank 2. |
| intrmdryBankAbaNum3 | string | ABA routing number of the intermediary bank 3. |
| intrmdryBankAddrLine3 | string | Address lines 1-7 (array) of the intermediary bank 3. |
| intrmdryBankNm3 | string | Name of the intermediary bank 3. |
| intrmdryBicCode3 | string | BIC number of the intermediary bank 3. |
| orgntngBankAbaNum | string | ABA routing number of the wire originator's bank. |
| orgntngBankAddrLine | string | Address lines 1-7 (array) of the wire originator's bank. |
| orgntngBankBicCode | string | BIC number of the wire originator's bank. |
| orgntngBankNm | string | Name of the wire originator's bank. |
| orgntngAba1 | string | ABA routing number of the originator 1. |
| orgntngArngNum1 | string | Account number of the originator 1. |
| orgntngIpNm1 | string | Name of the originator 1. |
| orgntngIpAddrLine1 | string | Address lines 1-7 (array) of the originator 1. |
| orgntngAba2 | string | ABA routing number of the originator 2. |
| orgntngArngNum2 | string | Account number of the originator 2. |
| orgntngIpNm2 | string | Name of the originator 2. |
| orgntngIpAddrLine2 | string | Address lines 1-7 (array) of the originator 2. |
| orgntngAba3 | string | ABA routing number of the originator 3. |
| orgntngArngNum3 | string | Account number of the originator 3. |
| orgntngIpNm3 | string | Name of the originator 3. |
| orgntngIpAddrLine3 | string | Address lines 1-7 (array) of the originator 3. |
| crVirtualNum | string | Virtual account number of the credit account. |
| dbVirtualNum | string | Virtual account number of the debit account. |
Request example (AL00901)
{
"alertNotificationRequest": [
{
"alertNotification": {
"alertHeader": {
"alertSentDateAndTime": "2023-02-1159T10:20:56Z",
"alertCode": "AL00901",
"payType": "WIRE",
"eapAlertGUID": "f4d88cd2-446c-3cc4-9330-aa123456789"
},
"alertBody": {
"crOrDbCode": "C",
"crArngNum": "359123456789",
"crArngTypeCode": "DDA",
"crArngBankNum": "0101",
"crTranCurrencyCode": "USD",
"dbArngTypeCode": "DDA",
"dbTranCurrencyCode": "USD",
"requestReferenceNumber": "4630123-20240212161123",
"crIpId": "999997",
"crIpNm": "BANKOFTEST",
"dbArngNum": "201907987654321",
"dbArngBankNum": "0101",
"dbIpId": "30472222",
"dbIpNm": "Test Name",
"payNotifyTs": "1673615327943",
"wireEventNm": "WirePaymentTransactionEvent",
"tranAmt": "12.79",
"tranExecutedDt": "20230112",
"federalReferNum": "null",
"sndngBankReferNum": "null",
"tranId": "US23010987654321",
"tranBusnStatusCode": "RegulatoryFilter",
"wireDirectionCode": "OUTBOUND",
"tranType": "null",
"tranValueTypeCode": "N",
"wireProcessTypeCode": "null",
"benefitAba": "null",
"benefitArngNum": "3435656765",
"benefitIpAddrLine": "250 Delaware Ave St",
"benefitBicCode": "KEYBUS33 XXX",
"benefitBankAbaNum": "null",
"benefitBankArngNum": "null",
"benefitBankAddrLine": "250 Delaware Ave St",
"benefitBankBicCode": "KEYBUS33 XXX",
"benefitBankNm": "KeyBank National Association",
"intrmdryBankAbaNum1": "null",
"intrmdryBankAddrLine1": "null",
"intrmdryBankNm1": "KeyBank National Association",
"intrmdryBicCode1": "21300077",
"intrmdryBankAbaNum2": "null",
"intrmdryBankAddrLine2": "null",
"intrmdryBankNm2": "BANKOFTEST",
"intrmdryBicCode2": "KEYBUS33 XXX",
"intrmdryBankAbaNum3": "null",
"intrmdryBankAddrLine3": "null",
"intrmdryBankNm3": "null",
"intrmdryBicCode3": "null",
"orgntngBankAbaNum": "null",
"orgntngBankAddrLine": "null",
"orgntngBankBicCode": "null",
"orgntngBankNm": "null",
"orgntngAba1": "null",
"orgntngArngNum1": "123456789",
"orgntngIpNm1": "TEST COMPANY 1, LLC",
"orgntngIpAddrLine1": "127 Public Sq, Cleveland,OH 44114,US",
"orgntngAba2": "null",
"orgntngArngNum2": "null",
"orgntngIpNm2": "null",
"orgntngIpAddrLine2": "null",
"orgntngAba3": "null",
"orgntngArngNum3": "null",
"orgntngIpNm3": "null",
"orgntngIpAddrLine3": "null",
"crVirtualNum": "953456789",
"dbVirtualNum": "953654321"
}
}
}
]
}AL00907 - Wire/RTP alerts
Request
| HEADER FIELD | TYPE | DESCRIPTION |
|---|---|---|
| alertSentDateAndTime | string | Date and time the alert was sent. Format: (YYYY-MM-DD)T(HH:MM:SS)Z |
| alertCode | string | For Wire and RTP alerts, the alert code is AL00907. |
| payType | string | Identifies if the payment type was a Wire or RTP transaction. Valid values: WIRE, RTP |
| eapAlertGUID | string | Unique alert notification identifier. |
| BODY FIELD | TYPE | DESCRIPTION |
|---|---|---|
| transactionId | string | The unique ID number associated with the original payment request. |
| transactionStatus | string | Status of the transaction. |
| transactionDate | string | Date the transaction occurred. Format: YYYY-MM-DD |
| transactionAmount | string | The dollar amount of the transaction. |
| requestReference | string | A reference value for the original request that is useful for traceability and reporting. |
| sendersReference | string | Sender tracking reference number returned from the request. |
| channel | string | Indicates if the transaction is from the API or a batch channel. Valid values: API, BATCH |
| transactionDirection | string | Indicates if the transaction is incoming or outgoing. Valid values: INBOUND, OUTBOUND |
| creditor | object | Customer number associated with the credit account. |
| name | string | Contains the customer identification number and the company name. |
| creditorAccount | object | Details about the creditor account. |
| accountNumber | string | Account number of the party. |
| virtualAccountNumber | string | Account number for the virtual account (VAM). |
| currencyCode | string | Indicates type of currency for the transaction amount. |
| debtor | object | Customer name associated with the debit account. |
| name | string | Contains the customer identification number and the company name. |
| debtorAccount | object | Details about the debtor account. |
| accountNumber | string | Account number of the party. |
| virtualAccountNumber | string | Account number for the virtual account (VAM). |
| currencyCode | string | Indicates type of currency for the transaction amount. |
Request example (AL00907)
{
"alertNotificationRequest": [
{
"alertNotification": {
"alertHeader": {
"alertSentDateAndTime": "2025-04-14T10:50:56Z",
"alertCode": "AL00907",
"payType": "WIRE",
"eapAlertGUID": "f4d88cd2-446c-3cc4-9330-aa123456789"
},
"alertBody": {
"transactionId": "US25032500068519",
"transactionStatus": "IN_PROCESS",
"transactionDate": "2025-03-25",
"transactionAmount": "6.48",
"requestReference": "36691398-42",
"sendersReference": "01234",
"channel": "API or BATCH",
"transactionDirection": "OUTBOUND",
"creditor": {
"name": "RTP GL Clearing Account"
},
"creditorAccount": {
"accountNumber": "1120108811111",
"virtualAccountNumber": "953006666798343",
"currencyCode": "USD"
},
"debtor": {
"name": "LINCOLN ELECTRIC CO"
},
"debtorAccount": {
"accountNumber": "149222222",
"virtualAccountNumber": "953006666796016",
"currencyCode": "USD"
}
}
}
}
]
}AL00906 - ACH alerts
Request
| HEADER FIELD | TYPE | DESCRIPTION |
|---|---|---|
| alertSentDateAndTime | string | Date and time the alert was sent. Format: (YYYY-MM-DD)T(HH:MM:SS)Z |
| alertCode | string | Alert code. Valid values: AL00906 |
| eapAlertGUID | string | Unique alert notification identifier. |
| BODY FIELD | TYPE | DESCRIPTION |
|---|---|---|
| transactionStatus | string | The status of the ACH transaction. Valid values: COLLECTED, RETURNED, SETTLED |
| traceNumber | string | The unique number for the transaction provided by the originator. |
| parNumber | string | The unique PAR number assigned to the the transaction by the ACH product processor. |
| transactionAmount | number | The dollar amount of the transaction. |
| collectionDate | string | Date the transaction was processed. Format: YYYY-MM-DD |
| settlementDate | string | The date the transaction settlement occurred. Format: YYYY-MM-DD |
| transactionCode | string | Two-digit code identifying the account type at the receiving financial institution. |
| transactionDescription | string | Description about the purpose of the transaction. |
| authorizedCustomerName | string | Authorized customer name |
| standardEntryClassCode | string | Three-digit Standard Entry Class (SEC) code based on Nacha rules. Valid values: CCD, CTX, PPD, TEL, WEB |
| receivingAccountNumber | string | Account number of the person or institution receiving the funds. |
| receivingCustomerIdentificationNumber | string | The customer identification number for the person receiving the transaction. |
| receivingCompanyName | string | Company name of the institution getting the funds. |
| originatingAccountNumber | string | Account number of the ACH transaction originator. |
| originatingCompanyName | string | Company name of the or associated with the ACH originator. |
| originatingCustomerIdentificationNumber | string | Originating customer identification number |
| returnReasonCode | string | The code associated with the reason for returning the ACH transaction. The code is the letter 'R' for reason followed by a two-digit numeric code. Format: R00 |
| returnReasonDescription | string | Description as to why the ACH transaction is returned. |
| returnDate | string | Date of the returned transaction to the ACH system. Format: YYYY-MM-DD |
| notificationOfChangeAddendaCount | string | Count of change notifications for addenda records. |
| internationalAddendaCount | string | Count of international addenda records. |
| addendaCount | string | Count of addenda records. |
Request example (AL00906)
{
"alertNotificationRequest": [
{
"alertNotification": {
"alertHeader": {
"alertSentDateAndTime": "2024-07-07T16:25:08Z",
"alertCode": "AL00906",
"eapAlertGUID": "4g0fda4b-156f-483c-98ae-bd8ccab266h0"
},
"alertBody": {
"transactionStatus": "COLLECTED",
"traceNumber": "41033956478656",
"parNumber": "22010008879477",
"transactionAmount": "287.40",
"collectionDate": "2024-01-12",
"settlementDate": "2024-01-12",
"transactionCode": "22",
"transactionDescription": "PAYMENT",
"authorizedCustomerName": "HIGHMARK INC.",
"standardEntryClassCode": "CCD",
"receivingAccountNumber": "00000000001000004133",
"receivingCustomerIdentificationNumber": "65A658990",
"receivingCompanyName": "LEHIGH GASTROENTEROLOG",
"originatingAccountNumber": "00000000001000005244",
"originatingCustomerIdentificationNumber": "7498659450",
"originatingCompanyName": "HIGHMARK INC.",
"returnReasonCode": "R29",
"returnReasonDescription": "Corporate Customer Advises Not Authorized",
"returnDate": "2024-01-03",
"notificationOfChangeAddendaCount": "1",
"internationalAddendaCount": "0",
"addendaCount": "0"
}
}
}
]
}Webhook response
Response structure
You are not required to respond with anything beyond the HTTP 200 or 202 acknowledgment. However, if you are interested in a more structured response, KeyBank recommends the following response format for the alertAcknowledgement object that includes two key identifiers:
eapAlertGUID: KeyBank‑generated unique alert identifier from the request. Copy the latest value from the corresponding alert to pass through unchanged.confirmationGUID: A unique identifier that you, the client, create and include in the response. It links the transaction from KeyBank (identified by theeapAlertGUID) to your record of receiving the transaction.
Response
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
| alertStatus | string | Indicates if the alert was a success or failure. Typically "SUCCESS" when your application processes the alert without issue. |
| confirmationGUID | string | A unique ID generated by your system to identify your receipt of the alert. |
| alertRecievedDateAndTime | string | Date and time the alert was received. Format: (YYYY-MM-DD)T(HH:MM:SS)Z |
| eapAlertGUID | string | The KeyBank‑generated unique alert identifier. You must copy this value unchanged from the corresponding alert in the incoming request. |
| message | string | Optional, human-readable message about the processing outcome. |
Successful - 200/202 response example
{
"alertNotificationResponse": [
{
"alertAcknowledgment": {
"alertStatus": "SUCCESS",
"confirmationGUID": "5f0ada5b-056f-483c-98ae-ac6ccab269c1",
"alertRecievedDateAndTime": "2021-11-19T10:31:12.000Z",
"eapAlertGUID": "5163dee6-0b2b-4901-9f6a-4b3997ee8d77",
"message": "Successfully submitted the request"
}
}
]
}Error handling
If your webhook receiver/handler encounters an error, KeyBank expects you to send one of the following HTTP status codes:
- 400: Invalid input
- 401: Authentication error
- 403: Authorization error
- 500: Internal errors
- 504: Gateway timeout (set to 30 seconds)
Both HTTP 400 and HTTP 500 errors are configured to send a structured response that includes the eapAlertGUID. KeyBank will resend the alert with the retry mechanism, using the latest eapAlertGUID received from the response.
The HTTP 500 codes prompt the retry mechanism. If you have one of the HTTP 400 codes, you are expected to troubleshoot the issue. If you cannot find a resolution, please contact your Technical Account Manager.
Unsuccessful - 400 response example
{
"alertNotificationResponse": [
{
"alertAcknowledgment": {
"alertStatus": "FAILURE",
"confirmationGUID": "5f0ada5b-056f-483c-98ae-ac6ccab269c1",
"alertRecievedDateAndTime": "2021-11-19T10:31:12.000Z",
"eapAlertGUID": "ce816009-4aa9-47c7-b2ee-bacf9f0872d0",
"message": "Required parameter(s) not found: [fieldName(s)]"
}
}
]
}Alert retry mechanism
The retry mechanism sends a failed alert notification if the transaction encounters any backend related issues. If KeyBank receives a HTTP 5XX error code, the retry mechanism will send up to three alerts to retry over a period of 24 hours after the original failed notification.
| Attempt number | Alert sent at | Time between each attempt |
|---|---|---|
| 1 | 5 minutes | Initial alert |
| 2 | 1 hour | 55 minutes |
| 3 | 12 hours | 11 hours |
| 4 | 24 hours | 12 hours |
After the 24-hour window, the notification fails and there are no more additional retry attempts. Notify your Technical Account Manager if there is an outage for more than 24 hours or if you have an outage planned for your systems that extends past a 24-hour period. You can also notify us with our Support form.
To inquire about a payment event after 24 hours, you must use the ACH Inquiry or Wire Inquiry APIs.
Changelog
3.0.0
June 2025 | MID impact
We have a new Wire/RTP alert event - AL00907. This event is a simple, straight-forward alert notification that shares transaction and party information.
2.2.0
January 2025 | LOW impact
The retry mechanism logic has been updated to send three alerts over the period of a 24 hours. This is a reduction from the initial design of 12 attempts over 24 hours. This change helps us avoid sending too many alerts for ACH batch type requests if it encounters a HTTP 5XX error.
2.1.0
August 2024 | HIGH impact
We introduce the version 2 of our Webhooks. This API is sleek! For ACH alerts, the alert codes (AL00902, AL00903, AL00904, AL00905) have been consolidated into a single and new code, AL00906.
1.2.0
April 2024 | MID impact
- For Wire and RTP webhook alert notifications,
dbTranCurrencyCodeanddbAngTypeCodeare in the alert body. - Added the
requestReferenceNumberto the alert body for Wire and RTP alert notification. If this parameter has a value, it will return in the alert body for RTP or Wire notifications.
1.1.0
December 2023 | LOW impact
Remove all leading zeros for the following account parameters:
crArngNumdbArngNumaccountNumber
1.0.1
August 2023
Released on the Developer Portal.
Impact levels
- LOW: This is a minor change or enhancement that does not alter the operations of the API. Upgrading to the latest specifications is preferable but not required.
- MID: The previous API version is valid and operates, but does not contain latest enhancements. You need to update your specifications to get these enhancements.
- HIGH: The previous API version is no longer operable. You must upgrade to the latest specifications to access and use this API product.
YAML file