Skip to main content
Webhooks are the primary way that Nickel tells your application that something has happened. To receive the event notifications documented on this page, create a webhook subscription programmatically via the POST /webhook endpoint. Once you specify a webhook URL, Nickel sends an HTTP POST request to that URL whenever something happens against your Nickel account.
Your account has a single API webhook subscription: creating a webhook replaces the API webhook already registered on your account, if any. A legacy payment-alert webhook configured from the dashboard settings page is separate and is left in place. To receive the events documented here, create your webhook via POST /webhook.

Webhook structure

Every event is delivered as a JSON body with the same envelope:

Delivery and retries

Nickel sends each event as a POST request with Content-Type: application/json and Nickel-Signature headers. Respond with any 2xx status code to acknowledge receipt. If your endpoint responds with a non-2xx status code or is unreachable, Nickel retries the delivery with exponential backoff (roughly 3s, 6s, 12s, and 24s between attempts) for up to 5 total attempts. Deliveries can occasionally arrive more than once or out of order, so make your handler idempotent. A repeated delivery of an event keeps its id, so skip an id you’ve already processed. Distinct events always have distinct ids, even for the same object: a payment refunded in two parts sends two payment.refunded events, and deduplicating by id keeps both. The signature is computed per attempt, so the t timestamp in the Nickel-Signature header reflects when that attempt was sent.

Verifying signatures

The response to POST /webhook includes a secret — a whsec_-prefixed string that Nickel uses to sign every delivery to that webhook. Store it alongside your API key; you can also retrieve it later with GET /webhook. Each delivery carries a Nickel-Signature header:
  • t is the unix timestamp (in seconds) of the delivery attempt.
  • v1 is the hex-encoded HMAC-SHA256 of the string {t}.{raw request body}, keyed with your webhook secret.
To verify a delivery:
  1. Split the header into t and v1.
  2. Compute HMAC-SHA256 over {t}.{body} with your secret, using the raw request body bytes — don’t parse and re-serialize the JSON first, since any formatting difference changes the digest.
  3. Compare your digest to v1 with a constant-time comparison.
  4. Reject deliveries whose t is too far from your current time (5 minutes is a reasonable tolerance) to guard against replayed requests.
Most web frameworks parse JSON bodies before your handler runs, so you’ll need the raw body captured separately — for example express.json({ verify: (req, _res, buf) => { req.rawBody = buf.toString() } }) in Express.
Webhooks created before signing shipped have no secret (GET /webhook returns "secret": null) and their deliveries are unsigned. Recreate the webhook with POST /webhook to get a secret — the new subscription replaces the old API webhook at the same or a new URL.
As defense in depth, treat the webhook purely as a trigger: fetch the associated object from the API (see Consuming Events) and act on that response rather than on the delivery payload itself.

Categories

Nickel currently supports the following webhook notifications. Each entry says what changed and what your application should do about it — always by fetching the associated object, not by acting on the event alone.

payment.made

A customer paid an invoice. Fetch the payment before recording anything: for a card payment it will show SUCCEEDED, but for a bank (ACH) payment this event fires when the debit is initiated, so the payment will still be PENDING — don’t treat the money as final yet. payment.succeeded follows when it is.

payment.succeeded

A customer’s payment completed. Fetch the payment: it now shows SUCCEEDED. For a card payment this arrives together with payment.made. For a bank (ACH) payment it arrives when the debit settles, usually a few business days after payment.made. Listen for it instead of polling a PENDING payment for its status to change. SUCCEEDED is not irreversible: the customer’s bank can still return an ACH debit for up to 60 days, which sends payment.failed, and a customer can dispute a card payment, which sends payment.disputed. To follow the money into your own account, use the disbursement.* events.

payment.failed

A payment failed — most often the customer’s bank returned an ACH debit, which can happen up to 60 days after payment.made. Fetch the payment and reverse whatever you recorded when it was made; the funds will not arrive (or will be clawed back if already paid out).

payment.refunded

You refunded a settled payment. Fetch the payment and read refunds[] for the amount. A fully refunded payment reopens its invoice to ACTIVE, so the customer can pay again — delete the invoice if you don’t want that.

payment.voided

A refund was requested before the charge settled, so Nickel cancelled the original charge outright — no money ever moved and no processing fee applies. The fetched payment shows refunds[].voided: true.

payment.disputed

Your customer disputed a card payment with their card issuer. This is a chargeback: the money goes back to the customer while the dispute is decided. Fetch the payment: it now shows FAILED, and the invoice it paid reopens to ACTIVE. Treat the money as not yours. Reverse whatever you recorded when the payment was made — the funds will not arrive, or will be clawed back if already paid out. If the dispute is a mistake, ask your customer to pay the invoice again; for questions about the dispute, contact support@nickel.com. If the dispute is decided in your favor, payment.dispute_won follows. If it’s decided against you, nothing more is sent: the payment stays FAILED.

