Verify a user in two calls: send a code to their email, then confirm the code. The second call returns the user access token.
Steps 1 and 2: verify a user through the API. You build the code screen. Two calls, with the partner key only. The second returns the user access token.
Read this diagram as text
- Your screen sends the user's email to your backend.
- Your backend calls POST /users/trigger-verification with external_ref and email.
- Flume emails the user a 6-digit code, valid for 10 minutes.
- The user types the code on your screen.
- Your screen sends the code to your backend.
- Your backend calls POST /users/confirm-verification with the email and the code.
- Flume returns the user access token, once.
- Your backend stores the token against that user and sends it on every call made for them.
Before you begin
Section titled “Before you begin”- A partner key. See Authentication and keys.
- A stable id for the user in your system. You send it as
external_ref.
1. Send the code
Section titled “1. Send the code”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" }}'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())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());{ "external_ref": "u_8812", "masked_email": "s···@example.com", "expires_in_s": 600, "resend_after_s": 30}- Only
external_refandemailare required. - Send the name, phone and firm if you have them. Flume puts them on the user's new Flume account.
phonemust be a US number.X-Flume-Client-IPis optional. Send the user's IP address in it and Flume also limits codes per IP address. See Users and verification.
Show the user a code box. Use masked_email to say where the code went.
2. Confirm the code
Section titled “2. Confirm the code”curl -X POST "https://sandbox-api.tryflume.ai/partner/v1/users/confirm-verification" \ -H "X-Flume-Partner-Key: $FLUME_PARTNER_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "sarah.chen@example.com", "code": "482913"}'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/confirm-verification", headers=headers, json={ "email": "sarah.chen@example.com", "code": "482913", }, timeout=30,)response.raise_for_status()print(response.json())const response = await fetch("https://sandbox-api.tryflume.ai/partner/v1/users/confirm-verification", { method: "POST", headers: { "X-Flume-Partner-Key": process.env.FLUME_PARTNER_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ "email": "sarah.chen@example.com", "code": "482913" }),});if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);console.log(await response.json());{ "external_ref": "u_8812", "email": "sarah.chen@example.com", "access_token": "ut_dev_acme_example_token", "token_type": "user_token", "verified_at": "2026-10-16T09:02:11Z", "account": "CREATED"}access_tokenis returned once. Store it encrypted, against the user.- A user has one working token at a time. This one replaces any earlier token.
accountisCREATEDfor a new Flume account, orLINKEDfor an existing one.- Send
external_refin the body only if two of your users share one email.
3. Use the token
Section titled “3. Use the token”Send it as X-Flume-User-Token, with your partner key, on every call made for the user.
curl "https://sandbox-api.tryflume.ai/partner/v1/products/7f3c2a91-4b0e-4c8d-9a21-1f6b2d5e7c30" \ -H "X-Flume-Partner-Key: $FLUME_PARTNER_KEY" \ -H "X-Flume-User-Token: $FLUME_USER_TOKEN"Handle the common errors
Section titled “Handle the common errors”| You get | Do this |
|---|---|
422 VERIFICATION_CODE_INVALID | Let the user try again. The message says how many tries are left |
422 VERIFICATION_TRIES_EXHAUSTED | Send a new code |
422 VERIFICATION_CODE_EXPIRED | Send a new code |
429 VERIFICATION_RATE_LIMITED | Wait Retry-After seconds, then resend |
502 VERIFICATION_EMAIL_FAILED | Retry the send |
404 NOT_FOUND on confirm | Call trigger-verification first |
Resend a code
Section titled “Resend a code”Call POST /users/trigger-verification again after resend_after_s seconds. The new code replaces the old one.
Revoke a token
Section titled “Revoke a token”Revoke when a user leaves or a token may have leaked.
curl -X DELETE "https://sandbox-api.tryflume.ai/partner/v1/users/u_8812/token" \ -H "X-Flume-Partner-Key: $FLUME_PARTNER_KEY"import os
import requests
headers = { "X-Flume-Partner-Key": os.environ["FLUME_PARTNER_KEY"],}
response = requests.delete( "https://sandbox-api.tryflume.ai/partner/v1/users/u_8812/token", headers=headers, timeout=30,)response.raise_for_status()print(response.status_code)const response = await fetch("https://sandbox-api.tryflume.ai/partner/v1/users/u_8812/token", { method: "DELETE", headers: { "X-Flume-Partner-Key": process.env.FLUME_PARTNER_KEY, },});if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);console.log(response.status);Response: 204. No body.
To give the user a new token, verify them again.
Test it
Section titled “Test it”The sandbox has no test code. Use an inbox you can read, and confirm with the code from the real email.