# Create a user

Canonical page: https://docs.ovok.com/signals/standalone/api/clients/create-a-user

{/* Generated from the API Explorer document by scripts/generate-signals-api-pages.mjs. Edit ovok-core, not this page. */}


# Create a user [#create-a-user]

| Method | Path |
| --- | --- |
| `POST` | `/v1/signals/api/user` |

<Availability route="POST /v1/signals/api/user" />

Mints an API client. `clientId` and `secret` are the Basic credential, chosen by the caller and never returned. `role` may be v1's lowercase. A SUBSCRIBER needs `webhookUrl` and at least one event. It is on `eventSchema` 2 unless the body says 1: on 2 its first Standard Webhooks signing secret is returned this once as `signingSecret`; on 1 it needs `webhookSecret` (v1 called it `secret`). `reach` is `attached` (default: the patients attached to it, as v1's) or `all` (every patient of the tenant, those enrolled later included).

### Through ovok [#through-ovok]

- **Who can call it:** Manager apps, and users whose access policy grants the capabilities.
- **Capabilities, all required:** `signals_webhooks:update`, `signals_events:read`. Project admins have every capability; client applications get no admin bypass.
- Only subscribers are created through ovok, on event schema 2. ovok generates their id and Signals login, which they never use, and Signals generates the webhook signing secret.
- It can reach any patient of your project without naming one, so it is for callers that reach every patient: project admins, manager or submitter apps, and anyone whose Patient access has no criteria.

## Request [#request]

### Body [#body]

Required.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `role` | `SUBSCRIBER` | Yes | Validated against the assignable roles rather than the full enum, so this MANAGER-gated route cannot mint a cross-tenant SUPER_ADMIN credential. |
| `name` | string | No | — |
| `webhookUrl` | string | No | — |
| `events` | array of string | No | — |
| `custom` | string | No | v1's `custom`: an opaque string every webhook carries back as `x-actimi-custom`. |
| `eventSchema` | `2` | No | 1 keeps v1's event names and bodies; 2, the default, sends one name per state change. |
| `reach` | `attached`, `all` | No | `attached`: the patients attached to it, as v1's; `all`: every patient of the tenant, later ones included. |

## Responses [#responses]

| Status | Meaning |
| --- | --- |
| `201` | The user, without its secret; `Location` names it. |
| `400` | The query carries a raw `#`, or more than 200 parameters. |
| `401` | Your ovok access token, or your client id and secret, are missing or invalid. |
| `403` | ovok refused the call: you lack a capability this route needs, or your session has no project, or `role` is not `SUBSCRIBER`, or your access covers only some patients. From Signals: Authenticated, but the client's role does not permit this, or it is not attached to the patient. Or: `FEATURE_DISABLED`: `events` names an episode event, and the tenant has `episodicAlerts` off, so it records none. |
| `409` | Your project has no Signals tenant of its own (`SIGNALS_TENANT_NOT_OWN`), or it is moving to another one. From Signals: The `clientId` is taken. |
| `415` | The body is not JSON. |
| `422` | `role` is missing, `clientId`, `secret` or `webhookSecret` was sent, or `eventSchema` is not 2. From Signals: The payload failed validation. `EVENTS_NOT_IN_SCHEMA`: `events` names a type its `eventSchema` never sends, such as `alert.trigger` on schema 2. |
| `429` | Too many requests. Retry after the seconds in `Retry-After`. |
| `500` | ovok hit an unexpected fault, such as your project having no Signals submitter. |
| `502` | Signals answered with something ovok couldn't use, or refused ovok's own credential. |
| `503` | Signals is unavailable. Retry after the seconds in `Retry-After`. |
| `504` | Signals did not answer in time. |

## Example [#example]

```bash
curl --request POST 'https://api.sandbox.ovok.com/v1/signals/api/user' \
  --user "${OVOK_CLIENT_ID}:${OVOK_CLIENT_SECRET}" \
  --header 'Content-Type: application/json' \
  --data @body.json
```
