pending, an on-chain transfer is detected, and the status moves to confirmed, partial, or excess depending on the amount received. This page walks through each stage in detail, explains how the detection mechanism works, and covers the separate lifecycle that invoices follow.
Payment link lifecycle
The full lifecycle of a payment link, from creation to final state:A link in
partial status remains open. If the payer sends additional USDC to the same deposit address, the accumulated total is re-evaluated and the status updates accordingly.Status definitions
pending — awaiting first transfer
pending — awaiting first transfer
The payment link has been created and the deposit address is registered with Alchemy. Kibble is watching for any USDC transfer to that address on Base. No funds have been received yet.
confirmed — exact amount received
confirmed — exact amount received
The cumulative USDC received equals the expected amount. The payment is complete. No further action is required.
partial — underpaid
partial — underpaid
The amount received is less than the expected amount. The link stays open and Kibble continues monitoring the deposit address. If more USDC arrives later, the status is recalculated.
excess — overpaid
excess — overpaid
The amount received exceeds the expected amount. The merchant can see the overpaid amount in the portal and via webhook. Kibble does not automatically refund the difference — handling the excess is up to you and your payer.
How on-chain detection works
When you create a payment link or invoice, Kibble:- Resolves or provisions a deposit address (see Wallets).
- Registers that address with Alchemy’s Address Activity webhook via a
PUTrequest to the Alchemy dashboard API.
Token verification
Kibble confirms that the received token is USDC on Base (
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913). Transfers of any other token are silently ignored.Amount classification
Kibble compares the received value to the
expected_amount set on the payment link:- Equal →
confirmed - Less than →
partial - Greater than →
excess
Invoice lifecycle
Invoices have a separate but related lifecycle. An invoice is backed by a payment link, and its status updates when the underlying payment link receives funds.Invoice status definitions
| Status | Meaning |
|---|---|
draft | Invoice created. Not yet emailed to the vendor. |
sent | Invoice emailed to the vendor. Awaiting payment. |
paid | Received amount matches the invoice total exactly. |
partial | Received amount is less than the invoice total. |
excess | Received amount exceeds the invoice total. |
confirmed, Kibble maps that to the invoice status paid. The partial and excess statuses map directly.
What happens when an invoice is paid
When the deposit address for an invoice receives a USDC transfer, Kibble:- Updates the invoice status (
paid,partial, orexcess) and records apaid_attimestamp. - Sends a payment confirmation email to the merchant with the invoice number, amount, and transaction hash.
- If you registered a
webhook_url, POSTs a signed JSON payload to your server:
sha256={hex} in the X-Kibble-Signature header using the webhook_secret returned at invoice creation time. See Webhooks for verification details.
Edge cases
Multiple transfers to the same address
Multiple transfers to the same address
If a payer sends USDC in multiple separate transactions, each one triggers the webhook. Kibble recalculates the total received against the expected amount on each event. A link moves from
partial to confirmed (or excess) as soon as the cumulative total meets or exceeds the expected amount.Transfer arrives before the link is registered
Transfer arrives before the link is registered
Alchemy address registration is a non-blocking async call. In the rare case that a transfer arrives before registration completes, the webhook will not fire for that transaction. This race condition is unlikely in practice but worth being aware of.
Duplicate payment detection
Duplicate payment detection
If the same on-chain transfer is detected more than once, Kibble deduplicates it automatically using the transaction hash. You will not see duplicate status changes for the same transaction.
Wrong token or wrong chain
Wrong token or wrong chain
Kibble silently ignores any transfer where the token contract does not match
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913. This includes ETH transfers, other ERC-20 tokens, and USDC on other chains such as Ethereum mainnet or Polygon.