# Bulk update premium currency from CSV

Upload a CSV that adds to, subtracts from or sets many traders' premium currency balances in one background job.

- Endpoint: `POST https://api.returning.ai/v1/users/bulk-update-premium-currency`
- Section: Users and data / Bulk operations
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `bulkUpdateUser` (Shown in the dashboard as "Bulk Update User")
- Retries: No Idempotency-Key; check API Logs before retrying
- Guide: hand-written
- Verified: live, 2026-09-27
- Last updated: 26 Sep 2026
- Web page: https://docs.returning.ai/api-reference/bulk-operations/bulk-update-premium-currency-from-csv

## When to use this

- A monthly campaign on your platform awards premium currency to a list of traders.
- You correct premium currency balances for several traders after a support review.
- You move premium currency balances over from another system when you launch.

**Instead:** Use [Bulk update users from CSV](https://docs.returning.ai/api-reference/bulk-operations/bulk-update-users-from-csv.md) instead to change coins, XP, roles or custom fields. This endpoint only changes premium currency.

**Queued, not applied:** A `200` means the file is saved and the job is queued. It returns no job ID, and the job doesn't appear in List bulk update jobs; follow it in the dashboard under Settings > Integration > API Logs.

## Authentication

- Header: `Authorization: Bearer <API_KEY>`
- Permission: `bulkUpdateUser`

Uploading needs `bulkUpdateUser`, shown in the dashboard as Bulk Update User, the same permission as Bulk update users from CSV. Every row is limited to traders in the key's community. Keep the key on your server.

## Behaviour

The upload only queues a job. Queued premium currency jobs run one at a time, oldest first. The job reads the whole file, checks every row, then applies the valid rows. It ends as `completed`, even when some rows failed, or as `failed` when the file as a whole was rejected. The API can't read these jobs: they aren't in [List bulk update jobs](https://docs.returning.ai/api-reference/bulk-operations/list-bulk-update-jobs.md), and the upload returns no job ID. Follow the job in the dashboard under Settings > Integration > API Logs. A finished job records how many rows succeeded and failed; a failed job records why the file was rejected.

The file as a whole is rejected, and nothing is applied, when `Email` or `Premium Currency` is missing from the header row, or the header row has any other column. A file with no data rows completes with nothing applied.

A row fails on its own, and the other rows still apply, when:

- `Email` is empty, or the same email appears in an earlier row. Only the first row for each email is used.
- `Premium Currency` is empty or not a number.
- `Premium Currency_op` isn't `add`, `subtract` or `overwrite`.
- No trader in your community has that email.

Premium currency changes don't appear in the `total_coins` field history, and the API has no read for a trader's premium currency balance.

## Request

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | Community API key with `bulkUpdateUser`. (`Bearer <API_KEY>`) |

### Body

Send `multipart/form-data` with the file in field `data`, and optionally `log_name`. Columns are separated by commas, and the first line must be the header row.

```csv
Email,Premium Currency,Premium Currency_op
trader@example.com,500,add
```

- Spell the headers exactly: `Email`, `Premium Currency` and, optionally, `Premium Currency_op`.
- Rows are matched by `Email`, not case-sensitive.
- `add` adds the amount and is the default when the operator column or cell is empty. `subtract` takes it away but never goes below 0. `overwrite` sets the balance to the amount.
- The file can be up to 30 MB.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `data` | `file` | Yes | The CSV file, with a header row and one row per trader. The form field must be named `data`. (`.csv` name or `text/csv` type; max 30 MB) |
| `log_name` | `string` | No | A name for this job. Make it unique so you can find the job in API Logs. |

Send the body as `multipart/form-data`.

### Example request

```bash
curl --request POST \
  --url https://api.returning.ai/v1/users/bulk-update-premium-currency \
  --header 'Authorization: Bearer <API_KEY>' \
  --form 'data=@premium-currency.csv' \
  --form 'log_name=Premium top-up 2026-09-27'
```

## Response

A `200` returns only a confirmation that the job is queued. It has no job ID, so use a unique `log_name` and look for it in API Logs.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `status` | `string` | always | Result of the request. (`success`) |
| `message` | `string` | always | Human-readable summary. Do not branch on it. |
| `data` | `object` | always | A short confirmation. |
| `data.message` | `string` | always | Human-readable confirmation that the job is queued. |

### Example response (200)

```json
{
  "status": "success",
  "message": "Bulk update premium currency process is queued",
  "data": {
    "message": "Bulk update premium currency process is queued. You can check in Api Log ( community settings )"
  }
}
```

## Errors

Errors from the API key check, such as 401 and 403, carry the code in `meta.code`. Other errors from this endpoint have no `code`, so branch on the HTTP status. Problems inside the file never cause an error here; they show up in the job's result in API Logs.

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | - | There is no `code`, so read `message`: - `A CSV file must be provided`: no file arrived. JSON bodies aren't accepted; send the file as multipart form field `data`. - `Uploaded file must be a CSV`: give the file a `.csv` name or a `text/csv` type. |
| 401 | `AUTHENTICATION_REQUIRED` | The key is missing, invalid or expired. Send `Authorization: Bearer <API_KEY>` with a current key. |
| 403 | `API_KEY_PERMISSION_DENIED` | The key is valid but lacks `bulkUpdateUser`, or it is a personal key. Use a Community API key and add the permission in Settings > Integration > API Keys. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 404 | `COMMUNITY_NOT_FOUND` | The key's community no longer exists. Use a key from an active community. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 500 | - | A JSON `500` means no job was created; retry with backoff. A `500` error page without JSON means the file is over 30 MB or was sent under a form field other than `data`; fix the upload instead. |
| 500 | `AUTHENTICATION_FAILED` | The key could not be checked. Retry the same request with backoff. |

**Retries:** This endpoint does not accept an `Idempotency-Key`. Each upload creates a new job, and running the same file twice applies `add` and `subtract` twice. After a timeout, check API Logs for your `log_name` before you upload again. Over the [rate limit](https://docs.returning.ai/how-it-works.md#rate-limits), requests return `429`; wait for the window to reset, then retry.

## Next step

- [Bulk update users from CSV](https://docs.returning.ai/api-reference/bulk-operations/bulk-update-users-from-csv.md): `POST /v1/users/bulk-update`. Use the user CSV upload for coins, XP, roles or custom fields in the same run.
- [Check a trader's record with Get User Data](https://docs.returning.ai/api-reference/users/get-user-data.md): `POST /v1/users/info`.
