Webhooks are events that enable you to monitor your account, including all objects such as orders, charges, sessions, etc.

You may either poll the API or receive webhooks at a specific URL.

Available Webhook Events

Session Events

EventDescription
session.createdTriggered when a session is created.
session.consumer_connectedTriggered when a consumer is connected to a session.
session.fi_account_connectedTriggered when a Financial Institution Account is connected to a session by the consumer.
session.authorizedTriggered when a session is successfully authorized by the consumer.
session.authorize_failedTriggered when a session authorization failed.
session.finalizedTriggered when an authorized session is converted into an order.

Order Events

EventDescription
order.createdTriggered when an order is created.
order.total_finalizedTriggered when there are changes to an order's amount before it can be charged.

NOTE: This event is always triggered even if there are no changes to the order total.
order.canceledTriggered when an order is canceled.
order.chargedTriggered when an order is charged/captured.

Charge Events

EventDescription
charge.createdTriggered when a charge is created.
charge.succeededTriggered when a charge is successful.
charge.failedTriggered when a charge attempt has failed.

NOTE: For ACH transactions, a charge can trigger a charge.succeeded event before it triggers a charge.failed event due to an ACH return
charge.retriedTriggered when a charge attempt is retried.

Refund Events

EventDescription
refund.createdTriggered when a refund is initiated.
refund.succeededTriggered when a refund is successful.
refund.failedTriggered when a refund has failed.

NOTE: For ACH transactions, a refund can trigger a refund.succeeded event before it triggers a refund.failed event due to an ACH return

Some API requests may cause multiple events to be created. For example, if you create a new order from a session, you will receive both an order.created event and a session.finalized event with respective payloads.

The data field of the event payload contains a snapshot of the state of corresponding API resource at the time of event creation.

For example a session.xx event will contain Session object in the data field and a charge.xx event will contain a Charge object.

Example Event Payload

{
  "event_id": "evt_RViwQ325voW3P4RXW4N8fv",
  "event_created": "2021-11-30T15:27:54.630965+00:00",
  "event_name": "session.created",
  "version": "v1",
  "data": {
    "id": "sess_FmEXSJ3pqsbXQqJFd7bySK",
    "create_date": "2021-11-30T15:27:54.627835+00:00",
    "status": "started",
    "organization_id": "org_mz8VKmRT5WJ78HJZKnvbK5",
    "type": "consumer_checkout",
    "total_amount": 1000,
    "is_valid_consumer": false,
    "is_valid_bank_account_selected": false,
    "is_sufficient_funds": false,
    "consent_text": "I authorize Swifter to debit my bank account and save my authorization for future use with Swifter.",
    "fees": 100,
    "track_number": "pv96xa"
  }
}

Verifying signatures

When a new webhook subscription is created a unique secret key called signing_secret is also created for it.

All events sent to the target endpoint is signed using the signing_secret with its corresponding signing_secret and provides you with X-Swifter-Signature and X-Swifter-Nonce to verify the authenticity of the payload

Example header

X-Swifter-Nonce	    1638286074697
X-Swifter-Signature	1b5674fd304e77c8ce92fcf59d2ad1e587b60c5656f033296e52e88e33c805f3

Swifter generates signatures using HMAC with SHA-256 hash function.

Steps to Verify Signature

  • Prepare the signed_payload by concatenating the value of header X-Swifter-Nonce , . and the request body
  • Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing_secret as the key, and use the signed_payload string as the message.
  • Compare the created signature to the value of X-Swifter-Signature from the request headers

Example Code to compute HMAC signature

key                = signing_secret
nonce              = headers['X-Swifter-Nonce']
separator          = '.'
signed_payload     = nonce + separator + raw_body
expected_signature = headers['X-Swifter-Signature']

computed_signature = hmac('sha256', signed_payload, key)

if computed_signature != expected_signature
    throw SecurityError
end
import hashlib
import hmac

signing_secret = "super_secret_key".encode("utf-8")

body = "{...}"
nonce = "1638286074697"
separator = "."

signed_payload = f"{nonce}{separator}{body}"

# encode the payload to utf-8 bytes
signed_payload = signed_payload.encode("utf-8")

# now use the hmac.new function and the hexdigest method
computed_signature = hmac.new(signing_secret, signed_payload, hashlib.sha256).hexdigest()

# check if computed_signature equals the `X-Swifter-Signature` from request header
if computed_signature != expected_signature

Idempotency

There could be scenarios where your webhook endpoint might receive the same event multiple times. This is an expected behaviour.

You can identify duplicate events using event_id field in the event payload. The event_id field contains an identifier which is unique per event.