Skip to content

Getting a token

Everything under /public/v1 — except categories — is called with the access token you received at the end of the OAuth flow, in the header:

Authorization: Bearer <access_token>

The base address is:

https://api.costia.app

An access token lasts fifteen minutes. With the offline_access scope you also get a refresh token, valid for ninety days, which gets you a new one without the person being present.

Refresh tokens rotate: each use returns a new one and invalidates the previous. Always store the latest. The upside is that a leaked refresh token stops working the moment its rightful owner uses theirs.

If your library manages the cycle for you, there is nothing to do. With Better Auth:

const { accessToken } = await auth.api.getAccessToken({
body: { providerId: 'costia' },
headers: request.headers,
});

It only refreshes when expiry is close.

Code What it means
401 UNAUTHORIZED The token was not issued by Costia to a registered client
403 ACCESS_DENIED The token is valid but lacks the scope the endpoint requires
403 NOT_A_PARTNER_CLIENT The client has no partner identity: it can identify people, not act as a merchant

The full list is in Errors.