K
KiflyDeveloper Docs
Sign up →
Agent Integration

Payment Rails

Kifly supports three payment rails. Card purchases are always human-confirmed — the buyer opens a payment link and completes it themselves. No tool call ever settles a card purchase on its own.

#RailStatusPayerSettlement
1Stripe Payment LinkliveHuman (browser)Stripe-hosted Checkout
2Coinbase CommercebetaHuman (browser)Buyer's choice: USDC on Base or card
3x402 USDC on BasebetaAgent (signed proof)Base mainnet via Coinbase

Rails 2–3 are beta. For new integrations today, use Rail 1.

No autonomous card settlement. Kifly deliberately does not offer a stored-card / reusable-token rail that lets an agent charge a buyer without the buyer confirming. The checkout tool always returns a link the buyer opens themselves.


Rail 1 — Stripe Payment Link (live)

The default rail. The agent handles the entire purchase except the payment step; the buyer pays in Stripe's hosted UI.

Flow

The agent calls checkout (MCP tool) or POST /api/agent/payment-link directly. Kifly creates a Stripe Checkout Session pre-filled with the shipping address and returns:

{
  "session_id": "cs_live_XXXXXXXXXX",
  "payment_url": "https://checkout.stripe.com/c/pay/cs_live_XXXXXXXXXX",
  "amount": 8550,
  "subtotal_cents": 7000,
  "delivery_fee_cents": 1550,
  "currency": "usd",
  "buyer_token_status": "resolved"
}

The agent surfaces the payment_url to the buyer. Stripe's webhook to Kifly marks the order paid; the agent confirms via order_status.

buyer_token_status is "resolved" if a valid buyer_token was passed (email pre-filled in Stripe Checkout), "invalid" if the token was unrecognized (checkout proceeds without pre-fill), or "none" if no token was passed.

Why this is the default

  • No buyer-side setup. No wallet, no Coinbase account.
  • Universal: any agent that can return a URL to a human can use it.

Rail 2 — Coinbase Commerce (beta)

Same shape as Rail 1 but the buyer has a choice at the payment page: pay with USDC on Base (Coinbase Commerce) or pay with card (Stripe). The agent's request is identical to Rail 1; Kifly returns a chooser URL when the seller has Coinbase Commerce enabled.

{
  "session_id": "kpc_XXXXXXXXXX",
  "payment_url": "https://kifly.ai/pay/kpc_XXXXXXXXXX",
  "amount": 8550,
  "currency": "usd",
  "methods": ["usdc-on-base", "card-via-stripe"]
}

Beta: sellers can opt in by emailing hello@kifly.ai.


Rail 3 — x402 USDC on Base (beta)

The x402 protocol extends HTTP 402 for on-chain payments. Agents whose buyer authorizes an on-chain payment submit a signed USDC proof; there is no stored-credential card path.

Reading the cart total returns a 402 challenge; for x402-enabled sellers it also carries an X-Payment-Required header advertising the USDC option:

POST /api/agent/cart/{cart_id}/checkout
Authorization: Bearer kfa_live_xxxxxxxxxxxxxxxx
Idempotency-Key: <uuid>
HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment realm="kifly"
X-Payment-Required: {"network":"base","currency":"USDC","amount":"49.99","address":"0x…"}

Agents that support x402 re-request with a signed payment proof:

POST /api/agent/cart/{cart_id}/checkout
X-Payment: <signed-usdc-proof>

The proof is verified by the Coinbase x402 facilitator and broadcast to Base mainnet.

Beta: use Rail 1 unless you have arranged x402 access with us. X-Payment on an endpoint where it is not enabled returns x402_not_configured.


Header detection

Header presentBehaviour
X-Payment: <proof>x402 (USDC on Base) settlement
Authorization: Bearer <key> only402 challenge — reads the cart total; never settles a card. Use /api/agent/payment-link for the Rail 1 payment link.

An Authorization: Payment <token> credential is not accepted for settlement — Kifly has no stored-card / reusable-token rail. Presenting one simply re-issues the 402 challenge.


Idempotency

All mutating agent endpoints require an Idempotency-Key header of 16-64 characters — a UUID is the easy choice. Repeating a request with the same key returns the original response, so it is safe to retry on network errors.

A key outside that length window is refused with IDEMPOTENCY_KEY_INVALID (not IDEMPOTENCY_KEY_REQUIRED), and the refusal carries details.min_length, details.max_length and details.received_length so you can correct it without guessing.

Idempotency-Key: <a-uuid-you-generate-per-request>

Always reuse the same key when retrying the same logical operation.

Payment Rails: Kifly Docs