# Authentication

The Payments API does **not** use an `Authorization` header. You identify yourself with keys inside the JSON request body (and, on some endpoints, in custom headers). Always send `Content-Type: application/json`. 

## The credentials at a glance

| Credential | Who has it | What it does | Where it goes | Keep it |
|------------|-----------|--------------|---------------|---------|
| `seller_payme_id` (the **MPL**) | Every seller (merchant) | Identifies the seller **and, on its own, authenticates** most seller-level calls: creating sales, refunding, querying sales, updating the seller. | JSON body field `seller_payme_id`, or header `PayMe-Merchant-Key` | **Secret** — server-side only |
| `payme_client_key` | **Partners** (platforms and marketplaces) only | The partner key. Needed for partner-level calls such as creating sellers and querying across sellers. | JSON body field `payme_client_key`, or header `PayMe-Partner-Key` | **Secret** — server-side only |
| Public key | Every seller; one per seller per environment | Designed for browser code: tokenizing cards (Hosted Fields), Apple Pay and Google Pay flows, and reading a filtered list of the seller's transactions. | Header `PayMe-Public-Key`; first argument of `PayMe.create(apiKey, …)` | May be exposed in the browser — but note it can read transactions |



Example MPL format: `MPLDEMO-MPLDEMO-MPLDEMO-1234567`. 

**`seller_payme_secret` is not a credential.** `create-seller` returns it, but it is a random value that PayMe never stores or checks. Ignore it. 

## Merchants and partners

- **A merchant** (a single seller) authenticates with `seller_payme_id`. It can call `refund-sale` with `seller_payme_id` alone — PayMe finds the partner from the seller. 
- **A partner** (a platform managing many sellers) also holds `payme_client_key`, sent in the body or the `PayMe-Partner-Key` header. If a partner sends both keys, the seller must belong to that partner; otherwise the request fails with error `20` ("Merchant-Seller inconsistency"). 

Partner-only endpoints documented with `payme_client_key` include `create-seller`, `update-seller`, `upload-seller-files`, `withdraw-balance`, `get-vas-seller`, `vas-enable`, `vas-disable`, POS `authenticate` and `pair`, and the query APIs `get-sellers`, `get-subscriptions`, `get-withdrawals` and `funds-transfer`. 

Error codes you may see while setting up keys: `1` — no key sent at all; `200` — the `payme_client_key` matches no partner; `201` — the partner is inactive; `251` — the `seller_payme_id` matches no seller; `163` — the seller is inactive. 

### Header-based endpoints

| Header | Carries | Used on (examples) |
|--------|---------|--------------------|
| `PayMe-Merchant-Key` | The seller's MPL | `GET /buyers/{buyer_guid}`, `GET /documents`, 3D Secure hash resolution, `PATCH /subscriptions/{sub_payme_id}/resume`, B2B `payment-contracts` |
| `PayMe-Partner-Key` | The partner's client key | `GET /sellers/{seller_payme_id}/public-keys`, `GET /banks/{country_iso_code}` |
| `PayMe-Public-Key` | The seller's public key | `POST /sales/{payme_sale_id}/3ds` (called from the browser), `POST /get-transaction-data` |
| `PayMe-Signature` | A static value PayMe provides on request | `/sellers/{mpl_key}/individuals`, `/sellers/{mpl_key}/mids` |



`PayMe-Signature` is not computed per request: it is a static secret value that PayMe gives you on request. Keep it secret and never paste it into code samples or tickets. 

### The public key

Each seller has its own public key, issued separately in each environment. A partner can look it up with `GET /sellers/{seller_payme_id}/public-keys` (header `PayMe-Partner-Key`), and `create-seller` returns it as `seller_public_key`. 

The public key is meant for browser code, but it can read a filtered list of the seller's transactions. Use it only where you need it in the browser. 

> ⚠ TO CONFIRM: Where in the merchant dashboard does a merchant find its public key? [Q9]

## Getting credentials

- **Payments API:** not yet documented — see below.
- **Keep API:** you receive a `Client ID` and `Client Secret` from your Account Manager. 

> ⚠ TO CONFIRM: How does a developer get sandbox credentials (seller_payme_id/MPL, payme_client_key, public key) — self-service sign-up, an account manager, or an email to support? [Q5]

> ⚠ TO CONFIRM: Sandbox and production credentials are most likely fully separate — each environment generates its own keys, so a sandbox key should be rejected by `live.payme.io` and vice versa. Please confirm the environments share no credentials. [Q10]

## Keep API: OAuth 2.0 client credentials

1. `POST /oauth2/token` with `application/x-www-form-urlencoded` body: `grant_type=client_credentials`, `client_id`, `client_secret`, optional `scope` (`partner-api` or `seller-api`).
2. The response has `access_token`, `refresh_token`, `expires_in`, `refresh_expires_in`, `token_type`, `scope`.
3. Send `Authorization: Bearer <access_token>` on every request.
4. Refresh with `grant_type=refresh_token` and the `refresh_token`.

Access tokens are short-lived ("typically 1 hour"); refresh tokens last "typically 30 days". All requests must use HTTPS; plain HTTP and unauthenticated calls fail. 

## Products & Customers API: JWT

1. `POST /auth/token` with `{"mpl": "<seller MPL>", "key": "<client key>"}` returns `access_token` and `refresh_token`.
2. Send `Authorization: Bearer <ACCESS_TOKEN>` on product and customer calls.
3. `POST /auth/refresh` with `refresh_token` in the body and headers `PayMe-Partner-Key` and `PayMe-Merchant-Key` returns a new `access_token` and `expires_in` (seconds).



> ⚠ TO CONFIRM: In Products & Customers `POST /auth/token`, is `key` the same value as `payme_client_key`? How long is the access token valid? [Q12]

## Keeping credentials secret

- Keep `seller_payme_id`, `payme_client_key`, the client password and `PayMe-Signature` on your **server**. Never put them in browser or mobile code, logs, or public repositories such as GitHub. 
- Only the public key belongs in browser code. The 3D Secure guide makes the same split: the browser call uses the public key, the hash-resolution call "should be called from your backend". 
- Store tokens securely, encrypted, and rotate credentials periodically. 

### If a key leaks

Contact PayMe support. PayMe can rotate a partner key or a seller ID without downtime — the old and new values both work until the switch — and can block a partner or deactivate a public key. There is no self-service endpoint for this.
