Events and Webhooks

You can configure webhook endpoints via APIs or Dashboard in your platform to be notified about events from Column. Each platform can create multiple webhook endpoints for different types of events. All webhook endpoints must be configured with https URLs that accept POST requests with JSON payloads.

Events limited to single webhook

Only one webhook endpoint on your platform can receive events of the same type. If you create two endpoints, both of which are configured for all ach event types, only the webhook created first will be notified of ACH events. Please take care to ensure multiple webhook endpoints are configured for different event types.

Event Object

Column event objects all have the same top level structure with unique information related to that event.

  • id unique identifier of an event. If a webhook event is sent multiple times, its id will remain the same for all requests.
  • created_at time at which an event was created.
  • type description of an event (see the table below for all types of events).
  • data object containing data associated with an event. Please refer to All Event Types for the data object of each event.
{
  "id": "evnt_1vEdMiZ5pmkmrKZfNZ8LeqF2KFP",
  "created_at": "2021-07-12T23:05:36Z",
  "type": "ach.outgoing_transfer.completed",
  "data": {
    "id": "acht_1vEdMiRjQWQYqRqaOppMfU7BWr1",
    ... // rest details of ACH transfer object
  }
}

Authentication

To verify that a webhook event was actually sent by Column, every webhook event payload is signed with a signature that is passed through as the HTTP header Column-Signature. The signature is a hash-based message authentication code (HMAC) with SHA-256, by applying the webhook endpoint's signing secret as the key, and the JSON payload (i.e., the request body) as the message. The HTTP header Webhook-Endpoint-Id specifies the webhook endpoint ID to which an event is sent.

Warning

Please use our raw webhook payloads without any modification to calculate signatures. Any pre-processing of our raw webhook payloads (e.g., prettify, deserialize/serialize, trim spaces, etc.) may result in different signatures.

All webhook events from Column will be sent from the following IPs, which can be whitelisted in your system:

  • 44.231.156.17

Confirmation & Retry

After an event is delivered to a webhook endpoint, and our system receives a 2XX HTTP response within 10 seconds, that event is considered to have been delivered successfully. If an event delivery failed, our system will retry up to 25 times within 3 days with exponential backoffs. The first retry happens one minute after the original failed delivery. An event may occasionally be delivered multiple times to a webhook endpoint with the same unique event ID. We advise you to guard against duplicated event receipts by making your event processing idempotent. In addition, we suggest you return a 2XX HTTP response right after an event is received, before you actually process it in your system, to avoid any potential timeout errors.

Event Ordering

Our webhook system does NOT guarantee that events will be delivered in the same order as they are created. For example, the following events might be created for an ACH transfer:

  • ach.outgoing_transfer.initiated
  • ach.outgoing_transfer.submitted
  • ach.outgoing_transfer.settled
  • ach.outgoing_transfer.acknowledged

An endpoint should not expect delivery of those events in this order and should handle so accordingly. In most cases, out of order event delivery happens when a previous delivery failed. For example, if our post to your webhook endpoint timed out when we tried to deliver ach.outgoing_transfer.initiated, it will be rescheduled with an exponential backoff time. If ach.outgoing_transfer.submitted is scheduled before that, and we successfully delivered it to your endpoint, ach.outgoing_transfer.initiated will be delivered after ach.outgoing_transfer.submitted. You can use our event APIs to fetch any missing or additional events, if necessary.

Examples

Setup a webhook endpoint

Each webhook endpoint must be configured to accept certain types of events by specifying them in the enabled_events list. You can use one webhook endpoint to handle several different event types at once or set up individual endpoints for specific types of events.

Wildcard * is supported as well. For example, you can use ach.* to accept all ACH transfer events, or * for all webhook events. Please be careful when using *, as it may overload your webhook servers. If multiple endpoints are configured for a certain event type, events of that type will be sent to the first configured endpoint.

curl https://api.column.com/api/webhook_endpoints \
  -X POST \
  -u :<api_key> \
  -d url="https://example.com/webhook" \
  -d description="endpoint for ACH events" \
  -d "enabled_events[]"="ach.*" \
  -d "enabled_events[]"="book.outgoing_transfer.completed"

Check the webhook signature

Column signs the webhook events sent to your endpoints by including a signature in each event's Column-Signature header. This allows you to verify that the events were sent by Column, not by a third party. Before you can verify signatures, you need to retrieve your endpoint's secret from your Dashboard's Webhook settings. Column generates a unique secret key for each endpoint.

Once you have the endpoint secret and the raw request body content of a webhook, you can compute an HMAC with the SHA256 hash function, by using the secret as the key and request body as the message. The result should be equal to the value of Column-Signature header for a valid webhook event sent by Column.

Fetch events