payment.dispute_won

A disputed card payment was decided in your favor, and the money is yours again. Fetch the payment: it shows SUCCEEDED again, and the invoice it paid counts the payment again. Re-record the payment you reversed on payment.disputed. If your customer paid the invoice again while the dispute was open, both payments now count toward the invoice — check it, and refund the extra payment if you don’t mean to keep it. Nickel restores the payment automatically only when nothing else, such as a refund, has changed it since the dispute opened. When it can’t, this event isn’t sent and the payment stays FAILED.

disbursement.pending

Nickel has batched settled payments into a disbursement headed for your bank account. Fetch the disbursement for the total and the paymentIds it contains — this is the moment to start reconciling against your bank statement.

disbursement.succeeded

The receiving bank accepted the disbursement. Depending on your bank’s turnaround it may not appear in your account balance yet — match it to the deposit when it does.

charge_authorization.authorized

Your customer authorized you to charge a payment method they put on file. Fetch the charge authorization and confirm active: true — you can now charge their open invoices against it.

charge_authorization.deleted

An authorization was revoked: by the customer, by you, or by Nickel when the customer’s bank returned a debit because the account can’t be debited at all (for example, it’s closed or the account number is invalid). A returned account can’t be charged again, so the customer has to put a new payment method on file. Stop charging it: check active on the fetched authorization before every charge rather than caching yesterday’s answer.

bill_payment.succeeded

Your vendor received the funds. The bill it paid now counts as Paid — safe to record in your books.

bill_payment.failed

A bill payment failed — for example, the debit from your funding source was returned. The bill is still owed; fix the funding source or delivery method and pay it again.

bill_payment.cancelled

A bill payment was cancelled before it went out to the payment network. Note that the fetched payment reports status: "FAILED" — this event is how you tell a cancellation apart from a genuine failure.

check.sent

Nickel mailed the check to the vendor. Check events carry the bill payment’s ID — fetch it with GET /billPayment/{billPaymentId}.

check.delivered

The check arrived at the vendor’s mailing address. Nothing to do — the vendor still needs to deposit it.

check.deposited

The vendor deposited the check. The bill payment completes from here.

check.returned

The check came back undeliverable. Confirm the vendor’s mailing address (their check delivery method) and pay the bill again.

check.failed

The check payment failed. Fetch the bill payment for its state, then retry with a corrected delivery method.

check_deposit.deposited

A check you deposited into Nickel Banking settled, and the money is yours to spend. The check.* events above are about checks Nickel mails to your vendors; check_deposit.* events are about checks you deposit. Fetch the deposit with GET /nickelBanking/checkDeposits/{checkDepositId}: its status is DEPOSITED and depositedAt says when it settled. The bank can still reverse a deposited check, sometimes days later. That arrives as check_deposit.returned.

check_deposit.rejected

The bank refused a check you deposited, so it never funded: for example, it couldn’t read the photos, or the payee doesn’t match the account. Fetch the deposit for rejectionReason, then deposit the check again or ask your customer for a new one. Nickel voids the deposit’s applications, which reopens the invoices it paid. The void can land a moment after this event, so an application may briefly still read voided: false. Once voided, its voidReason is DEPOSIT_REJECTED.

check_deposit.returned

The bank reversed a check after crediting it, for example because the payer’s account didn’t have the funds or they stopped payment, and the amount has left your account again. Fetch the deposit for returnReason, and reverse whatever you recorded when it was deposited. As with a rejection, Nickel voids the deposit’s applications and the invoices reopen, with voidReason DEPOSIT_RETURNED.
The event is sent to your organization’s webhook whoever registered it, but fetching a check deposit needs a key whose team member can see Nickel Banking deposits. Without that permission the fetch answers 403 and says which permission is missing.

vendor.payout_method_updated

A vendor’s delivery method was created or changed — through the onboarding form or by you. Refetch the vendor and use the current vendorDeliveryMethods[].id when paying; a cached ID may now point at stale details.

Consuming events

Individual events don’t contain very much information on their own. This is by design, as the API structure can remain extremely stable and avoid difficult webhook migrations in the future as the Nickel API changes. If you need additional metadata, such as the amount of the disbursement in the envelope example above, make a GET request to the API for that information. You can use the associated_object_type or category fields to determine what resource to fetch from the API.

See it in practice

Receive webhooks

Register an endpoint, build a reliable receiver, and test the loop in the sandbox.