When to use machine access
Use this pattern when your backend needs to:- Provision or update users via the Builder API.
- Mint user-scoped JWTs for end-users already known to your system.
- Read aggregated usage data from the Usage API.
- Complete a device authorization on behalf of a user (RFC 8693 token exchange).
Prerequisites
- A confidential M2M client (
m2m_…id andpmth_cs_…secret). See Client model. - The M2M client has been granted the scopes required by the endpoint you are calling.
Option A: Client credentials grant
Exchange your credentials for a short-lived Bearer token, then use that token for subsequent API calls. This is the preferred pattern when making multiple API calls in the same request lifecycle, because it decouples token acquisition from the API call.1. Obtain a machine token
The token endpoint is published in OIDC discovery undertoken_endpoint. For convenience it is stable at {issuer}/token.
2. Call the Builder API with Bearer auth
Option B: HTTP Basic auth
For single calls where acquiring a separate token adds unnecessary latency, pass the M2M credentials directly using HTTP Basic auth (RFC 7617). PymtHouse accepts Basic auth on all Builder API endpoints.clientId in the URL path must match the authenticated confidential client’s associated app. A valid credential from a different app’s M2M client returns 404.
Choosing between Bearer and Basic
For high-throughput backends making many calls in sequence, acquire one token and reuse it for the batch. For low-frequency automations and operational scripts, Basic auth is simpler.
Error responses
Rotating client secrets
Rotate M2M secrets through the app credentials endpoint in the developer dashboard or admin API. After rotation:- Update the secret in your backend’s secret manager.
- Redeploy or restart the service.
- Do not rotate the public client secret — public clients must remain secretless.
Key design decisions
- Basic auth is supported alongside Bearer. Confidential server-to-server clients are common in automation tooling where adding a token exchange step adds operational friction. Supporting both modes simplifies bootstrapping and scripting without compromising security, since the credential type (M2M secret) carries the same privilege either way.
- Tenant boundary on path, not query parameter. Enforcing
clientIdas a URL path segment rather than a query parameter makes the tenant scope visible and cache-key-safe. The route handler resolves the OAuthclient_idto an internal record before any query, keeping the public API free of internal IDs. - Short-lived machine tokens, not long-lived API keys. Using the standard client credentials flow means PymtHouse does not need a separate API-key issuance system. Short lifetimes limit the blast radius of a compromised token without requiring explicit revocation infrastructure.
Implementation tasks
- Store
M2M_IDandM2M_SECRETin your backend secret manager (e.g., HashiCorp Vault, AWS Secrets Manager, Vercel environment variables). Do not commit them to source control. - Implement a simple in-process token cache: acquire a machine token once per request batch, reuse it, and let it expire naturally rather than building explicit refresh logic.
- For HTTP Basic auth calls, ensure your HTTP client encodes the credentials correctly (
base64(client_id + ":" + client_secret)). Most libraries handle this via aauthoruser/passwordfield. - Test that Basic auth calls to a different app’s
clientIdreturn404, not403— this verifies that the tenant boundary is enforced, not just that the credentials are valid.