You can fetch all events (including events that are not sent via webhooks) that happened via our /api/events API. If you just want to fetch events that were sent to your webhook endpoints, you can use our /api/events/webhook API. Please refer to All Event Types for more information.

Fetch event delivery history

You can fetch the history of webhook deliveries for a certain endpoint or event. The responses of such requests will contain list of all webhook delivery attempts and their statuses based on query filters.

{
  "webhook_deliveries":  [
    {
      "event":  {
        ... // event object defined above
      },
      "scheduled_at":  "2021-07-19T17:34:34Z",
      "status":  "SUCCEEDED"
    },
    ... // more webhook delivery attempt
  ]
}

Protect endpoint secrets

Endpoint signing secrets are critical for you to authenticate webhook events from Column. If an endpoint's secret is believed to be compromised, you can create a new webhook subscription endpoint with the same URL and enabled events. Column will continue sending webhook events to the old endpoint until you have updated your system with the new endpoint secret and deleted the old endpoint. At that point, Column will start to send webhook events to the new endpoint.

All Event Types

This is a list of all the types of events we currently create. Note that this list is a work-in-progress. We may add or delete events at any time, so please keep that in mind while developing and maintaining your code. All event types follow a pattern {category}.{action} or {category}.{sub_category}.{action}.

Not all events will be sent via webhook endpoints. Events marked as WEBHOOK: FALSE are only created but not sent via webhook. However, you can fetch all types of events via our event APIs.

Book Transfer Events


For all Book transfer events, data in the webhook response will be the Book Transfer Object at the time the webhook is fired.

book.transfer.initiated (WEBHOOK: FALSE)
Column has received your book transfer request.

book.transfer.completed
Column has processed your book transfer request successfully. This event may be fired directly upon creating a book transfer, or in the case of a hold, when the clear endpoint is called.

book.transfer.hold_created
Column has received your book transfer request with a hold.

book.transfer.updated
Column has updated your book transfer in a hold state successfully.

book.transfer.canceled
Column has canceled your book transfer in a hold state successfully. Funds that were in a hold state because of this transfer are now available.

ACH Transfer Events


For all ACH transfer events, data in the webhook response will be the ACH Transfer Object at the time the webhook is fired.

ach.outgoing_transfer.initiated
Column has received your ACH transfer request and will submit it to the Federal Reserve Bank at the next settlement window.

ach.outgoing_transfer.manual_review
The transfer is in manual review and will be evaluated by the Column team.

ach.outgoing_transfer.submitted
Column has submitted the ACH transfer request to the Federal Reserve Bank.

ach.outgoing_transfer.settled
The ACH transfer has been settled at the RDFI. For outgoing ACH debit transfers, funds will be available to withdraw once they are settled.

ach.outgoing_transfer.completed
The return window has passed for this ACH transfer, and it is deemed officially completed. In a few very rare cases, it can still be returned by the RDFI with return code R06 or R31 (Return Reason Codes).

ach.outgoing_transfer.returned
The outgoing ACH transfer has been returned by the RDFI. Return details are available in ach_transfer.return_details.

ach.outgoing_transfer.return_dishonored
The return from the RDFI of an outgoing ACH transfer has been dishonored by Column. Return details are available in ach_transfer.return_details.

ach.outgoing_transfer.return_contested
The dishonored return from Column of an outgoing ACH transfer has been contested by the RDFI. Return details are available in ach_transfer.return_details.

ach.outgoing_transfer.canceled
The ACH transfer has been canceled before Column submits it to the Federal Reserve Bank per your request.

ach.outgoing_transfer.noc
Column has received a Notification of Change (NOC) from the RDFI that some information about the counterparty should be updated. NOC details are available in ach_transfer.notification_of_changes.

ach.incoming_transfer.scheduled
Column has received an incoming ACH transfer (either credit or debit) from another ODFI, and scheduled to process it on its settlement date.

ach.incoming_transfer.settled
Column has received an incoming ACH transfer (either credit or debit) from another ODFI, and settled it successfully.

ach.incoming_transfer.nsf
Column attempted to process an incoming ACH credit/debit transfer request, but their were insufficient funds in the account. This is usually followed by a returned event.

ach.incoming_transfer.completed
The return window has passed for this incoming ACH transfer, and it is deemed officially completed. In a few very rare cases, you can still request to return it with return code R06 or R31 (Return Reason Codes).

ach.incoming_transfer.returned
The incoming ACH transfer has been returned by Column. Return details are available in ach_transfer.return_details.

ach.incoming_transfer.return_dishonored
The return sent by Column for an incoming ACH transfer has been dishonored by the ODFI. Return details are available in ach_transfer.return_details.

