User Authentication
On this page
Request a one-time code by phone number or email, then exchange it at /auth/token for a user access token.
Learn how to get a TNID user access token to authenticate into the /user GraphQL API.
Users of TNID (as opposed to Companies) authenticate with a one-time code (OTP) delivered to their telephone number or email address.
Access tokens are valid for 7 days and refresh tokens for 30 days (see Refresh Token). There are no passwords to rotate; if a token is compromised, stop using it and request a new OTP.
Generate Your Access Token
The OTP endpoint is available in each environment:
| Environment | OTP endpoint |
|---|---|
| Staging | https://api.staging.v2.tnid.com/auth/create-user-otp |
| Zero (pre-production) | https://api.zero.v2.tnid.com/auth/create-user-otp |
The path is also accepted spelled /auth/create_user_otp.
Step 1. Make a request to /auth/create-user-otp with the telephone_number or email of an existing user. To create a new user, include the optional profile fields:
{
"telephone_number": "13024343433",
"first_name": "John",
"last_name": "Doe",
"email": "email@address.com"
}
The response tells you when the code expires and how many attempts remain:
{
"expires_at": "2026-01-15T09:00:01.000000Z",
"next_otp_at": "2026-01-15T09:00:00",
"otp_status": "OTP sent",
"remaining_otp_attempts": 5
}
Step 2. Make a request to /auth/token with the same telephone_number (or email) and the received otp_code:
{
"telephone_number": "13024343433",
"otp_code": "698125"
}
The response contains an access_token and a refresh_token. Use the access_token as Authorization: Bearer <access_token> to interact with the GraphQL API at /user.
Example Code
Python
import requests
BASE = "https://api.staging.v2.tnid.com"
HEADERS = {"Content-Type": "application/x-www-form-urlencoded"}
# Step one: request an OTP for an existing user. The user receives the code by SMS (or email if you pass "email").
def request_otp(user_phone_number):
response = requests.post(f"{BASE}/auth/create-user-otp", headers=HEADERS,
data={"telephone_number": user_phone_number})
if response.status_code != 200:
raise Exception(f"Failed to request OTP: {response.status_code} {response.text}")
print(f"OTP requested: {response.text}")
# Step two: exchange the OTP for tokens.
def get_bearer_token(user_phone_number, otp):
response = requests.post(f"{BASE}/auth/token", headers=HEADERS,
data={"telephone_number": user_phone_number, "otp_code": otp})
if response.status_code != 200:
raise Exception(f"Failed to retrieve token: {response.status_code} {response.text}")
return response.json().get("access_token")
# Creating a new user: same endpoint, with profile fields. Then request the OTP and token as above.
def create_new_user(phone_number, first_name, last_name, email):
response = requests.post(f"{BASE}/auth/create-user-otp", headers=HEADERS,
data={"telephone_number": phone_number, "first_name": first_name,
"last_name": last_name, "email": email})
if response.status_code != 200:
raise Exception(f"Failed to create new user: {response.status_code} {response.text}")
print(f"User created: {response.text}")
phone = "14075554530"
request_otp(phone)
otp = input("Enter the OTP you received: ")
print("Bearer Token:", get_bearer_token(phone, otp))
curl
curl -X POST https://api.staging.v2.tnid.com/auth/create-user-otp \
-H "Content-Type: application/json" \
-d '{"telephone_number":"14075554530"}'
curl -X POST https://api.staging.v2.tnid.com/auth/token \
-H "Content-Type: application/json" \
-d '{"telephone_number":"14075554530","otp_code":"698125"}'