# Users · Customers

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## POST /profile/customer/signin

**Customer sign in**

`operationId: UsersController_customerSignin`

Authenticates a customer. Customers are a separate population from users — a customer account does not grant access to the back office.

#### Signature

```http
POST /profile/customer/signin (body) -> Tokens and the customer
```

#### Access

Public — no credentials required.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | INVALID_CREDENTIALS | Invalid username or password | The identifier or password is wrong. | Deliberately does not distinguish an unknown account from a wrong password — do not surface a more specific message to the caller. |
| `403` | ACCOUNT_LOCKED | Account is locked. Please contact support. | The account has been locked, typically after repeated failed attempts. | An operator must unlock it. Retrying does not help. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signup`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `x-client-info` | header | string | — | Client context recorded against the attempt — used for device tracking and blocking. |

### Request body

Credentials.

```json
{
  "email": "ada@example.com",
  "password": "…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens and the customer |
| `400` | Invalid username or password — The identifier or password is wrong. |
| `403` | Account is locked. Please contact support. — The account has been locked, typically after repeated failed attempts. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/signin

**Customer sign in**

`operationId: UsersController_customerSignin`

Authenticates a customer. Customers are a separate population from users — a customer account does not grant access to the back office.

#### Signature

```http
POST /user/customer/signin (body) -> Tokens and the customer
```

#### Access

Public — no credentials required.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | INVALID_CREDENTIALS | Invalid username or password | The identifier or password is wrong. | Deliberately does not distinguish an unknown account from a wrong password — do not surface a more specific message to the caller. |
| `403` | ACCOUNT_LOCKED | Account is locked. Please contact support. | The account has been locked, typically after repeated failed attempts. | An operator must unlock it. Retrying does not help. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signup`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `x-client-info` | header | string | — | Client context recorded against the attempt — used for device tracking and blocking. |

### Request body

Credentials.

```json
{
  "email": "ada@example.com",
  "password": "…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens and the customer |
| `400` | Invalid username or password — The identifier or password is wrong. |
| `403` | Account is locked. Please contact support. — The account has been locked, typically after repeated failed attempts. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/shared-account

**Choose the account a customer buys for**

`operationId: UsersController_setSharedAccount`

Switches a signed-in customer between buying as themselves and buying for a shared account they are associated with (`data.sharedAccounts`). Returns the customer with a re-issued token pair carrying the choice — store them in place of the current ones. Send no `accountId` to go back to buying as themselves.

#### Signature

```http
POST /profile/customer/shared-account (body) -> { customer, token, refreshToken, orgId }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_SIGNED_IN | Not signed in | No customer session. | — |
| `403` | NOT_ASSOCIATED | You are not associated with this account | `accountId` is not one of the customer's shared accounts. | — |
| `404` | CUSTOMER_NOT_FOUND | Customer not found | The customer record is gone. | — |

Plus the standard platform errors: `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The shared account, or nothing.

```json
{
  "accountId": "acct_9k2m4h"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | { customer, token, refreshToken, orgId } |
| `401` | Not signed in — No customer session. |
| `403` | You are not associated with this account — `accountId` is not one of the customer's shared accounts. |
| `404` | Customer not found — The customer record is gone. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/shared-account

**Choose the account a customer buys for**

`operationId: UsersController_setSharedAccount`

Switches a signed-in customer between buying as themselves and buying for a shared account they are associated with (`data.sharedAccounts`). Returns the customer with a re-issued token pair carrying the choice — store them in place of the current ones. Send no `accountId` to go back to buying as themselves.

#### Signature

```http
POST /user/customer/shared-account (body) -> { customer, token, refreshToken, orgId }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `401` | NOT_SIGNED_IN | Not signed in | No customer session. | — |
| `403` | NOT_ASSOCIATED | You are not associated with this account | `accountId` is not one of the customer's shared accounts. | — |
| `404` | CUSTOMER_NOT_FOUND | Customer not found | The customer record is gone. | — |

Plus the standard platform errors: `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The shared account, or nothing.

```json
{
  "accountId": "acct_9k2m4h"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | { customer, token, refreshToken, orgId } |
| `401` | Not signed in — No customer session. |
| `403` | You are not associated with this account — `accountId` is not one of the customer's shared accounts. |
| `404` | Customer not found — The customer record is gone. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/dashboard/auth/{authOrgId}

**Authenticate a customer for a dashboard**

`operationId: UsersController_customerDashboardAuth`

Authenticates a customer against another organization's dashboard — the cross-org hop for a shared portal.

#### Signature

```http
POST /profile/customer/dashboard/auth/{authOrgId} (authOrgId: string, body) -> Tokens for that organization
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /customer/signin`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `authOrgId` | path | string | yes | Organization to authenticate against. |

### Request body

Auth context.

```json
{}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens for that organization |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/dashboard/auth/{authOrgId}

**Authenticate a customer for a dashboard**

`operationId: UsersController_customerDashboardAuth`

Authenticates a customer against another organization's dashboard — the cross-org hop for a shared portal.

#### Signature

```http
POST /user/customer/dashboard/auth/{authOrgId} (authOrgId: string, body) -> Tokens for that organization
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /customer/signin`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `authOrgId` | path | string | yes | Organization to authenticate against. |

### Request body

Auth context.

```json
{}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens for that organization |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/signup

**Customer sign up**

`operationId: UsersController_customerSignup`

Registers a customer account.

#### Signature

```http
POST /profile/customer/signup (body) -> The created customer
```

#### Access

Public — no credentials required.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | CUSTOMER_EXISTS | A customer with this email already exists in the organization | The email is already registered as a customer. | Sign in instead. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signin`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The account to create.

```json
{
  "email": "ada@example.com",
  "password": "…",
  "firstName": "Ada"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created customer |
| `400` | A customer with this email already exists in the organization — The email is already registered as a customer. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/signup

**Customer sign up**

`operationId: UsersController_customerSignup`

Registers a customer account.

#### Signature

```http
POST /user/customer/signup (body) -> The created customer
```

#### Access

Public — no credentials required.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | CUSTOMER_EXISTS | A customer with this email already exists in the organization | The email is already registered as a customer. | Sign in instead. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signin`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The account to create.

```json
{
  "email": "ada@example.com",
  "password": "…",
  "firstName": "Ada"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created customer |
| `400` | A customer with this email already exists in the organization — The email is already registered as a customer. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/refresh

**Refresh a customer token**

`operationId: UsersController_customerRefreshToken`

Exchanges a customer refresh token for a new access token.

#### Signature

```http
POST /profile/customer/refresh (body) -> New tokens
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signin`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The refresh token.

```json
{
  "refreshToken": "eyJhbGciOi…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | New tokens |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/refresh

**Refresh a customer token**

`operationId: UsersController_customerRefreshToken`

Exchanges a customer refresh token for a new access token.

#### Signature

```http
POST /user/customer/refresh (body) -> New tokens
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signin`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The refresh token.

```json
{
  "refreshToken": "eyJhbGciOi…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | New tokens |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/subscribe

**Subscribe a customer**

`operationId: UsersController_customerSubscribe`

Records a customer opting in to marketing. Capture what they consented to — see the promotions endpoints, which store the consent text.

#### Signature

```http
POST /profile/customer/subscribe (body) -> The result
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /crm/promotions/{name}/subscribe`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The subscription.

```json
{
  "email": "ada@example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/subscribe

**Subscribe a customer**

`operationId: UsersController_customerSubscribe`

Records a customer opting in to marketing. Capture what they consented to — see the promotions endpoints, which store the consent text.

#### Signature

```http
POST /user/customer/subscribe (body) -> The result
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /crm/promotions/{name}/subscribe`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The subscription.

```json
{
  "email": "ada@example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/unsubscribe

**Unsubscribe a customer**

`operationId: UsersController_customerUnsubscribe`

Records a customer opting out. Honour it promptly and completely.

#### Signature

```http
POST /profile/customer/unsubscribe (body) -> The result
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/subscribe`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The unsubscribe request.

```json
{
  "email": "ada@example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/unsubscribe

**Unsubscribe a customer**

`operationId: UsersController_customerUnsubscribe`

Records a customer opting out. Honour it promptly and completely.

#### Signature

```http
POST /user/customer/unsubscribe (body) -> The result
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/subscribe`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The unsubscribe request.

```json
{
  "email": "ada@example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/update

**Update a customer**

`operationId: UsersController_customerUpdate`

Updates a customer record.

#### Signature

```http
POST /profile/customer/update (body) -> The updated customer
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /customer/profile/{emailOrUsername}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The customer to update.

```json
{
  "email": "ada@example.com",
  "firstName": "Ada"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated customer |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/update

**Update a customer**

`operationId: UsersController_customerUpdate`

Updates a customer record.

#### Signature

```http
POST /user/customer/update (body) -> The updated customer
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /customer/profile/{emailOrUsername}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The customer to update.

```json
{
  "email": "ada@example.com",
  "firstName": "Ada"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated customer |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/password/change

**Change a customer password**

`operationId: UsersController_customerPasswordChange`

Changes a customer's password, requiring the current one.

#### Signature

```http
POST /profile/customer/password/change (body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /customer/password/reset`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `x-client-info` | header | string | — | Client context recorded against the attempt — used for device tracking and blocking. |

### Request body

Current and new password.

```json
{
  "currentPassword": "…",
  "newPassword": "…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/password/change

**Change a customer password**

`operationId: UsersController_customerPasswordChange`

Changes a customer's password, requiring the current one.

#### Signature

```http
POST /user/customer/password/change (body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /customer/password/reset`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `x-client-info` | header | string | — | Client context recorded against the attempt — used for device tracking and blocking. |

### Request body

Current and new password.

```json
{
  "currentPassword": "…",
  "newPassword": "…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/password/reset

**Reset a customer password**

`operationId: UsersController_customerPasswordReset`

Sets a new customer password using a reset token.

#### Signature

```http
POST /profile/customer/password/reset (body) -> The result
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/password/validate-token`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `x-client-info` | header | string | — | Client context recorded against the attempt — used for device tracking and blocking. |

### Request body

Token and new password.

```json
{
  "token": "rst_9k2m4h1p7q",
  "newPassword": "…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/password/reset

**Reset a customer password**

`operationId: UsersController_customerPasswordReset`

Sets a new customer password using a reset token.

#### Signature

```http
POST /user/customer/password/reset (body) -> The result
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/password/validate-token`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `x-client-info` | header | string | — | Client context recorded against the attempt — used for device tracking and blocking. |

### Request body

Token and new password.

```json
{
  "token": "rst_9k2m4h1p7q",
  "newPassword": "…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/password/validate-token

**Validate a customer reset token**

`operationId: UsersController_customerValidateResetToken`

Checks a customer reset token before showing the reset form.

#### Signature

```http
POST /profile/customer/password/validate-token (body) -> Whether the token is valid
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/password/reset`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The token.

```json
{
  "token": "rst_9k2m4h1p7q"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Whether the token is valid |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/password/validate-token

**Validate a customer reset token**

`operationId: UsersController_customerValidateResetToken`

Checks a customer reset token before showing the reset form.

#### Signature

```http
POST /user/customer/password/validate-token (body) -> Whether the token is valid
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/password/reset`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The token.

```json
{
  "token": "rst_9k2m4h1p7q"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Whether the token is valid |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/social-login

**Validate a customer social login**

`operationId: UsersController_customerValidateSocialLobin`

Completes a social sign-in for a customer across providers.

#### Signature

```http
POST /profile/customer/social-login (body) -> Tokens and the customer
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/google/token`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The provider and its token.

```json
{
  "provider": "google",
  "accessToken": "ya29…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens and the customer |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/social-login

**Validate a customer social login**

`operationId: UsersController_customerValidateSocialLobin`

Completes a social sign-in for a customer across providers.

#### Signature

```http
POST /user/customer/social-login (body) -> Tokens and the customer
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/google/token`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The provider and its token.

```json
{
  "provider": "google",
  "accessToken": "ya29…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens and the customer |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /profile/customer/password/forgot/{email}/{redirectUrl}

**Request a customer password reset**

`operationId: UsersController_customerPasswordForgot`

Sends a customer a reset link, returning them to the supplied URL. **Validate `redirectUrl` against an allowlist** — an unchecked redirect in a password-reset email is a phishing vector.

#### Signature

```http
GET /profile/customer/password/forgot/{email}/{redirectUrl} (email: string, redirectUrl: string) -> The request result
```

#### Access

Public — no credentials required.

#### Notes

- An open redirect here lands in a trusted email. Restrict the accepted hosts.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/password/reset`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `email` | path | string | yes | Email address. |
| `redirectUrl` | path | string | yes | Where to return the customer after reset. |
| `strategy` | query | string | yes |  |
| `password` | query | string | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The request result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /user/customer/password/forgot/{email}/{redirectUrl}

**Request a customer password reset**

`operationId: UsersController_customerPasswordForgot`

Sends a customer a reset link, returning them to the supplied URL. **Validate `redirectUrl` against an allowlist** — an unchecked redirect in a password-reset email is a phishing vector.

#### Signature

```http
GET /user/customer/password/forgot/{email}/{redirectUrl} (email: string, redirectUrl: string) -> The request result
```

#### Access

Public — no credentials required.

#### Notes

- An open redirect here lands in a trusted email. Restrict the accepted hosts.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/password/reset`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `email` | path | string | yes | Email address. |
| `redirectUrl` | path | string | yes | Where to return the customer after reset. |
| `strategy` | query | string | yes |  |
| `password` | query | string | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The request result |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /profile/customers/{attr}/{value}

**Find customers by attribute**

`operationId: UsersController_customers`

Finds customers matching an attribute and value.

#### Signature

```http
GET /profile/customers/{attr}/{value} (attr: string, value: string) -> Matching customers
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /customer/profile/{emailOrUsername}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `attr` | path | string | yes | Attribute to match. |
| `value` | path | string | yes | Value to match. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Matching customers |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /user/customers/{attr}/{value}

**Find customers by attribute**

`operationId: UsersController_customers`

Finds customers matching an attribute and value.

#### Signature

```http
GET /user/customers/{attr}/{value} (attr: string, value: string) -> Matching customers
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /customer/profile/{emailOrUsername}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `attr` | path | string | yes | Attribute to match. |
| `value` | path | string | yes | Value to match. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Matching customers |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /profile/customer/exist/{emailOrUsername}

**Check whether a customer exists**

`operationId: UsersController_customerExist`

Reports whether a customer account exists. This confirms account existence to an unauthenticated caller — rate-limit anything built on it.

#### Signature

```http
GET /profile/customer/exist/{emailOrUsername} (emailOrUsername: string) -> Whether the customer exists
```

#### Access

Public — no credentials required.

#### Notes

- An enumeration surface by design — treat it accordingly.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signup`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `emailOrUsername` | path | string | yes | Email address or username. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Whether the customer exists |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /user/customer/exist/{emailOrUsername}

**Check whether a customer exists**

`operationId: UsersController_customerExist`

Reports whether a customer account exists. This confirms account existence to an unauthenticated caller — rate-limit anything built on it.

#### Signature

```http
GET /user/customer/exist/{emailOrUsername} (emailOrUsername: string) -> Whether the customer exists
```

#### Access

Public — no credentials required.

#### Notes

- An enumeration surface by design — treat it accordingly.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/signup`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `emailOrUsername` | path | string | yes | Email address or username. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Whether the customer exists |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /profile/customer/profile/{emailOrUsername}

**Get a customer profile**

`operationId: UsersController_customerProfile`

Fetches a customer profile by email or username.

#### Signature

```http
GET /profile/customer/profile/{emailOrUsername} (emailOrUsername: string) -> The customer profile
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /customer/update`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `emailOrUsername` | path | string | yes | Email address or username. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The customer profile |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /profile/customer/profile/{emailOrUsername}

**Delete a customer**

`operationId: UsersController_deleteCustomer`

Deletes a customer account properly — the endpoint the generic repository delete points at rather than dropping the row.

#### Signature

```http
DELETE /profile/customer/profile/{emailOrUsername} (emailOrUsername: string) -> Deletion result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `DELETE /repository/delete/{datatype}/{id}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `emailOrUsername` | path | string | yes | Email address or username. |
| `reason` | query | string | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Deletion result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /user/customer/profile/{emailOrUsername}

**Get a customer profile**

`operationId: UsersController_customerProfile`

Fetches a customer profile by email or username.

#### Signature

```http
GET /user/customer/profile/{emailOrUsername} (emailOrUsername: string) -> The customer profile
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /customer/update`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `emailOrUsername` | path | string | yes | Email address or username. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The customer profile |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /user/customer/profile/{emailOrUsername}

**Delete a customer**

`operationId: UsersController_deleteCustomer`

Deletes a customer account properly — the endpoint the generic repository delete points at rather than dropping the row.

#### Signature

```http
DELETE /user/customer/profile/{emailOrUsername} (emailOrUsername: string) -> Deletion result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `DELETE /repository/delete/{datatype}/{id}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `emailOrUsername` | path | string | yes | Email address or username. |
| `reason` | query | string | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Deletion result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /profile/customer/self

**Delete my customer account**

`operationId: UsersController_deleteSelfCustomer`

Deletes the calling customer's own account. Irreversible.

#### Signature

```http
DELETE /profile/customer/self () -> Deletion result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `DELETE /customer/profile/{emailOrUsername}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Deletion result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /user/customer/self

**Delete my customer account**

`operationId: UsersController_deleteSelfCustomer`

Deletes the calling customer's own account. Irreversible.

#### Signature

```http
DELETE /user/customer/self () -> Deletion result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `DELETE /customer/profile/{emailOrUsername}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Deletion result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /profile/customer/google/token

**Exchange a Google token for a customer**

`operationId: UsersController_customerGoogleTokenExchange`

Exchanges a Google token for customer tokens — the native-app sign-in path.

#### Signature

```http
POST /profile/customer/google/token (body) -> Tokens and the customer
```

#### Access

Public — no credentials required.

#### Notes

- Verify the token with Google rather than trusting the client.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/social-login`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The provider token.

```json
{
  "idToken": "eyJhbGciOi…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens and the customer |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /user/customer/google/token

**Exchange a Google token for a customer**

`operationId: UsersController_customerGoogleTokenExchange`

Exchanges a Google token for customer tokens — the native-app sign-in path.

#### Signature

```http
POST /user/customer/google/token (body) -> Tokens and the customer
```

#### Access

Public — no credentials required.

#### Notes

- Verify the token with Google rather than trusting the client.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /customer/social-login`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The provider token.

```json
{
  "idToken": "eyJhbGciOi…"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Tokens and the customer |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