ach.incoming_transfer.return_contested
The dishonored return from the ODFI of an incoming ACH transfer has been contested by Column. Return details are available in ach_transfer.return_details.

Wire Transfer Events


For all Wire transfer events, data in the webhook response will be the Wire Transfer Object at the time the webhook is fired.

wire.outgoing_transfer.initiated
Column has received your wire transfer request and will submit it to the Federal Reserve Bank soon.

wire.outgoing_transfer.manual_review
The transfer is in manual review and will be evaluated by the Column team.

wire.outgoing_transfer.submitted
Column has submitted the wire transfer request to the Federal Reserve Bank.

wire.outgoing_transfer.rejected
The wire transfer request has been rejected by Column or by the Federal Reserve (this event will rarely happen).

wire.outgoing_transfer.completed
Column has received an acknowledgement from the Federal Reserve that this wire transfer request has been processed successfully.

wire.incoming_transfer.completed
Column has received an incoming wire transfer (credit only) from another ODFI, and processed it successfully.

Wire Drawdown Events


For all Wire drawdown events, data in the webhook response will be the Wire Drawdown Object at the time the webhook is fired.

wire.incoming_drawdown_request.received
Column has received an incoming wire drawdown request from another ODFI.

wire.incoming_drawdown_request.approved
The incoming wire drawdown request has been approved, Column will send an outgoing wire.

wire.incoming_drawdown_request.denied
After the wire drawdown request was approved, the outgoing wire was rejected.

International Wire Transfer Events


For all International wire events, data in the webhook response will be the International Wire Object at the time the webhook is fired, unless specified otherwise.

swift.outgoing_transfer.initiated
Column has received your request and will submit it to the Swift network very shortly.

swift.outgoing_transfer.manual_review
Column is manually reviewing your request, and will submit it once it is approved.

swift.outgoing_transfer.submitted
Column has submitted your request to the Swift network.

swift.outgoing_transfer.completed
Column has settled the funds to the beneficiary bank or correspondent bank.

swift.outgoing_transfer.returned
Your request has been returned/rejected by the Swift network, correspondent bank, or beneficiary bank.

swift.outgoing_transfer.cancellation_requested
Column has submitted your request to cancel an outgoing transfer to the Swift network.

swift.outgoing_transfer.cancellation_accepted
The beneficiary bank of an outgoing transfer has accepted your cancellation request, and funds will be returned shortly.

swift.outgoing_transfer.cancellation_rejected
The beneficiary bank of an outgoing transfer has rejected your cancellation request, and funds will not be returned.

swift.outgoing_transfer.tracking_updated
Tracking details of an outgoing transfer are updated. data in the webhook response will be the International Tracking Object.

swift.incoming_transfer.initiated
Column has received the incoming transfer message, but not received the funds yet.

swift.incoming_transfer.completed
Column has received the funds for the incoming transfer, and settled it successfully.

swift.incoming_transfer.pending_return
Column has received your return request for the incoming transfer, but not returned the funds yet.

swift.incoming_transfer.returned
Column has successfully returned the funds of the incoming transfer.

swift.incoming_transfer.cancellation_requested
Column has received a cancellation request for an incoming transfer.

swift.incoming_transfer.cancellation_accepted
You have accepted the cancellation request of an incoming transfer by returning it.

swift.incoming_transfer.cancellation_rejected
You have ignored the cancellation request of an incoming transfer without returning it. So Column has rejected the cancellation request on your behalf.

swift.incoming_transfer.tracking_updated
Tracking details of an incoming transfer are updated. data in the webhook response will be the International Tracking Object.

Check Transfer Events


For all Check transfer events, data in the webhook response will be the Check Transfer Object at the time the webhook is fired.

check.incoming_debit.issued
Column has successfully created the check with a unique check number.

check.incoming_debit.settled
The incoming debit has been settled at Column.

check.incoming_debit.pending_first_return
The incoming debit is pending first return to the BOFD which can happen for a variety of reasons.

check.incoming_debit.returned
The incoming debit has been successfully returned.

check.incoming_debit.pending_reclear
The incoming debit is pending reclear.

check.incoming_debit.pending_second_return
The incoming debit is pending a second return.

check.incoming_debit.second_return
The incoming debit has been returned a second time.

check.incoming_debit.user_initiated_return_submitted
The payer initiated return has been submitted to the Fed.

check.incoming_debit.user_initiated_returned
The payer initiated return has been settled.

check.incoming_debit.user_initiated_return_dishonored
The payer initiated return has been dishonored.

check.incoming_debit.pending_stop
The payer has issued a stop payment instruction. Column will hold funds for a period of time.

check.incoming_debit.stopped
Column has released funds held on a stop payment.

