Skip to main content
Every Payment API request is authenticated with an OAuth 2.0 Client Credentials access token. You exchange your client_id and client_secret for a short-lived access_token, then send that token as a Bearer credential on each request.
Authentication is server-side only. Your client_secret and the tokens derived from it must never be exposed in a browser, mobile app, or any client your customers control. Treat them like a password.

Obtain an Access Token

Call POST /api/v1/oauth2/token with the client_credentials grant. You receive both an access_token (for API calls) and a refresh_token (to renew it without re-sending your secret).
curl -X POST 'https://core.quidkey.com/api/v1/oauth2/token' \
  -H 'Content-Type: application/json' \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

Response

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 900
  }
}
FieldDescription
access_tokenThe token you send on every API request. Valid for ~15 minutes.
refresh_tokenUsed to obtain a new access_token without re-sending your client_secret. Valid for 24 hours.
token_typeAlways Bearer.
expires_inLifetime of the access_token in seconds (900 = 15 minutes).

Authenticate Requests

Send the access token in the Authorization header on every Payment API call:
Authorization: Bearer <access_token>
curl 'https://core.quidkey.com/api/v1/payment-requests:redirect' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{ ... }'
A missing, malformed, or expired token returns 401 (with code NO_TOKEN or INVALID_TOKEN). Branch on the 401 status rather than the code. See Errors for the full error envelope.

Refresh Before Expiry

Access tokens are intentionally short-lived. Rather than calling /oauth2/token for every request, cache the token and refresh it before it expires using the refresh_token.
curl -X POST 'https://core.quidkey.com/api/v1/oauth2/refresh' \
  -H 'Content-Type: application/json' \
  -d '{
    "refresh_token": "YOUR_REFRESH_TOKEN"
  }'
The response returns a fresh access_token and expires_in. It does not return a new refresh_token: reuse your existing one until it expires.
Refresh a little early (for example when the token is within ~60 seconds of expiry) so an in-flight request never fails on a token that expires mid-call.

Token Lifecycle

TokenValidityRenewed by
access_token~15 minutesPOST /api/v1/oauth2/refresh
refresh_token24 hoursPOST /api/v1/oauth2/token (with client_id + client_secret)
When the refresh_token itself expires (after 24 hours), authenticate again from scratch using your client_id and client_secret.

Best Practices

Store client_id and client_secret in environment variables or a secrets manager (Google Secret Manager, HashiCorp Vault, etc.). Never ship them to a browser, mobile binary, or public repository.
Hold the access_token in memory across requests for its full lifetime instead of minting a new one each time. Track expires_in and refresh proactively.
If a request returns 401, refresh the token once and retry. If the refresh also fails, fall back to a full client_credentials exchange.

Next Steps

Issue a Token

Try the OAuth flow in the interactive playground

Idempotency

Make create calls safe to retry

Errors

Error envelope, status codes, and handling

API Reference

Base URLs, response format, and conventions