> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.crisscross.money/authentication/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.crisscross.money/_mcp/server. # Authentication > Learn how to authenticate requests to the CrissCross APIs (Collect, Exchange, and Payouts) using access tokens. ### Authentication All requests to the CrissCross APIs (Collect, Exchange, and Payouts) require an access token. CrissCross uses OAuth 2.0 style access tokens for authenticating API requests. Authentication is machine-to-machine: request a token with your `client_id` and `client_secret`, then include it as a Bearer token in the `Authorization` header on every subsequent request. #### Request an access token `POST https://api.crisscross.money/v1/auth/oauth2/token` ```bash curl --request POST 'https://api.crisscross.money/v1/auth/oauth2/token' \ --header 'Content-Type: application/json' \ --data-raw '{ "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" }' ``` The body must be JSON — form-encoded bodies are rejected with `400`. No `grant_type`, `scope`, or `audience` is needed; client credentials is implied. #### Response ```json { "access_token": "eyJhbGci...", "token_type": "Bearer", "expires_in": 86400 } ``` Store the token until it expires. `expires_in` is the token's lifetime in seconds (currently 86400, or 24 hours). There is no refresh token; request a new token when the current one expires. #### Use the token ```bash curl --request GET 'https://api.crisscross.money/v1/' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' ``` #### Handling authentication failures Errors from the token endpoint are a single-field envelope, `{"error": ""}`: | Status | Body | Cause | | ------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | `{"error": "Invalid request body"}` | The body is malformed or not JSON. | | `400 Bad Request` | `{"error": "client_id and client_secret are required"}` | A required field is missing. | | `401 Unauthorized` | `{"error": "Invalid client credentials"}` | Wrong credentials — an unknown `client_id` and a wrong `client_secret` are deliberately indistinguishable. | | `503 Service Unavailable` | `{"error": "Authentication service unavailable"}` | Temporary outage — retry with backoff. | On every other API call, a missing, invalid, or expired access token returns `401` with a different envelope: `{"message": "Unauthorized"}`. If you see that shape, request a new token and retry. #### Best practices * **Secure storage:** keep your `client_secret` and access tokens in a secrets manager or environment variables, never in source code. * **Rotate on compromise:** if your `client_secret` is exposed, rotate it immediately. > Securing API access with authentication