Skip to content

Authentication

The Shopwave API uses OAuth2 with the authorization code flow. Every API request must include a valid Bearer token in the Authorization header.

Overview

mermaid
sequenceDiagram
    participant App as Your App
    participant User as Merchant User
    participant Auth as Shopwave Auth
    participant API as Shopwave API

    App->>User: Redirect to authorization URL
    User->>Auth: Grant access
    Auth->>App: Redirect with authorization code
    App->>Auth: Exchange code for tokens
    Auth->>App: Access token + refresh token
    App->>API: API request with Bearer token
    API->>App: Response data

Step 1: Redirect to authorize

Send the merchant to the Shopwave Auth authorization endpoint:

https://secure.staging.merchantstack.com/oauth/authorize
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/callback
  &response_type=code
  &scope=read write
ParameterDescription
client_idYour application's identifier from the Applications API
redirect_uriMust match one of the URLs registered with your application
response_typeAlways code
scopeSpace-separated list of scopes

The merchant reviews the requested permissions and either approves or denies access.

Step 2: Exchange the code

After approval, Shopwave Auth redirects the merchant back to your redirect_uri with a code query parameter:

https://yourapp.com/callback?code=AUTHORIZATION_CODE

Exchange this code for an access token:

bash
curl -X POST https://secure.staging.merchantstack.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "AUTHORIZATION_CODE",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "redirect_uri": "https://yourapp.com/callback"
  }'
js
const response = await fetch('https://secure.staging.merchantstack.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'authorization_code',
    code: 'AUTHORIZATION_CODE',
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET',
    redirect_uri: 'https://yourapp.com/callback'
  })
})

const tokens = await response.json()
// {
//   access_token: "eyJhbGciOi...",
//   refresh_token: "dGhpcyBpcyBh...",
//   token_type: "Bearer",
//   expires_in: 3600
// }

WARNING

Authorization codes are single-use and short-lived. Exchange them promptly — typically within 60 seconds.

Step 3: Use the token

Include the access token as a Bearer token in the Authorization header of every API request:

bash
curl https://api.staging.merchantstack.com/product \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -H "x-accept-version: 2.0"
js
const response = await fetch('https://api.staging.merchantstack.com/product', {
  headers: {
    'Authorization': 'Bearer eyJhbGciOi...',
    'x-accept-version': '2.0'
  }
})

Scopes

Request only the scopes your application needs. The merchant sees these during the approval step.

ScopeAllows
readRead access to all resources — products, baskets, stores, reports, etc.
writeCreate and update resources — products, baskets, transactions, invoices, etc.
adminFull administrative access including destructive operations (deletes)

TIP

The admin scope includes write, and write includes read. Request the minimum scope your application requires — merchants are more likely to approve limited access.

Refreshing tokens

Access tokens expire after a set period. Use the refresh token to obtain a new access token without requiring the merchant to re-authorize:

bash
curl -X POST https://secure.staging.merchantstack.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "dGhpcyBpcyBh...",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'
js
const response = await fetch('https://secure.staging.merchantstack.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'refresh_token',
    refresh_token: 'dGhpcyBpcyBh...',
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET'
  })
})

const tokens = await response.json()
// New access_token and refresh_token

WARNING

Each refresh token is single-use. The response includes a new refresh token — store it securely and discard the old one.

Common errors

ErrorCauseFix
401 UnauthorizedMissing or invalid tokenCheck the Authorization header format: Bearer <token>
401 UnauthorizedExpired tokenRefresh the token using the refresh flow above
403 ForbiddenInsufficient scopeYour token's scope doesn't cover this operation — re-authorize with the required scope
invalid_grantExpired or reused authorization codeRestart the authorization flow from Step 1
invalid_clientWrong client_id or client_secretVerify your application credentials in the partner dashboard
redirect_uri_mismatchRedirect URI doesn't matchThe redirect_uri must exactly match one registered with your application

Security best practices

  • Store tokens securely — never expose tokens in client-side code, URLs, or logs
  • Use HTTPS — all Shopwave Auth and API endpoints require HTTPS
  • Rotate secrets — if your client secret is compromised, regenerate it immediately via the Applications API
  • Minimal scopes — request only what your application needs; you can always re-authorize for additional scopes later
  • Validate redirect URIs — register only the specific callback URLs your application uses