Reserve APIs#
Retrieve reserve balances and recommended reserve settings for your subscription.
Overview#
- Base URL: markup
https://api.pay.ledger1.ai/portalpay - Authentication (Developer APIs): All requests require an Azure APIM subscription key header:
- markup
Ocp-Apim-Subscription-Key: {your-subscription-key}
- Gateway posture: APIM custom domain is the primary endpoint. Azure Front Door (AFD) may be configured as an optional/fallback edge; if enabled, APIM accepts an internal markupper policy.
x-edge-secret - Rate limiting headers (if enabled): markup,
X-RateLimit-Limitmarkup,X-RateLimit-RemainingmarkupX-RateLimit-Reset - Identity: Wallet identity is resolved automatically at the gateway based on your subscription; client requests must not include wallet identity headers.
../auth.md../../public/openapi.yamlGET /portalpay/api/reserve/balances#
Return current reserve balances, by currency, for the merchant associated with your subscription.
Request#
Headers:
markupOcp-Apim-Subscription-Key: {your-subscription-key}
Example Requests:
curl -X GET "https://api.pay.ledger1.ai/portalpay/api/reserve/balances" \
-H "Ocp-Apim-Subscription-Key: $APIM_SUBSCRIPTION_KEY"GET/portalpay/api/reserve/balancesTry It: Reserve Balances
Fetch current reserve balances by currency.
Default is the APIM custom domain. For AFD, enter only the AFD endpoint host (e.g., https://afd-endpoint-pay-...) without any path; the /portalpay prefix is added automatically for /api/* and /healthz.
The key is kept only in memory while this page is open. Do not paste secrets on shared machines.
For public reads (GET /api/inventory, GET /api/shop/config), include the merchant wallet (0x-prefixed 40-hex). Non-GET requests should use JWT and will ignore this header.
Using server-side proxy to avoid CORS. Requests go through /api/tryit-proxy to AFD/APIM.cURLcurl -X GET "https://api.pay.ledger1.ai/portalpay/api/reserve/balances"Response Status—Response Headers—Response Body—
Response#
Success (200 OK):
json{ "balances": [ { "currency": "USDC", "reserved": 100.00, "target": 150.00 }, { "currency": "ETH", "reserved": 0.025, "target": 0.050 } ], "updatedAt": 1698765432000 }
Notes:
- markupis the currently held amount.
reserved - markupis the recommended or configured target amount (if available).
target
Response Headers (when enabled at gateway):
- markup
X-RateLimit-Limit - markup
X-RateLimit-Remaining - markup
X-RateLimit-Reset
POST /portalpay/api/reserve/recommend (Admin – JWT)#
Update reserve recommendation settings (e.g., jurisdictions or strategy inputs) via the PortalPay admin UI. This operation is not callable via a developer APIM key.
Request#
Headers:
markupContent-Type: application/json Cookie: cb_auth_token=...
Body (JSON) example (deployment-dependent):
json{ "taxConfig": { "jurisdictions": ["US-CA"], "provider": "ava" }, "defaultJurisdictionCode": "US-CA" }
Response#
Success (200 OK):
json{ "ok": true }
Other responses:
- 400: markup
invalid_input - 403: markup
forbidden - 429: markup
rate_limited - 500: markup
failed
Notes:
- Client-provided wallet headers are ignored; the authenticated admin wallet is used.
- CSRF protections apply for browser-based writes.
GET /portalpay/api/reserve/recommend#
Return recommended reserve targets by currency based on recent activity and configuration.
Request#
Headers:
markupOcp-Apim-Subscription-Key: {your-subscription-key}
Example Requests:
curl -X GET "https://api.pay.ledger1.ai/portalpay/api/reserve/recommend" \
-H "Ocp-Apim-Subscription-Key: $APIM_SUBSCRIPTION_KEY"GET/portalpay/api/reserve/recommendTry It: Reserve Recommendations
Fetch recommended reserve targets by currency.
Default is the APIM custom domain. For AFD, enter only the AFD endpoint host (e.g., https://afd-endpoint-pay-...) without any path; the /portalpay prefix is added automatically for /api/* and /healthz.
The key is kept only in memory while this page is open. Do not paste secrets on shared machines.
For public reads (GET /api/inventory, GET /api/shop/config), include the merchant wallet (0x-prefixed 40-hex). Non-GET requests should use JWT and will ignore this header.
Using server-side proxy to avoid CORS. Requests go through /api/tryit-proxy to AFD/APIM.cURLcurl -X GET "https://api.pay.ledger1.ai/portalpay/api/reserve/recommend"Response Status—Response Headers—Response Body—
Response#
Success (200 OK):
json{ "recommendations": [ { "currency": "USDC", "target": 200.00, "basis": "30d_median_payouts" }, { "currency": "ETH", "target": 0.075, "basis": "fees_buffer" } ], "windowDays": 30, "updatedAt": 1698765432000 }
Notes:
- markupindicates the heuristic used (deployment-dependent).
basis - Use these values to adjust reserve levels for smoothing payouts and covering fees.
Response Headers (when enabled at gateway):
- markup
X-RateLimit-Limit - markup
X-RateLimit-Remaining - markup
X-RateLimit-Reset
Error Responses#
401 Unauthorized
json{ "error": "unauthorized", "message": "Missing or invalid subscription key" }
403 Forbidden
json{ "error": "forbidden", "message": "Insufficient privileges or origin enforcement failed" }
429 Too Many Requests
json{ "error": "rate_limited", "resetAt": 1698765432000 }
500 Internal Server Error
json{ "error": "failed", "message": "Unable to retrieve reserve data" }
Code Examples#
JavaScript/TypeScript#
typescriptconst APIM_SUBSCRIPTION_KEY = process.env.APIM_SUBSCRIPTION_KEY!; const BASE_URL = 'https://api.pay.ledger1.ai/portalpay'; export async function getReserveBalances() { const res = await fetch(`${BASE_URL}/api/reserve/balances`, { headers: { 'Ocp-Apim-Subscription-Key': APIM_SUBSCRIPTION_KEY } }); if (!res.ok) throw new Error(`reserve_balances_failed_${res.status}`); return res.json() as Promise<{ balances: { currency: string; reserved: number; target?: number }[]; updatedAt?: number; }>; } export async function getReserveRecommendations() { const res = await fetch(`${BASE_URL}/api/reserve/recommend`, { headers: { 'Ocp-Apim-Subscription-Key': APIM_SUBSCRIPTION_KEY } }); if (!res.ok) throw new Error(`reserve_recommend_failed_${res.status}`); return res.json() as Promise<{ recommendations: { currency: string; target: number; basis?: string }[]; windowDays?: number; updatedAt?: number; }>; }
Python#
pythonimport os, requests APIM_SUBSCRIPTION_KEY = os.environ['APIM_SUBSCRIPTION_KEY'] BASE_URL = 'https://api.pay.ledger1.ai/portalpay' def get_reserve_balances(): r = requests.get( f'{BASE_URL}/api/reserve/balances', headers={'Ocp-Apim-Subscription-Key': APIM_SUBSCRIPTION_KEY} ) r.raise_for_status() return r.json() def get_reserve_recommendations(): r = requests.get( f'{BASE_URL}/api/reserve/recommend', headers={'Ocp-Apim-Subscription-Key': APIM_SUBSCRIPTION_KEY} ) r.raise_for_status() return r.json()
Notes on Auth Models#
- Developer reads must use markup. Wallet identity is resolved automatically at the gateway based on your subscription; the backend trusts the resolved identity.
Ocp-Apim-Subscription-Key - Admin/UI writes (e.g., POST markup) require JWT cookies (
/portalpay/api/reserve/recommendmarkup) with CSRF and role checks; any client-supplied wallet headers are ignored on writes.cb_auth_token - Client requests do not include wallet identity for developer APIs; it is resolved at the gateway per subscription.
