Productsup
Stream API

Authentication

How to authenticate with the Productsup Stream API using the OAuth 2.0 Client Credentials flow.

9 min read

The Stream 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.

Personal Access Tokens still work, but they are deprecated. We onboard new integrations with Client Credentials. See Personal Access Tokens (deprecated).

Get your client credentials

Each integration gets its own client_id and client_secret pair. Productsup provisions them for you. The pair is bound to a single Productsup organization, so a token created from a given client credentials reaches only that organization's streams.

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:

Request
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:

Response
{
  "access_token": "...",
  "expires_in": 300,
  "token_type": "Bearer",
  "not-before-policy": 0,
  "scope": ""
}
FieldDescription
access_tokenThe JWT to send on API requests.
expires_inRemaining lifetime of the token in seconds.
token_typeAlways 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.

This example 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-configuration

It resolves the token endpoint, the supported grant types, and the JWKS URI for verifying token signatures. No scope is required for the Stream API — omit scope from the token request.

Use the token in API requests

Pass the token in the Authorization header:

Request
curl "https://stream-api.productsup.com/streams" \
  -H "Authorization: Bearer <access_token>"

Every Stream API endpoint requires this header. The API host is https://stream-api.productsup.com.

What the token grants

A Client Credentials token carries an organization identity, not a user identity. There is no user behind it, and the organization it resolves to is fixed when Productsup provisions your credentials.

Within that organization, the token lets you:

  • Produce and consume stream items
  • Produce webhook payloads
  • Manage streams
  • Manage webhooks
  • Read batch status

The token reaches nothing outside that organization. An integration that spans several Productsup organizations needs one credential pair per organization.

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 wastes your rate limit budget.
  • 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 Unauthorized from the Stream API as an expired or revoked token. Request a new token and retry the call once. If the retry also returns 401, stop and check your credentials — retrying in a loop will not recover.

Unified authentication

The Stream API and the Platform API use separate tokens. Some Platform API endpoints, however, support unified authentication — they accept a Stream API Personal Access Token, so you do not need separate Platform API credentials to call them.

Endpoints that support unified authentication:

Unified authentication accepts Personal Access Tokens only. These two endpoints do not accept a Client Credentials access token, so an integration that calls them needs a PAT alongside its client credentials.

Both appear in Getting started. See Platform API authentication for the Platform API side.

Personal Access Tokens (deprecated)

Personal Access Tokens remain supported for existing integrations, but they are deprecated. We onboard new integrations with the OAuth 2.0 Client Credentials flow described in Request an access token.

A Personal Access Token (PAT) is a long-lived token sent as a bearer token. The Productsup platform links PATs to user accounts. A PAT grants full access; there are no finer-grained permissions.

Your main Productsup contact can arrange Stream API access, issue additional tokens, and revoke existing ones.

The following request lists a stream. It uses the same Authorization: Bearer <token> header format as a Client Credentials access token:

Request
curl --location --request GET 'https://stream-api.productsup.com/streams/124773' \
--header 'Authorization: Bearer <token>'

Next steps

  • Getting started — create a stream, upload data, and import it into a site
  • Uploading data — the products endpoint, request body, and attribute requirements
  • Rate limiting — per-endpoint limits, rate limit headers, and retry guidance

On this page

Still stuck?

Reach out to our support team and we’ll help you get unstuck.

Contact support