Authentication
How to authenticate with the ETM API using the OAuth 2.0 Client Credentials flow.
The ETM API authenticates with the OAuth 2.0 Client Credentials flow against Productsup's authentication server. You exchange a client_id and client_secret for a short-lived JWT, then send that JWT as a bearer token on every API request. This is a machine-to-machine flow — no end-user credentials and no shared backend secret are involved.
Get your client credentials
Each integration gets its own client_id and client_secret. They are scoped to your organization, so a token created from them can only reach your own export templates.
To request a pair, contact your Productsup Customer Success Manager or our Technical Support Team via support@productsup.com.
The client_secret is a server-side credential. Never ship it in browser or mobile code, never commit it to a repository, and never expose it to end users. Store it in your secret manager or as an environment variable.
Request an access token
Send a form-encoded POST to the authentication server token endpoint:
curl -X POST "https://auth.productsup.com/realms/External-Applications/protocol/openid-connect/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>"A successful request returns 200 OK:
{
"access_token": "...",
"expires_in": 300,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": ""
}| Field | Description |
|---|---|
access_token | The JWT to send on API requests. |
expires_in | Remaining lifetime of the token in seconds. |
token_type | Always Bearer. |
Client Credentials does not issue a refresh_token — see Token lifetime and re-authentication.
A 401 Unauthorized from this endpoint means the client_id or client_secret is wrong. A 400 Bad Request with unsupported_grant_type means the client is not configured for Client Credentials — contact support.
The example above sends the secret in the request body (client_secret_post). The token endpoint also accepts HTTP Basic (client_secret_basic), which is what most OAuth client libraries use by default. Either is fine.
Configure your client from OpenID Connect discovery
If your HTTP client is OIDC-aware, point it at the discovery document instead of hardcoding endpoints:
https://auth.productsup.com/realms/External-Applications/.well-known/openid-configurationIt resolves the token endpoint, the supported grant types, and the JWKS URI for verifying token signatures. No scope is required for ETM — omit scope from the token request.
Use the token in API requests
Pass the token in the Authorization header:
curl "https://export-template-api.productsup.com/V1/export-templates" \
-H "Authorization: Bearer <access_token>"Every ETM API endpoint requires this header. The API host is https://export-template-api.productsup.com.
Token lifetime and re-authentication
An access token is valid for the number of seconds in expires_in.
- Cache the token in memory and reuse it until it expires. Do not request a new token per API call; that adds a round trip to the authentication server on every request and will hit rate limits at scale.
- Re-authenticate by repeating the token request. Client Credentials issues no refresh token, because your client already holds the credentials needed to mint a fresh one.
- Refresh early. Request a new token shortly before the current one expires, rather than waiting for the first failure.
- Treat
401 Unauthorizedfrom the ETM API as an expired or revoked token. Request a new token and retry the call once. If the retry also returns401, stop and check your credentials — retrying in a loop will not recover.
Next steps
- Publishing changes — why a successful write is not yet live, and how to commit it
- Analyzer tests — assign reusable validators to export template attributes
- API reference — every endpoint, request, and response
How is this guide?