Generate a PKCE code_verifier (43–128 random characters, base64url) and compute code_challenge as S256 (SHA-256 hash, base64url-encoded)
POST the authorization request parameters (client_id, response_type, scope, redirect_uri, code_challenge, code_challenge_method=S256, and FDX-specific consent parameters) to the Financial Institution's PAR endpoint (/oauth2/par) to receive a request_uri
Redirect the user to the FI's authorization endpoint with only client_id and request_uri as query parameters; the full parameter set is now server-side, preventing manipulation
After the user authenticates and grants consent, receive the authorization code at your redirect_uri; exchange it for tokens by sending the code plus the original code_verifier to the token endpoint
Use the FDX ConsentGrant response to determine which accounts and data clusters (ACCOUNT_BASIC, ACCOUNT_DETAILED, TRANSACTIONS, STATEMENTS, etc.) the user actually authorized — may be a subset of what you requested
Store the structured consent receipt (FDX ConsentReceipt object) including consentId, grantedScopes, and expirationDate for audit and future revocation calls
Known gotchas
FAPI 2.0 requires the PAR endpoint to be authenticated with your client credentials (mTLS or private_key_jwt) — plain client_secret_basic is not compliant; verify your client registration at the FI supports the required auth method
The request_uri returned by PAR is single-use and typically expires in 60–90 seconds; if the user takes too long to reach the authorization endpoint, you must restart the PAR flow from scratch
FDX v6 scopes are data-cluster-based (not account-specific at the OAuth layer); account selection happens inside the FI's consent UI — you cannot pre-select specific accounts in the PAR request
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp