Management API Credentials
The Management API uses client credentials (client ID and client secret) for secure server-to-server authentication using the OAuth 2.0 Client Credentials flow.
Overview
Client credentials are used exclusively for server-to-server authentication to the Management API. These credentials should be treated as highly sensitive and never exposed in client-side code or public repositories.
Getting Your Credentials
Manage your keys through the Management API itself, at https://api2.sesamy.com/management/api-keys. The Sesamy dashboard calls these same endpoints.
Create a Key
curl -X POST https://api2.sesamy.com/management/api-keys \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Newsroom CMS", "role": "read" }'Response:
{
"clientId": "apikey_9f2c1d8e4b7a4f1e9c3d5a6b7c8d9e0f",
"name": "Newsroom CMS",
"role": "read",
"scopes": [
"access-lists:read",
"bills:read",
"checkouts:read",
"contracts:read",
"domains:read",
"entitlements:read",
"products:read",
"sites:read",
"stats:views:read",
"transactions:read",
"users:read"
],
"createdAt": "2026-09-01T09:12:44.000Z",
"clientSecret": "k2Jd8sV1pQ7wE4rT6yU9iO0aS3dF5gH8",
"tokenUrl": "https://acme.token.sesamy.com/oauth/token",
"audience": "urn:sesamy"
}| Field | Type | Description |
|---|---|---|
name | string | What the key is for. Shown in the key list and the only way to tell keys apart |
role | string | (Optional) read or full. Defaults to read |
The secret is shown once
clientSecret appears in this response and nowhere else. Store it before you close the response. There is no way to read it back, so replacing a lost secret means deleting the key and creating a new one.
API keys use a different token URL to the rest of the platform
Everywhere else in these docs, the token endpoint is the shared https://token.sesamy.com/oauth/token. API keys are the exception. Your key lives on your own tenant, which is addressed as a subdomain, so it authenticates against https://<your-vendor-id>.token.sesamy.com/oauth/token instead. Posting a key to the shared host reaches a different tenant and fails with invalid_client.
Do not build the URL by hand. Use the tokenUrl and audience returned when the key was created.
List Your Keys
curl https://api2.sesamy.com/management/api-keys \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Returns every key for your vendor, newest first, without secrets.
Keep Your Credentials Secret
Never commit credentials to version control or expose them in any client-side code. If your credentials are compromised, revoke them immediately and create new ones.
Using Client Credentials - OAuth 2.0 Client Credentials Flow
Step 1: Request an Access Token
Send a POST request to the token endpoint with your credentials:
curl -X POST https://acme.token.sesamy.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "audience=urn:sesamy"Replace acme with your own vendor id, as returned in tokenUrl when you created the key.
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 86400
}Step 2: Use the Access Token
Include the access token in the Authorization header of your Management API requests:
curl -X GET https://api2.sesamy.com/management/products \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"With SDKs
The Sesamy SDK takes a tokenProvider that returns a complete Authorization header, so it works with a key once you have exchanged it for an access token:
import { management } from '@sesamy/sdk';
const sdk = management({
baseUrl: 'https://api2.sesamy.com',
tokenProvider: async () => `Bearer ${await getAccessToken()}`,
vendorId: 'acme',
});
const products = await sdk.getProducts();Cache the token inside getAccessToken rather than exchanging your key on every call. See Implement Token Caching.
Management API Permissions
A key carries a preset of Management API scopes, chosen with role when you create it. Presets rather than free-form scope lists keep a key's reach predictable and reviewable.
The read Preset
Every read scope: access-lists:read, bills:read, checkouts:read, contracts:read, domains:read, entitlements:read, products:read, sites:read, stats:views:read, transactions:read, and users:read.
Use this for anything that only reports, such as a dashboard, a data export, or a reconciliation job.
The full Preset
Everything in read, plus access-lists:write, domains:write, links:create, products:write, sites:write, and users:write.
What no key can do
Neither preset can manage team members, portal permissions, or other API keys. Those stay human, session-authenticated actions, so a leaked key cannot be used to grant its holder access that survives the key being revoked.
Requesting Specific Scopes
A token carries the scopes you ask for, narrowed to what the key's preset allows. Ask for less than the preset when a job needs less:
curl -X POST https://acme.token.sesamy.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "audience=urn:sesamy" \
-d "scope=products:read users:read"Asking for a scope the preset does not include fails the exchange with access_denied. Omit scope to receive the whole preset.
Scope Patterns
Scopes follow a resource:action pattern:
resource:read- read and retrieve operationsresource:write- create, update, and delete operations
Some scopes cover nested resources. access-lists:write includes managing the grants under an access list.
Best Practices
1. Store Securely
Use environment variables or a secrets management service:
# .env file (never commit this!)
SESAMY_CLIENT_ID=YOUR_CLIENT_ID
SESAMY_CLIENT_SECRET=YOUR_CLIENT_SECRET2. Implement Token Caching
Cache tokens to reduce token endpoint requests.
Revoking Credentials
Delete the key by its clientId:
curl -X DELETE https://api2.sesamy.com/management/api-keys/apikey_9f2c1d8e4b7a4f1e9c3d5a6b7c8d9e0f \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Returns 204 No Content. The key can mint no further tokens.
Tokens already minted stay valid
Revoking stops the key from minting new tokens. Access tokens it minted earlier keep working until they expire, so treat a compromise as live until the longest-lived token has expired.
If you suspect a key has been compromised:
- Create a replacement key and deploy it
- Delete the compromised key
- Check your logs for what the key did while it was exposed
Troubleshooting
401 Unauthorized
If you receive a 401 Unauthorized error:
- Verify your
client_idandclient_secretare correct - Check that the credentials haven't been revoked
- Ensure you're using the correct environment (development vs. production)
- Verify the
Authorizationheader is properly formatted asBearer TOKEN
403 Forbidden
If you receive a 403 Forbidden error:
- Verify your credentials have access to the Management API
- Confirm the requested resource is available in your plan
- Check your rate limits haven't been exceeded
Invalid Client
If you receive an "invalid_client" error:
- Verify your
client_idandclient_secretare correct - Ensure neither value contains extra whitespace
- Confirm the application is active in your dashboard
Next Steps
- OAuth 2.0 - Learn about authorization flows for apps and websites
- JWT Tokens - Understanding and validating access tokens
- API Reference - Explore available Management API endpoints