MMeerPartners docs

API authentication

Three ways to authenticate with the MeerPartners API: human sign-in via MeerID OIDC, JWT Bearer for the cabinet, and HMAC over an API key for server-to-server integrations. When to use which.

MeerPartners has three authentication methods — each for its own purpose. People sign in via MeerID, the browser cabinet calls the API with a JWT, and server-to-server integrations (postback, SSO) sign requests with HMAC over the API key secret.

Which method when

MethodUsed forInitiated byWhere described
MeerID OIDCHuman sign-in to the portal/cabinetThe user's browserbelow
JWT BearerCabinet requests (/api/v1/aff, /api/v1/merchant)The frontend on behalf of the signed-in userbelow
API key + HMACServer-to-server S2S: postback, token-exchangeYour business backendbelow

In short

If you are writing a server-to-server integration (sending conversions or embedding the affiliate program) — you need an API key + HMAC. JWT and MeerID are about live humans signing in to the browser cabinet, which the portal handles for you.

MeerID OIDC — human sign-in

Signing in to MeerPartners is only via MeerID, the single OIDC SSO of the Meer ecosystem. The platform has no registration, passwords or OTP of its own. A person signs in to MeerID, the platform receives a verified identity and exchanges it for a local JWT pair.

POST/api/v1/auth/meerid/exchange🔒

This is the public first-session endpoint: the MeerID browser SDK returns either a code + PKCE (popup/redirect) or a signed idToken + nonce (FedCM), and the platform returns an access_token / refresh_token.

Response of /auth/meerid/exchange
{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "expires_in": 900,
  "user": {
    "user_id": 42,
    "email": "a@b.io",
    "display_name": "Neo",
    "is_affiliate": false,
    "affiliate_id": null,
    "memberships": []
  }
}

This is handled by the MeerPartners portal — you do not need to embed this flow into your own integration. If you need to authorize your own users inside the affiliate program without MeerID, use token-exchange, not OIDC. For how people sign in, see Registration & sign-in.

JWT Bearer — cabinet requests

After sign-in the portal talks to the core API with a local JWT. The cabinet endpoints (/api/v1/aff/*, /api/v1/merchant/*, /api/v1/auth/me) accept the token in the standard header:

Authorization: Bearer <access_token>
ParameterValue
AlgorithmHS256 (HMAC)
Access tokenTTL 15 minutes
Refresh tokenTTL 30 days, single-use (rotated on every refresh)
RefreshPOST /api/v1/auth/refresh with refresh_token
Sign-outPOST /api/v1/auth/logout (one session) / POST /api/v1/auth/logout-all (all)

Refresh tokens are rotated: on POST /api/v1/auth/refresh the old token is consumed and a new pair is issued. Reusing an already-used refresh token outside the short grace window → TOKEN_REVOKED (401).

The business tenant is resolved from membership

Business-cabinet requests resolve the active tenant from the user's membership in the database (anti-IDOR), not from the request body. If you have several businesses under one account, specify the active one via the X-Tenant-Id header. It is validated against your membership; another tenant → 403 FORBIDDEN, a garbage value is ignored. This mostly concerns server-to-server calls — see API keys.

API key + HMAC — server-to-server integrations

For S2S calls (your business server → the platform) JWT is not used — the request is signed with HMAC-SHA256 over the API key secret. Signed this way are:

Each request carries four headers and a signature of the request string:

X-Api-Key-Id: <key_id>
X-Tenant-Id: <tenant_id>        # optional; if set, must match the key's tenant
X-Timestamp: 1717200000          # epoch seconds, ±300 s window
X-Signature: <hex(HMAC_SHA256(secret, signing_string))>

The signing_string is assembled like this:

{METHOD}\n{PATH}\n{X-Timestamp}\n{SHA256_hex(raw_body)}

The body enters the signature as a hash — this protects integrity: the amount or fields of the order cannot be changed after signing. The platform verifies the signature in constant time and checks the freshness of X-Timestamp (anti-replay).

The full algorithm with a worked example, along with scopes, key rotation and revocation, is on the next page.

The key secret stays on the backend only

The HMAC secret of an API key must never reach the browser, a mobile app or a public repository. The signature is computed on the server only. To authorize users in the frontend, use a scoped token from token-exchange.

What's next