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:

http://secure.dev.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 http://secure.dev.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('http://secure.dev.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 http://api.dev.merchantstack.com/product \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -H "x-accept-version: 2.0"
js
const response = await fetch('http://api.dev.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 http://secure.dev.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('http://secure.dev.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