Skip to content

Authentication

View as Markdown

Every request to the Flowkiwi APIs is authenticated with an OAuth 2.0 bearer token, sent as:

Authorization: Bearer <token>

There are two ways to get one.

A user token authenticates you as a partner - the same identity you have when you sign in to the partner app. Use it to explore the API and to follow the guides.

You don’t need to leave the docs to get one: on any endpoint page, the Access token field in the right-hand panel has a Log in with Flowkiwi button. Sign in once and your token is filled in automatically on every endpoint page and substituted into the {token} placeholder of every cURL example. You can also paste a token by hand into that field.

Ready to try it? Head to the reference:

For production, server-to-server access you’ll use an integration instead of a personal user token: an integration carries its own credentials (a client id and secret) that you exchange for a token, independent of any one partner’s session.

A token carries a set of permissions (products:write, purchase_offers:write, …). They gate operations and, on reads, individual properties.

When the caller lacks a permission the operation requires, the request is refused with 403 Forbidden. The Problem Details body names what is missing in missingPermissions:

{
"type": "/errors/403",
"title": "An error occurred",
"status": 403,
"detail": "Access Denied.",
"missingPermissions": ["purchase_offers:write"]
}

Reads behave differently: rather than refusing the whole request, the API returns the resource with the gated properties emptied, and names the missing scopes in a response header:

Flowkiwi-Missing-Scopes: purchase_offers:read

A blank or absent property is therefore ambiguous on its own - it can mean “no value” or “not visible to this token”. Check the header before treating an empty field as empty data.

Across the Product Management API, POST, PUT and PATCH return the resource written, in the same representation as a GET on it - no follow-up read needed. A POST answers 201 Created with a Location header carrying the new IRI; a DELETE answers 204 No Content.

{
"@id": "/api/products/0196f3a0-4444-7000-8000-000000000001",
"@type": "Product",
"id": "0196f3a0-4444-7000-8000-000000000001",
"title": "Blue sneaker",
"status": "/api/statuses/DRAFT"
}

The response shows the plain representation: relations stay IRIs (no expand), every field is present (no properties[]), and resolved prices are not computed. GET the IRI with those parameters when you need them.