The person's own card
A cardholder connects one of their own credit or debit cards once, behind a passkey on their phone. The agent pays with it after they approve each purchase there. Nothing is issued, nothing is prepaid, they keep their points.
Connect the card
POST /v1/cards/connect returns a one-hour, single-use link. Send it to the cardholder and never open it yourself. They open it in Safari or Chrome on the phone they will approve purchases with, type the card once, and lock it with a passkey. The card is encrypted on their device before it leaves the page; AgentPay never holds the number in clear and never stores the security code.
curl -X POST https://api.joomjoo.com/v1/cards/connect \
-H "Authorization: Bearer $AGENTPAY_API_KEY"{
"connect_id": "6f1c...",
"connect_url": "https://claim.joomjoo.com/add/6f1c...#...",
"expires_at": "2026-11-03T15:00:00.000Z",
"status": "open",
"instructions": "Send the link to the cardholder. They open it in Safari or Chrome on the phone they will approve purchases with, type the card once, and lock it with a passkey. The security code is never stored. Then GET /v1/cards shows it with source \"own\".",
"request_id": "req_a1b2c3"
}Once connected, GET /v1/cards lists it first, with source: "own".
Pay with it
Pass the card's id as own_card_id on POST /v1/checkout. The run drives the merchant as usual and stops at the review with status needs_card_approval:
approval_urlis the link the cardholder opens on their phone. They see the amount and the merchant, type the security code, and confirm with their passkey.approval_expires_atis when the link stops working.- The same link arrives on the
checkout.needs_card_approvalevent, withamount_displayandcard_last4.
confirm_pay cannot skip this approval. The bank's own check (3-D Secure) on a connected card is not cleared by AgentPay; the cardholder completes it on the agent's screen.
Remove it
DELETE /v1/cards/{id} removes a connected card and withdraws any purchase waiting on it. An issued card is closed with POST /v1/cards/{id}/close instead; the two are never mixed.
Connecting a card is switched on per account. Where it is not, POST /v1/cards/connect answers 503 own_card_unavailable.