sdk.settlement
Create payments, validate receipts, and manage budgets. All payment flows are non-custodial — the SDK never holds funds.
Create a Payment Intent
const cap = await sdk.developer.capability.request('settlement:intent:create', 'myapp.gao', 300)
const intent = await sdk.settlement.createIntent({
amount: '25.00', // decimal string
currency: 'USDC', // USDC | USDT | GAO | USD
recipient: 'merchant.gao', // recipient's Gao Domain
description?: 'Booking deposit',
idempotency_key: crypto.randomUUID(), // REQUIRED — prevents duplicate charges
capability: cap.token,
})
interface PaymentIntent {
intent_id: string
domain: string
amount: string
currency: string
recipient: string
status: 'pending' | 'confirmed' | 'failed'
receipt: PaymentReceipt
created_at: string
}
Always pass a unique **idempotency_key**. Reusing the same key for different payments triggers GAO-4006.
Validate Receipt
Always validate before fulfilling. A receipt is proof of payment — invalid receipt means do not proceed.
const valid = await sdk.settlement.validateReceipt(intent.receipt)
if (!valid) {
throw new Error('Invalid receipt — do not fulfill order')
}
// Safe to fulfill
await fulfillOrder(intent.intent_id)
---
### Watch Finality
For on-chain settlement, wait for finality confirmation before releasing goods or services.
const finality = await sdk.settlement.watchFinality(intent.intent_id)
switch (finality.status) {
case 'confirmed':
await releaseOrder()
break
case 'failed':
await refundUser()
break
// 'pending' = still confirming, poll again
}
`watchFinality()` polls until a terminal state (`confirmed` or `failed`) or timeout (default 5 minutes).
---
### Get Receipt
const receipt = await sdk.settlement.getReceipt(intentId)
interface PaymentReceipt {
receipt_id: string
intent_id: string
domain: string
amount: string
currency: string
recipient: string
status: string
signature: string // domain-signed — cryptographically verifiable
timestamp: string // ISO8601
finality_hash?: string // present after on-chain confirmation
immutable: true
}
Receipts are **immutable** — never modified after creation.
---
### Budget Management
// Get current budget status for a domain
const budget = await sdk.settlement.budget.get('myapp.gao')
// budget.limit — total budget cap
// budget.used — amount spent
// budget.remaining — available
// budget.currency — "USDC"
// Check if a payment amount is within budget
const canPay = await sdk.settlement.budget.check('myapp.gao', '25.00')
// → true | false
x402 Sub-Module
For HTTP 402 payment-required flows (API billing, metered services):
// Create payment proof for an x402 challenge
const proof = await sdk.settlement.x402.createProof(
'0.01', // amount
'USDC', // currency
'api.gao' // recipient
)
// Attach as HTTP header
headers['X-Payment'] = proof
// On server: verify incoming proof
const valid = await sdk.settlement.x402.verifyProof(incomingProof)
---
### React Hook
import { usePayment } from '@gao/system-sdk/react'
function CheckoutButton({ amount, recipient, orderId }: Props) {
const { createIntent, receipt, status, error } = usePayment(sdk)
const handlePay = () => createIntent({
amount,
currency: 'USDC',
recipient,
idempotency_key: orderId,
capability: 'settlement:intent:create',
})
return (
<div>
{status === 'idle' && <button onClick={handlePay}>Pay {amount} USDC</button>}
{status === 'pending' && <span>Processing...</span>}
{status === 'confirmed' && <span>✓ Payment confirmed</span>}
{error && <span>Error: {error.message}</span>}
</div>
)
}
Non-Custodial Rules
The SDK never:
-
Stores private keys or wallet credentials
-
Pools or holds funds between transactions
-
Modifies receipts after generation
-
Executes unsigned transactions
All payment actions require explicit user authorization via capability token.