check.incoming_debit.manual_review
The issued check is undergoing a manual review which will be approved or rejected by Column. This can be triggered for a variety of reasons.

check.incoming_debit.rejected
The check transfer has been rejected by Column or by the Federal Reserve.

check.incoming_debit.delivery.created
The physical check has been successfully created.

check.incoming_debit.delivery.mailed
The check has been handed off to and accepted by USPS and is en route.

check.incoming_debit.delivery.in_transit
The check is being processed at the entry/origin facility.

check.incoming_debit.delivery.in_local_area
The check is being processed at the destination facility.

check.incoming_debit.delivery.processed_for_delivery
The check has been greenlit for delivery at the recipient's nearest postal facility. The check should reach the mailbox within 1 business day of this tracking event.

check.incoming_debit.delivery.delivered
The check has been delivered to the recipient’s address. The final scan is generated when the mail carrier's GPS unit leaves the delivery area.

check.incoming_debit.delivery.rerouted
The check is re-routed due to recipient change of address, address errors, or USPS relabeling of barcode/ID tag area.

check.incoming_debit.delivery.returned_to_sender
The check is being returned to sender due to barcode, ID tag area, or address errors.

check.incoming_debit.delivery.failed
Physical check delivery failed.

check.outgoing_debit.manual_review
The issued check is undergoing a manual review which will be approved or rejected by Column. This can be triggered for a variety of reasons.

check.outgoing_debit.rejected
The check transfer has been rejected by Column or by the Federal Reserve.

check.outgoing_debit.pending_debit
The check is ready to be sent to the Fed.

check.outgoing_debit.deposited
Column has successfully deposited the check. If the check is not returned after 2 business days, Column moves the check to a settled state.

check.outgoing_debit.settled
The deposited check (outgoing debit) has been settled.

check.outgoing_debit.returned
The deposited check (outgoing debit) has been returned.

check.outgoing_debit.pending_reclear
Column will attempt to reclear a check if returned with return reason A (NSF) or return reason B (UCF - Uncollected Funds Hold).

check.outgoing_debit.recleared
Column has recleared the check. At this point the check will be returned, if the reclear attempt fails, or settled, if the check is recleared successfully.

Identity Verification Events


For all Identity verification events, data in the webhook response will be the Entity Object at the time the webhook is fired.

identity.created
An entity has been created, awaiting identity verification.

identity.verification.pending
Column has submitted the identity information for verification, and is awaiting the result.

identity.verification.manual_review
The identity information is being manually reviewed.

identity.verification.verified
The identity information has been verified successfully.

identity.verification.denied
Column has failed to verify the identity information and denied the service request.

Loan Events


For all Loan events, data in the webhook response will be the Loan Object at the time the webhook is fired.

loan.created
A loan has been created in Column's system.

loan.updated
A loan has been updated in Column's system.

loan.in_dispute
A loan has been updated to in_dispute in Column's system.

loan.delinquent
A loan has been updated to delinquent in Column's system.

loan.paid_off
A loan has been updated to paid_off in Column's system.

loan.charged_off
A loan has been updated to charged_off in Column's system.

loan.canceled
A loan has been canceled in Column's system.

For all Loan disbursement events, data in the webhook response will be the Loan Disbursement Response at the time the webhook is fired.

loan.disbursement.hold_created
A loan disbursement with a hold has been created in Column's system.

loan.disbursement.hold_updated
A loan disbursement with a hold has been updated in Column's system.

loan.disbursement.hold_canceled
A loan disbursement with a hold has been canceled in Column's system.

loan.disbursement.completed
A loan disbursement been successfully completed in Column's system.

For all Loan payment events, data in the webhook response will be the Loan Payment Response at the time the webhook is fired.

loan.payment.completed
A loan payment has been successfully completed in Column's system.

Reporting Events


For all reporting events, data in the webhook response will be the Settlement Report Object at the time the webhook is fired.

reporting.bank_account_summary.scheduled
Successfully scheduled a bank_account_summary settlement report

reporting.bank_account_summary.completed
Successfully generated a bank_account_summary settlement report

reporting.bank_account_summary.failed
Failed to generate a bank_account_summary settlement report

reporting.bank_account_transaction.scheduled
Successfully scheduled a bank_account_transaction settlement report

reporting.bank_account_transaction.completed
Successfully generated a bank_account_transaction settlement report

reporting.bank_account_transaction.failed
Failed to generate a bank_account_transaction settlement report

Overdraft Events


For all overdraft events, data in the webhook response will be the Overdraft Object at the time the webhook is fired.

account.overdrafted
An account has been overdrawn due to an outgoing transfer or an incoming return, and funds have been locked in your reserve accounts.

account.overdraft_released
An account has been credited and locked funds in your reserve accounts have been released.