API Reference#
PortalPay’s developer-facing APIs are fronted by Azure API Management (APIM) on a custom domain. All external integrations must call the APIM gateway and authenticate with an APIM subscription key. Wallet identity is resolved at the gateway based on your subscription and propagated to the backend; clients MUST NOT send wallet identity headers.
Admin-only operations in the PortalPay web app use JWT cookies (
markup
) with CSRF protections and role checks.cb_auth_token- Base URL: markup
https://api.pay.ledger1.ai/portalpay - Developer Authentication: markup
Ocp-Apim-Subscription-Key: {your-subscription-key} - Identity: Wallet is resolved by APIM from your subscription and propagated to the backend; clients do not manage wallet identity
- Admin/UI Authentication: JWT cookie (markup) in PortalPay; used for sensitive write operations
cb_auth_token - Health: markupis open and does not require a subscription key
GET /portalpay/healthz
See Authentication & Security:
markup
../auth.mdQuick Start#
- Obtain your APIM subscription key (PortalPay Admin → API Subscriptions or directly in APIM)
- Set the header in every developer API request (except healthz):
markup
Ocp-Apim-Subscription-Key: {your-subscription-key} - Wallet identity is resolved automatically at the gateway based on your subscription; no wallet fields are accepted in requests.
Example:
bashcurl -X GET "https://api.pay.ledger1.ai/portalpay/api/inventory" \ -H "Ocp-Apim-Subscription-Key: $APIM_SUBSCRIPTION_KEY"
Gateway and Optional Edge#
APIM custom domain is the primary client endpoint. Azure Front Door (AFD) may be configured as an optional/fallback edge. If AFD is used, it injects an internal
markup
header that APIM will accept per policy. Direct backend origin access is denied; all developer traffic should use the APIM custom domain.x-edge-secretEndpoint Index#
Legend:
- Dev: Requires APIM subscription key
- Admin (JWT): Requires markupcookie in PortalPay app (role checks, CSRF)
cb_auth_token
Inventory (Dev)#
- GET markup– List products with filtering/pagination
/portalpay/api/inventory - POST markup– Create/update product (idempotent by SKU)
/portalpay/api/inventory - DELETE markup– Delete product Docs:
/portalpay/api/inventory?id=...markup./inventory.md
Orders (Dev)#
- POST markup– Generate receipt/order from inventory items Docs:
/portalpay/api/ordersmarkup./orders.md
Receipts (Dev + Admin)#
- GET markup– List receipts (Dev)
/portalpay/api/receipts?limit=... - GET markup– Get receipt by ID (Dev)
/portalpay/api/receipts/{id} - GET markup– Check payment status (Dev)
/portalpay/api/receipts/status?receiptId=... - POST markup– Process refund (Admin – JWT)
/portalpay/api/receipts/refund - POST markup– Terminal display/complete (Admin – JWT) Docs:
/portalpay/api/receipts/terminalmarkup./receipts.md
Shop Configuration (Dev + Admin)#
- GET markup– Read merchant configuration (Dev)
/portalpay/api/shop/config - POST markup– Update configuration (Admin – JWT) Docs:
/portalpay/api/shop/configmarkup./shop.md
Site Configuration (Public/Dev, environment-dependent)#
- GET markup– Platform defaults (may be public; APIM can enforce in production) Docs:
/portalpay/api/site/configmarkup(section: GET /portalpay/api/site/config)./shop.md
Split (Dev + Admin)#
- GET markup– Read split configuration (Dev)
/portalpay/api/split/deploy - GET markup– List split transactions (Dev)
/portalpay/api/split/transactions?limit=... - POST markup– Configure split (Admin – JWT)
/portalpay/api/split/deploy - POST markup– Deprecated – Use client-side PaymentSplitter.release; may return 410/204 Docs:
/portalpay/api/split/withdrawmarkup./split.md
Pricing Configuration (Dev + Admin)#
- GET markup– Read pricing configuration (Dev)
/portalpay/api/pricing/config - POST markup– Update pricing configuration (Admin – JWT) Docs:
/portalpay/api/pricing/configmarkup../pricing.md
Billing (Dev)#
- GET markup– Current wallet balance and usage Docs:
/portalpay/api/billing/balancemarkup./billing.md
Tax Catalog (Dev)#
- GET markup– Jurisdiction tax catalog Docs:
/portalpay/api/tax/catalogmarkup./tax.md
Reserve (Dev)#
- GET markup– Reserve balances by currency
/portalpay/api/reserve/balances - GET markup– Recommended reserve settings Docs:
/portalpay/api/reserve/recommendmarkup./reserve.md
Users (Dev)#
- GET markup– Search users by text, XP range, and metrics filters
/portalpay/api/users/search - GET markup– List currently live/public users Docs:
/portalpay/api/users/livemarkup./users.md
GraphQL (Dev)#
- GET/POST markup– GraphQL endpoint for queries
/portalpay/api/graphql- Queries: markup,
usermarkup,followsmarkup,liveUsersmarkupleaderboard - Mutations are not available via APIM developer subscriptions; use PortalPay Admin UI for admin operations
Docs: markup
./graphql.md
- Queries:
Health (Public)#
- GET markup– Health check (no subscription key required) Docs:
/portalpay/healthzmarkup./health.md
Authorization Scopes#
APIM products/subscriptions grant scopes that are enforced by the backend. Common scopes:
- markup,
inventory:readmarkupinventory:write - markup
orders:create - markup,
receipts:readmarkupreceipts:write - markup
shop:read - markup
split:read - markup
users:read - markup
graphql:read
Requests missing the required scope return
markup
.403 ForbiddenRate Limiting and Errors#
Gateway/backend quotas and rate limits apply per subscription/wallet.
- 401 Unauthorized: Missing/invalid subscription key
- 403 Forbidden: Insufficient scope or disallowed action
- 429 Too Many Requests: Rate limit exceeded
Rate limit headers (if enabled):
- markup
X-RateLimit-Limit - markup
X-RateLimit-Remaining - markup
X-RateLimit-Reset
429 payload:
json{ "error": "rate_limited", "resetAt": 1698765432000 }
Best Practices#
- Use markupfor all developer requests (except healthz)
Ocp-Apim-Subscription-Key - Client requests do not include wallet identity; it is resolved at the gateway per subscription
- Treat your subscription key like a secret; rotate if compromised
- For admin writes, perform actions within the PortalPay web app (JWT cookie is handled by the browser)
- Monitor usage and errors; consider IP allowlists/WAF rules on your side if applicable
Related Documents#
- Authentication & Security: markup
../auth.md - Inventory: markup
./inventory.md - Orders: markup
./orders.md - Receipts: markup
./receipts.md - Shop: markup
./shop.md - Split: markup
./split.md - Users: markup
./users.md - GraphQL: markup
./graphql.md - OpenAPI: markup
../../public/openapi.yaml - Pricing & Subscription Tiers: markup
../pricing.md
