Skip to main content

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.
If you’re using one of the TypeScript server guides or starter kits (Express, Hono, Next.js), facilitator authentication is already built in. Just set the PAYAI_API_KEY_ID and PAYAI_API_KEY_SECRET environment variables and the middleware handles the rest. Refer to those guides for setup instructions.

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 with payai_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

  1. Base64url-encode the header JSON -> headerB64
  2. Base64url-encode the payload JSON -> payloadB64
  3. Form the signing input: headerB64 + "." + payloadB64
  4. Sign the UTF-8 bytes of the signing input with your Ed25519 private key
  5. Base64url-encode the 64-byte signature -> signatureB64
  6. The JWT is: headerB64.payloadB64.signatureB64
Base64url encoding uses the standard Base64 alphabet with + replaced by -, / replaced by _, and no = padding.

5. Send the request

Include the JWT as a Bearer token on all facilitator requests:
This header is required on all authenticated facilitator endpoints: POST /verify, POST /settle, and GET /supported.

Token caching

JWTs are valid for the full exp - 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.
Uses the Web Crypto API — works in Node.js 18+, Deno, Bun, and browsers with zero dependencies.

Facilitator endpoints

All endpoints are at https://facilitator.payai.network and require the Authorization: Bearer <jwt> header when authenticated.

Request body (/verify and /settle)

For full payload schemas, see the x402 Reference.

Troubleshooting

Need help?

Join our Community

Have questions or want to connect with other developers? Join our Discord server.