# Authentication

Payd uses API keys with HTTP Basic authentication. Each key belongs to one Payd account, and every request you make with it acts on that account.

## Create a key

1. Sign in to the [Payd app](https://app.payd.money).
2. Open **Settings**, then **API keys**.
3. Name the key after where you will use it, such as "Online shop", and create it.
4. Copy the **username** and **password** straight away. Payd shows the password once.

The app also shows an **API secret**. It works in place of the password, so keep it as safe as the password.

## Send the key with each request

Join the username and password with a colon, encode the result in Base64, and send it in the `Authorization` header:

```http
Authorization: Basic base64(username:password)
```

Most HTTP clients do this for you:

::: code-group

```bash [cURL]
curl https://api.payd.money/api/v2/payments/discovery/KE \
  -u "$PAYD_API_USERNAME:$PAYD_API_PASSWORD"
```

```js [Node.js]
const auth = Buffer.from(
  `${process.env.PAYD_API_USERNAME}:${process.env.PAYD_API_PASSWORD}`,
).toString('base64')

const res = await fetch('https://api.payd.money/api/v2/payments/discovery/KE', {
  headers: { Authorization: `Basic ${auth}` },
})
console.log(await res.json())
```

```python [Python]
import os
import requests

auth = (os.environ["PAYD_API_USERNAME"], os.environ["PAYD_API_PASSWORD"])
res = requests.get("https://api.payd.money/api/v2/payments/discovery/KE", auth=auth, timeout=30)
print(res.json())
```

```php [PHP]
<?php
$ch = curl_init('https://api.payd.money/api/v2/payments/discovery/KE');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERPWD => getenv('PAYD_API_USERNAME') . ':' . getenv('PAYD_API_PASSWORD'),
    CURLOPT_TIMEOUT => 30,
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
```

:::

## Find your account id

Payins, payouts and balance checks name the account they act on. Look up the account your key belongs to once, and keep it in your configuration:

```bash
curl https://api.payd.money/api/v2/api_keys/$PAYD_API_USERNAME \
  -u "$PAYD_API_USERNAME:$PAYD_API_PASSWORD"
```

```json
{
  "api_key": {
    "id": "0b6c5d0e-3c8f-4a59-9a64-0d5f2e7c1a33",
    "account_id": "4f28836c-2f1e-4d9b-9a51-6f3c2b1d8e70",
    "name": "Online shop",
    "username": "your_key_username",
    "user_id": "9e1d2f4a-6b7c-4d8e-9f01-2a3b4c5d6e7f"
  }
}
```

| Field | Meaning |
| --- | --- |
| `account_id` | The Payd account this key acts on. Send it as `vendor_config.account_id` on payins and payouts, and in the path of the balances endpoint. |
| `user_id` | The Payd user who created the key. |

The response also has `password` and `api_secret` fields. They are always empty here: Payd never sends your credentials back.

## When authentication fails

A missing or wrong key gets a `401` before Payd looks at the rest of the request:

```json
{
  "error_code": "user_unauthorized",
  "error_message": "API key validation failed",
  "status_code": 401,
  "request_id": "c38729b625825cd0"
}
```

`error_message` is `missing API key credentials` when the request has no `Authorization` header, and `API key validation failed` when the username or password is wrong.

If you send a key that works but name an account it does not belong to, you get `403` with `error_code` `permission_denied`. See [errors](./errors.md) for the full list.

## Keep keys safe

- Call the API only from your server. Never put a key in a web page, a mobile app or a public repository.
- Store keys in environment variables or a secrets manager, not in code.
- Use a separate key for each app or site, so you can replace one without touching the others.
- If a key leaks, create a new key, move your app to it, and email [support@paydhq.com](mailto:support@paydhq.com) to switch the old key off.
- Anyone with the key can move money out of the account, so limit who can read it.
