# Core concepts

> Workspaces, members and roles, the four kinds of keys, user tokens and SDK sessions, test mode, and partners.

Source: https://docs.nexafone.so/v1/concepts/

## Workspaces, members and roles

A **workspace** is one business: its WhatsApp number, inbox, teams, calls and billing. People who work in it are
**members**, each with one role: `owner`, `admin`, `supervisor`, `agent` or `viewer`. Teams group members; agents see
only their teams’ conversations and calls. Every API operation declares the permission it needs (shown as
**Permission** in the [API reference](/v1/api/)), and the server checks it on every request.

## Keys

| Key | Prefix | Lives | Used for |
| --- | --- | --- | --- |
| Secret key | `sk_live_…`, `sk_test_…` | Your server only | Calling the API and signing user tokens. Carries **scopes** (the permissions it acts with) and an optional IP allow-list |
| Publishable key | `pk_live_…`, `pk_test_…` | Browser or app | Starting SDK sessions, only from its **allowed origins** (web) or bundle ids and package names (mobile) |
| Partner secret key | `psk_live_…`, `psk_test_…` | The partner’s server | The [Partner API](/v1/partners/api/) and the partner’s own stores |
| Partner publishable key | `ppk_live_…`, `ppk_test_…` | Browser | SDK sessions on the partner’s domains, for all of a user’s stores |

Keys are shown **once**, when they are created; Nexafon keeps only a hash. Revoke a key and it stops working at once.
Workspace keys are managed under **Developers → API keys**; partner keys by Nexafon in the console.

## User tokens and SDK sessions

Browsers never hold a secret key. Instead:

1. Your server signs a **user token**: a JWT (HS256) signed with a secret key, naming your user, valid for at most 10
   minutes and usable once. See [user tokens](/v1/server/user-tokens/).
2. The SDK exchanges it, with the publishable key, at `POST /api/v1/sdk/sessions` for an **SDK session token**
   (`sdk_…`). The session acts as the workspace member the user maps to, within the scopes of the secret key that
   signed the token.
3. The session lasts 15 minutes and is refreshed in the background for up to 12 hours; after that the SDK asks your
   server for a new user token. It is held **in memory** inside Nexafon’s frames, never in `localStorage` or cookies.

## Test mode

Test keys (`sk_test_…`, `pk_test_…`) and the sessions they start work against the same workspace data but never
reach real customers or move money. Every operation that calls Meta (sending messages; placing, answering, declining,
ending, transferring or picking up WhatsApp calls; submitting, deleting or syncing templates; changing the number or
the store's catalog) answers `403 test_mode_live` unless the workspace has a WhatsApp **test number** connected.
Internal calls between members never reach Meta and work in test mode. Payments, subscription changes and wallet
settings (automatic top-up charges a saved card) always answer `403 test_mode_live`, and a test key or session that
adds a member when every seat is taken gets `seat_limit_reached` instead of buying a seat. A user token must be signed
with a secret key of the same mode as the publishable key.

## Plans and features

What a workspace may use comes from its plan: features such as `sdk.embeds` or `commerce.orders`, and limits such as
`seats`. An operation whose feature the plan lacks answers `403` with the code `feature_not_in_plan`. See
[billing](/v1/billing/) for the full list.

## Partners and stores

A **partner** is a platform (a marketplace, a restaurant system) that runs many businesses. Each business on it is a
**store**: an ordinary workspace linked to the partner by the partner’s own id for it, its `externalRef`. The partner
creates stores, signs in their staff and receives every store’s events. See [partners](/v1/partners/).

## Versions

This is version **v1** of the API and SDK. Public operations answer with an `API-Version: v1` header. A deprecated
operation keeps working for at least 180 days and announces it with `Deprecation` and `Sunset` headers; see the
[API overview](/v1/api/#versioning-and-deprecation).
