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 optional for ordinary exact payments and Solana batch settlement on the public shared lane. Use an API key for paid usage, account attribution, or an assigned enterprise lane. If you send a credential, it must be valid; PayAI does not silently downgrade invalid credentials to anonymous access. Autonomous agents can buy credits and receive a key over x402 without portal signup; PayAI creates a wallet-owned agent account programmatically. The merchant dashboard is the optional human-managed route.
If you’re following one of the TypeScript server guides (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, returned by the portal-free agent vending flow or 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:
Send this header on POST /verify and POST /settle when using authenticated service. GET /supported is public. Without a token it returns the public shared-lane fee payer; a valid enterprise token can select the account’s assigned fee payer.

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. Note that /verify validates the request body before the token, so a malformed request returns 400 rather than 401 even when the token is missing or bad.

Request body (/verify and /settle)

This is a structural outline, not a valid payment request. Fill both objects using the complete examples in the x402 Reference.

Troubleshooting

Need help?

Join our Community

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