Overview
The PayAI facilitator authenticates merchants using short-lived JWTs signed with Ed25519 (the EdDSA algorithm). If you use the@payai/facilitator TypeScript package, this is handled automatically. This guide explains the underlying protocol so you can implement authentication in any language without depending on PayAI packages.
Authentication is only required beyond the free tier (10,000 settlements/month). Create a merchant account at merchant.payai.network to get your API keys.
API key structure
Your API key has two parts, available from the merchant dashboard:
The secret may be prefixed with
payai_sk_ as shown in the dashboard. Strip this prefix before use — the remaining string is a standard base64-encoded PKCS#8 DER key.
Protocol steps
1. Normalize the API key secret
If the secret starts withpayai_sk_, remove that prefix. The result is a base64-encoded Ed25519 private key in PKCS#8/DER format.
2. Build the JWT header
3. Build the JWT payload
4. Encode and sign
- Base64url-encode the header JSON ->
headerB64 - Base64url-encode the payload JSON ->
payloadB64 - Form the signing input:
headerB64 + "." + payloadB64 - Sign the UTF-8 bytes of the signing input with your Ed25519 private key
- Base64url-encode the 64-byte signature ->
signatureB64 - The JWT is:
headerB64.payloadB64.signatureB64
+ replaced by -, / replaced by _, and no = padding.
5. Send the request
Include the JWT as a Bearer token on all facilitator requests:POST /verify, POST /settle, and GET /supported.
Token caching
JWTs are valid for the fullexp - iat window (default: 120 seconds). To avoid signing on every request, cache the token and refresh it ~30 seconds before expiry.
Code examples
The following examples implement the full authentication flow with no PayAI-specific dependencies.- TypeScript
- Python
- Go
- Rust
Uses the Web Crypto API — works in Node.js 18+, Deno, Bun, and browsers with zero dependencies.
Facilitator endpoints
All endpoints are athttps://facilitator.payai.network and require the Authorization: Bearer <jwt> header when authenticated.
Request body (/verify and /settle)
Troubleshooting
Need help?
Join our Community
Have questions or want to connect with other developers? Join our Discord server.

