WinShopAPI docs
Getting started

Authentication

Get an access token with OAuth 2.0 client credentials and send it with every request.

The API uses the OAuth 2.0 client credentials grant. Your integration is a client with an id and a secret. It exchanges them for a short-lived access token and sends that token with every request. There is no user login and no browser redirect.

Get credentials

Ask WinShop support at [email protected] for a client_id and client_secret for the instance you integrate with. Say what your integration needs to read and write, because support assigns the client a role that decides which endpoints it may call.

Keep the secret on your server. Never ship it in a browser or a mobile app.

Request a token

Send a form-encoded POST to /connect/token:

curl -X POST https://<your-instance>/connect/token \
  -d grant_type=client_credentials \
  -d client_id=svc-your-client \
  -d client_secret=your-secret

Do not send a scope parameter. The API defines no scopes; what a client may do is decided by its role.

The response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...",
  "token_type": "Bearer",
  "expires_in": 3600
}
FieldMeaning
access_tokenThe token to send with API requests. Treat it as an opaque string.
token_typeAlways Bearer.
expires_inLifetime of the token in seconds. The default is 3600 (one hour), but each instance can configure its own value. Always use the number you receive.

Call the API

Send the token in the Authorization header:

curl https://<your-instance>/api/item-lists/warehouses \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Cache the token

Request one token and reuse it until shortly before it expires. Do not request a new token for every API call.

The token endpoint is rate limited to 300 requests per minute per client. Above that it answers 429 Too Many Requests with a Retry-After header that says how many seconds to wait.

A minimal cache:

using System.Net.Http.Json;

string? cachedToken = null;
DateTime validUntil = DateTime.MinValue;

async Task<string> GetAccessTokenAsync()
{
    if (cachedToken is not null && DateTime.UtcNow < validUntil) return cachedToken;

    var response = await http.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
    {
        ["grant_type"] = "client_credentials",
        ["client_id"] = "svc-your-client",
        ["client_secret"] = "your-secret",
    }));
    response.EnsureSuccessStatusCode();

    var token = (await response.Content.ReadFromJsonAsync<TokenResponse>())!;
    cachedToken = token.AccessToken;
    // renew one minute early
    validUntil = DateTime.UtcNow.AddSeconds(token.ExpiresIn - 60);

    return cachedToken;
}

The samples in the rest of this site assume a helper like this one and call it GetAccessTokenAsync() or getAccessToken().

When a request is refused

StatusMeaningWhat to do
401 UnauthorizedThe token is missing, malformed or expired.Request a new token and repeat the call once.
403 ForbiddenThe token is valid, but the role of your client lacks the permission this endpoint needs.Ask WinShop support to adjust the role of your client. A new token will not help.
429 Too Many RequestsToo many token requests.Wait for the number of seconds in Retry-After, and cache the token.

Permissions are named Permissions.{Resource}.{Action}, for example Permissions.DeliveryNotes.View. The description of each endpoint in the reference names the permission it requires. Tell support which permissions your client is missing.

Rotating the secret

You cannot change the client secret through the API. To rotate it, or if it may have leaked, contact WinShop support at [email protected].

On this page