Authentication
The Partner API uses the standard OAuth 2.0 Client Credentials grant. Every request to the API must include a valid access token in the Authorization header.
Machine‑to‑Machine Authentication
This is a machine‑to‑machine (server‑to‑server) flow. Tokens are issued to your backend service, not to individual end‑users.
Key Points
- No browser redirects or user interfaces are involved.
- You request tokens programmatically with
client_id,client_secret,scope, andgrant_type=client_credentials. - Never commit actual credentials to version control. Store
client_id,client_secret, and endpoint URLs as environment variables or in secure configuration management systems. - The token endpoint does not accept user access tokens from B2C or other interactive sign‑in flows.
- Refresh tokens are not returned; when a token expires, request a new one with the same credentials.
If you need user-level authentication, you may handle that in your own application. Just let your backend call the Partner API using this machine credential flow.
Authentication Flow
Step 1: Obtain an Access Token
Endpoint
POST <https://<token‑endpoint>>/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
Replace <token‑endpoint> with the URL provided by your onboarding contact.
Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
client_id | string | Yes | The application (client) ID issued to you |
client_secret | string | Yes | The secret paired with client_id, keep it safe and never share it client-side |
scope | string | Yes | Always api://<client-id>/.default |
grant_type | string | Yes | Must be client_credentials |
Example Request (Bash)
curl -X POST "https://<token-endpoint>/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=api://YOUR_CLIENT_ID/.default" \
-d "grant_type=client_credentials"
Example Request (PowerShell)
curl -X POST "https://<token-endpoint>/oauth2/v2.0/token" `
-H "Content-Type: application/x-www-form-urlencoded" `
-d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&scope=api://YOUR_CLIENT_ID/.default&grant_type=client_credentials"
Successful Response
{
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in": 3599,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGci..."
}
expires_in is the token lifetime in seconds (≈ 60 minutes). Request a new token when the current one expires.
Step 2: Call the API
Include the token in the Authorization header on every request:
GET <partner-api.utopi.io/<resource>>
Authorization: Bearer <access_token>
SiteId: <your_site_id>
If the token is missing, expired, or invalid, the API returns 401 Unauthorized.
Error Reference (Token Endpoint)
| HTTP status | Meaning | Common causes |
|---|---|---|
| 400 | Bad Request | Missing or malformed parameter. |
| 401 | Unauthorized | Invalid client credentials. |
Common Authentication Errors
Authentication errors from the token endpoint follow a different format than Partner API errors. Here are the most common issues:
400 Bad Request - Invalid Grant Type
Error: unsupported_grant_type
{
"error": "unsupported_grant_type",
"error_description": "The app requested an unsupported grant type 'invalid_grant'.",
"error_codes": [70003],
"timestamp": "2025-08-01T14:27:45Z",
"trace_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"correlation_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Resolution: Ensure grant_type=client_credentials is included in your request.
400 Bad Request - Invalid Client ID
Error: unauthorized_client
{
"error": "unauthorized_client",
"error_description": "Application with identifier 'invalid-client-id' was not found in the directory.",
"error_codes": [700016],
"timestamp": "2025-08-01T14:27:21Z",
"trace_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"correlation_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"error_uri": "https://login.example.com/error?code=700016"
}
Resolution: Verify your client_id is correct and matches the credentials provided during onboarding.
401 Unauthorized - Invalid Client Secret
Error: invalid_client
{
"error": "invalid_client",
"error_description": "Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID.",
"error_codes": [7000215],
"timestamp": "2025-08-01T14:29:20Z",
"trace_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"correlation_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"error_uri": "https://login.example.com/error?code=7000215"
}
Resolution: Verify your client_secret is the actual secret value, not the secret ID. Check your stored credentials.
Error Response Structure
Authentication errors include these fields:
error- Short error identifiererror_description- Detailed error message with error codeerror_codes- Array of specific error codestimestamp- When the error occurredtrace_id- Trace identifier for debuggingcorrelation_id- Request correlation identifiererror_uri- Link to error documentation (when available)
Troubleshooting Steps
- Verify credentials - Ensure
client_idandclient_secretmatch your onboarding details - Check parameters - Confirm all required parameters are included with correct values
- Review scope format - Ensure scope is
api://<your-client-id>/.default - Contact your technical contact if errors persist after verification