Skip to main content

Authentication

The Clopos Open API v2 uses short-lived JWT access tokens. Exchange your credentials at /v2/auth to receive a token, then include it in the x-token header on every subsequent request.

Prerequisites

Before you can authenticate you will need:
  • Client ID — your application’s unique identifier
  • Client Secret — your application’s secret key
  • Brand — the brand identifier you want to access
  • Integrator ID — identifies the integrator making the request. New in v2 and required on every auth call.
Request your credentials and an integrator_id from Clopos by filling out this form.
All v2 requests use the base URL https://integrations.clopos.com/open-api/v2.

Authentication flow

Step 1: Obtain an access token

Send a POST request to the v2 auth endpoint:
curl -X POST https://integrations.clopos.com/open-api/v2/auth \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "{{client_id}}",
    "client_secret": "{{client_secret}}",
    "brand": "{{brand}}",
    "integrator_id": "{{integrator_id}}"
  }'
Request body
FieldTypeRequiredDescription
client_idstringYesIssued by Clopos.
client_secretstringYesPaired secret for the client.
brandstringYesBrand identifier.
integrator_idstringYesIntegrator identifier issued by Clopos.
venue_id is not part of the v2 auth body. The active venue is resolved from the JWT and can optionally be overridden per-request with the x-venue header.

Step 2: Inspect the response

A successful authentication returns a signed JWT:
{
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "expires_at": 1767852332,
  "message": "Authentication successful"
}
FieldTypeDescription
tokenstringThe JWT. Include it verbatim in the x-token header.
token_typestringAlways Bearer.
expires_inintegerToken lifetime in seconds (typically 3600).
expires_atintegerUnix timestamp after which the token is rejected.
The JWT encodes your brand, venue_id, integrator_id, and upstream auth state, so you do not need to send them as separate headers.

Step 3: Call an authenticated endpoint

Include the JWT in the x-token header. That is the only header required on v2 endpoints.
curl -X GET "https://integrations.clopos.com/open-api/v2/products" \
  -H "x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Required header
  • x-token — the JWT returned by /v2/auth.
Optional header
  • x-venue — override the venue encoded in the JWT for this request. Useful when a single integrator operates across multiple venues.

Token management

Tokens expire after expires_in seconds (typically 1 hour). Refresh them before they expire to avoid request failures.

Best practices

  1. Store tokens securely — never expose them in client-side code or commit them to source control.
  2. Refresh proactively — re-authenticate before expires_at rather than waiting for a 401.
  3. Handle errors gracefully — on any 401, re-authenticate and retry once.
  4. Use HTTPS only — never send credentials over unencrypted connections.

Error handling

Errors from /v2/auth

StatusBodyCause
400 Bad Request{ "success": false, "error": "Missing client_id, client_secret, brand, or integrator_id" }One or more required fields were omitted.
400 Bad Request{ "success": false, "error": "Invalid integrator_id" }The integrator_id is unknown or inactive.
200 OK{ "success": false, "error": "Integrator is in test mode. But brand is not in test mode", "brand": "...", "integrator": "..." }The integrator is flagged as test-only, but the brand is in production stage. Switch to a production integrator or a test brand. Note this is returned as a 200 with success: false, not a 4xx.
401 Unauthorized{ "success": false, "message": "..." }Upstream rejected the client_id / client_secret / brand combination.

Errors from authenticated endpoints

StatusBodyCause
401 Unauthorized{ "success": false, "error": "Headers are missing" }The x-token header was not sent.
401 Unauthorized{ "success": false, "error": "Invalid token" }The JWT is malformed or its signature does not verify.
401 Unauthorized{ "success": false, "expires_at": "2026-01-01T12:00:00.000Z", "error": "Token expired" }The JWT expired. Re-authenticate to get a new one. Note that expires_at in this error is an ISO 8601 string, unlike the Unix timestamp returned by /v2/auth.
401 Unauthorized{ "success": false, "error": "Invalid integrator_id" }The integrator_id encoded in the token is no longer active.
401 Unauthorized{ "success": false, "error": "Integrator is in test mode. But brand is not in test mode", "brand": "...", "integrator": "..." }Same test/production mismatch as above, enforced on every authenticated call.

Code examples

const BASE_URL = 'https://integrations.clopos.com/open-api/v2';

async function authenticate() {
  const response = await fetch(`${BASE_URL}/auth`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: '{{client_id}}',
      client_secret: '{{client_secret}}',
      brand: '{{brand}}',
      integrator_id: '{{integrator_id}}'
    })
  });

  const data = await response.json();

  if (!data.success) {
    throw new Error(data.error || 'Authentication failed');
  }

  return { token: data.token, expiresAt: data.expires_at };
}

async function makeAuthenticatedRequest(path, token, options = {}) {
  return fetch(`${BASE_URL}${path}`, {
    ...options,
    headers: {
      'x-token': token,
      'Content-Type': 'application/json',
      ...options.headers
    }
  });
}

Next steps

Once you have your access token you can start making API requests: