Skip to main content

Payment Flow

What You’ll LearnThis guide covers:
  • The complete payment lifecycle (Fund → Card → Spend → Settle)
  • Card credential access and attestation
  • Intent declaration flow for controlled spending
  • Transaction states and webhook events
  • Common scenarios and timing considerations
Time to read: 15 minutes
This guide walks through the complete payment flow in LedgerOS, from initial funding to transaction settlement.

Overview

The LedgerOS payment system follows a secure flow:

Phase 1: Setup

User Onboarding

Before any spending can happen, you need a verified, funded user:
1

Create User

curl -X POST https://api.ledger.so/v1/users \
  -H "Api-Key: lk_live_xxx" \
  -d '{"firstName": "John", "lastName": "Doe", "email": "[email protected]"}'
Returns: user_id
2

Initiate KYC

curl -X POST https://api.ledger.so/v1/verification/user \
  -H "Api-Key: lk_live_xxx" \
  -d '{"userId": "user_xxx"}'
Returns: verificationUrl - send this to your user
3

User Completes KYC

User visits the verification URL and completes identity verification. You receive webhook: user.approved when complete.
4

User Deposits Funds

curl https://api.ledger.so/v1/users/user_xxx/funding \
  -H "Api-Key: lk_live_xxx"
Returns deposit addresses for USDC/USDT. User sends crypto. You receive webhook: deposit.completed when funds are credited.

Agent Creation

Once a user is funded, register agents:
curl -X POST https://api.ledger.so/v1/agents/register \
  -H "Api-Key: lk_live_xxx" \
  -d '{
    "userId": "user_xxx",
    "name": "checkout-bot",
    "description": "Handles online purchases",
    "spendingLimit": 50000,
    "spendingLimitFrequency": "perMonth"
  }'
Returns agent_id and optionally an agent_token for agent-scoped API access.

Phase 2: Purchase Flow

Card Creation

Create a card for the specific purchase:
curl -X POST https://api.ledger.so/v1/agents/agent_xxx/cards \
  -H "Api-Key: lk_live_xxx" \
  -d '{
    "purpose": "Purchase wireless headphones from Amazon",
    "type": "single",
    "maxAmount": 15000
  }'
ParameterDescription
purposeHuman-readable description (for audit)
typesingle (one transaction) or multi (reusable with limits)
maxAmountMaximum spend in cents

Intent Declaration

Before accessing card credentials, agents must declare their spending intent:
curl -X POST https://api.ledger.so/v1/cards/card_xxx/intents \
  -H "Api-Key: lk_live_xxx" \
  -d '{
    "summary": "Buy Sony WH-1000XM5 headphones",
    "amount": 34999,
    "merchantText": "Amazon"
  }'
Intent ExpirationIntents expire after 1 hour if no card details are accessed. After accessing card details, the intent is valid for 24 hours waiting for a matching transaction.

Card Detail Access (Attestation)

When your agent needs the actual card credentials:
curl -X POST https://api.ledger.so/v1/cards/card_xxx/details \
  -H "Api-Key: lk_live_xxx" \
  -d '{
    "summary": "Buy Sony WH-1000XM5 headphones",
    "expectedAmount": 34999,
    "merchantText": "Amazon"
  }'
Response:
{
  "accessEventId": "evt_abc123",
  "pan": "4111111111111111",
  "cvv": "123",
  "expirationMonth": "12",
  "expirationYear": "2026",
  "last4": "1111"
}
Attestation Creates Audit TrailThe accessEventId links this credential access to your stated intent. When a transaction occurs, LedgerOS correlates it with the attestation to detect anomalies.

Transaction Authorization

When the agent uses the card at a merchant:

Phase 3: Settlement

Transaction States

StateDescriptionTiming
pendingAuthorization approved, funds heldImmediate
settledMerchant captured, funds transferred1-3 business days
voidedMerchant cancelled before settlementVaries
refundedMerchant refunded after settlementVaries

Webhooks

You’ll receive webhooks for each state change:
EventWhen
transaction.createdAuthorization approved
transaction.settledFunds captured
transaction.voidedAuthorization reversed
transaction.refundedRefund processed
transaction.declinedAuthorization denied

Intent Matching

When a transaction occurs, LedgerOS matches it against the declared intent: Intent states after transaction:
StateMeaning
matchedTransaction matches declared intent
mismatchedAmount or merchant differs significantly
expiredNo transaction within 24 hours

Card Lifecycle

Single-Use Cards

Single-use cards automatically close after one successful transaction settles.

Multi-Use Cards

Multi-use cards remain open for repeat purchases until manually closed or limits are exceeded.

Timing Considerations

StageTypical Timing
KYC approval1-5 minutes (automated)
Crypto deposit credit2-5 minutes
Card creationInstant
Authorization< 2 seconds
Settlement1-3 business days
Balance vs AvailableAfter authorization, funds are held but not yet settled. The user’s “available” balance decreases immediately, but “settled” balance changes only after settlement.

Troubleshooting

Cause: No intent was declared for this card.Solution: Call POST /v1/cards/{id}/intents before requesting details. All cards require intent declaration.
Cause: User’s available balance is less than the transaction amount.Solution: Check balance with GET /v1/balances/{userId}. User needs to deposit more funds.
Cause: Transaction exceeds card’s per-transaction, daily, or monthly limit.Solution: Check card limits with GET /v1/cards/{cardId}. Either increase limits or create a new card.
Cause: Transaction amount or merchant differs significantly from declared intent.Solution: This is informational—the transaction still completes. Review the mismatch for potential issues. Consider adjusting intent parameters for future purchases.
Cause: Webhook endpoint unreachable or returned error.Solution: Check webhook logs in dashboard. Verify endpoint is accessible and returns 2xx. LedgerOS retries failed webhooks with exponential backoff.

Next Steps