---
title: "Send a verification code"
description: "POST /users/trigger-verification: Emails a 6-digit verification code to a user."
url: https://docs.tryflume.ai/api/trigger-verification
updated: 2026-11-11
---

# Send a verification code

> POST /users/trigger-verification: Emails a 6-digit verification code to a user.

Emails a 6-digit verification code to a user.

```http
POST https://sandbox-api.tryflume.ai/partner/v1/users/trigger-verification
```

- Send `external_ref`, your permanent id for the user, and `email`.
- The code is valid for 10 minutes.
- No account or token exists until the code is confirmed.
- Call again to resend after `resend_after_s` seconds, or to update the user's details.
- Send the user's IP address as `X-Flume-Client-IP`. Flume then also limits codes per IP address.
- Codes count against a daily limit per partner.

## Request

### Headers

| Header | Required | Description |
|---|---|---|
| `X-Flume-Partner-Key` | Yes | Your partner key. |
| `X-Flume-Client-IP` | No | The user's own IP address: one IPv4 or IPv6 address. When sent, Flume also limits codes per IP address. Without it, only the limits per mailbox apply. |

### Body (`application/json`)

| Field | Type | Required | Description |
|---|---|---|---|
| `external_ref` | string | Yes | Your permanent id for the user. 1 to 128 characters. |
| `email` | string | Yes | Where the code goes. It is also the user's Flume sign-in address. Max 320 characters. Pattern `^[^@\s]+@[^@\s]+\.[^@\s]+$`. |
| `first_name` | string or null | No | The user's first name. Max 128 characters. |
| `last_name` | string or null | No | The user's last name. Max 128 characters. |
| `phone` | string or null | No | A US phone number, in any common format. Max 32 characters. |
| `org` | object or null | No | The firm the user works at. |
| `org.external_ref` | string or null | No | Your id for the firm. Max 128 characters. |
| `org.name` | string or null | No | The firm's name. Max 255 characters. |
| `org.website_domain` | string or null | No | The firm's website domain. Max 255 characters. |
| `method` | enum | No | How the user proves their email. `email_code` is the only method today. Default `"email_code"`. |

### Sample

**curl**

```sh
curl -X POST "https://sandbox-api.tryflume.ai/partner/v1/users/trigger-verification" \
  -H "X-Flume-Partner-Key: $FLUME_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "external_ref": "u_8812",
  "email": "sarah.chen@example.com",
  "first_name": "Sarah",
  "last_name": "Chen",
  "org": {
    "name": "NY Design Co"
  }
}'
```

**Python**

```python
import os

import requests

headers = {
    "X-Flume-Partner-Key": os.environ["FLUME_PARTNER_KEY"],
}

response = requests.post(
    "https://sandbox-api.tryflume.ai/partner/v1/users/trigger-verification",
    headers=headers,
    json={
        "external_ref": "u_8812",
        "email": "sarah.chen@example.com",
        "first_name": "Sarah",
        "last_name": "Chen",
        "org": {
            "name": "NY Design Co",
        },
    },
    timeout=30,
)
response.raise_for_status()
print(response.json())
```

**Node.js**

```js
const response = await fetch("https://sandbox-api.tryflume.ai/partner/v1/users/trigger-verification", {
  method: "POST",
  headers: {
    "X-Flume-Partner-Key": process.env.FLUME_PARTNER_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "external_ref": "u_8812",
    "email": "sarah.chen@example.com",
    "first_name": "Sarah",
    "last_name": "Chen",
    "org": {
      "name": "NY Design Co"
    }
  }),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
console.log(await response.json());
```

## Returns (202)

Every field is always present. A field with no value is `null`.

| Field | Type | Description |
|---|---|---|
| `external_ref` | string | Your id for the user. |
| `masked_email` | string | The address the code went to, masked. Safe to show the user. |
| `expires_in_s` | integer | How long the code is valid, in seconds. |
| `resend_after_s` | integer | How long to wait before you ask for another code for this user, in seconds. |

**Response (202)**

```json
{
  "external_ref": "u_8812",
  "masked_email": "s···@example.com",
  "expires_in_s": 600,
  "resend_after_s": 30
}
```

## Errors

| Status | Code | Meaning |
|---|---|---|
| 401 | `EMBED_TOKEN_INVALID` | You sent an `Authorization` header and no `X-Flume-Partner-Key`. Flume read the call as one from its own iframe. |
| 401 | `PARTNER_KEY_INVALID` | The partner key is missing, unknown, revoked, expired, or from the other environment. On live, also a platform Flume has not enabled yet. |
| 401 | `USER_TOKEN_INVALID` | The user access token is unknown, revoked, another partner's, or replaced by a later verification. A verification in the iframe replaces it too. |
| 422 | `USER_ACCOUNT_CLOSED` | The user's email belongs to a Flume account that Flume has closed. |
| 422 | `VALIDATION_FAILED` | A field is missing, unknown or has an unusable value. `field` names it as a dotted path. Some refusals carry the detail in `details` and leave `field` empty. |
| 429 | `RATE_LIMITED` | Today's limit for this call is used up. `Retry-After` is the number of seconds until 00:00 UTC. |
| 429 | `VERIFICATION_RATE_LIMITED` | A resend came too soon, or the mailbox reached its limit. When you send `X-Flume-Client-IP`, the limit per IP address applies too. |
| 500 | `INTERNAL` | Something failed on Flume's side. |
| 502 | `VERIFICATION_EMAIL_FAILED` | The email could not be sent. |

Every code, with its fix: [API error codes](https://docs.tryflume.ai/api/errors.md).

Guide: [Verify a user](https://docs.tryflume.ai/guides/verify-a-user.md).
