Auth1 API Documentation
Everything you need to integrate Auth1 into your application. SMS OTP, Email Magic Links, VOIP detection, risk scoring, and more.
Quick Start
Get up and running with Auth1 in under five minutes. Install the SDK, configure your API key, and send your first verification.
1. Install the SDK
npm install @auth1/sdk
yarn add @auth1/sdk
pnpm add @auth1/sdk
2. Initialize and Verify
import Auth1 from '@auth1/sdk';
// Initialize with your API key
const auth = new Auth1({
apiKey: 'auth1_pk_...'
});
// Send a verification to the user
const result = await auth.verify('user@example.com', '+18005551234');
// result includes VOIP detection + risk score
console.log(result.isVoip); // false
console.log(result.riskScore); // 0.12
Authentication
All API requests require an API key passed in the x-api-key header. You can generate keys from your Auth1 Dashboard.
x-api-key: auth1_pk_YOUR_API_KEY
Content-Type: application/json
Key Types
| Prefix | Type | Description |
|---|---|---|
| auth1_pk_ | string | Production key. Full API access, rate limits applied per your plan. |
| auth1_sk_ | string | Secret key. Used for server-side webhook signature verification only. Never expose client-side. |
| auth1_test_ | string | Test key. Simulates API responses without sending real SMS/emails. Free and unlimited. |
auth1_sk_ secret key in client-side code or public repositories. Use environment variables on the server.SMS OTP
Send a one-time verification code via SMS. Auth1 automatically detects VOIP numbers and calculates a fraud risk score before delivery.
Headers
| Header | Type | Description |
|---|---|---|
| x-api-key required | string | Your Auth1 API key |
| Content-Type required | string | application/json |
Request Body
| Parameter | Type | Description |
|---|---|---|
| phone required | string | E.164 format phone number (e.g., +18005551234) |
| email required | string | User's email address for identity binding |
| tenant required | string | Your tenant identifier |
Response 200 OK
| Field | Type | Description |
|---|---|---|
| phoneVerificationId | string | UUID to pass to the verify endpoint |
| phoneType | string | Carrier-detected type: mobile, landline, or voip |
| isVoip | boolean | true if VOIP number detected |
| riskScore | number | Fraud risk score from 0.0 (safe) to 1.0 (high risk) |
| message | string | Human-readable status message |
| provider | string | Delivery provider used (twilio or sns) |
curl -X POST https://auth-api.z101.ai/api/auth/sms/request \
-H "Content-Type: application/json" \
-H "x-api-key: auth1_pk_YOUR_KEY" \
-d '{
"phone": "+18005551234",
"email": "user@example.com",
"tenant": "your-tenant"
}'
const res = await fetch('https://auth-api.z101.ai/api/auth/sms/request', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'auth1_pk_YOUR_KEY'
},
body: JSON.stringify({
phone: '+18005551234',
email: 'user@example.com',
tenant: 'your-tenant'
})
});
const data = await res.json();
console.log(data.phoneVerificationId); // uuid
console.log(data.isVoip); // false
console.log(data.riskScore); // 0.12
import requests
resp = requests.post(
"https://auth-api.z101.ai/api/auth/sms/request",
headers={
"Content-Type": "application/json",
"x-api-key": "auth1_pk_YOUR_KEY"
},
json={
"phone": "+18005551234",
"email": "user@example.com",
"tenant": "your-tenant"
}
)
data = resp.json()
print(data["phoneVerificationId"]) # uuid
print(data["isVoip"]) # False
print(data["riskScore"]) # 0.12
Example Response
{
"phoneVerificationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"phoneType": "mobile",
"isVoip": false,
"riskScore": 0.12,
"message": "Verification code sent",
"provider": "twilio"
}
Email Magic Link
Send a passwordless magic link to the user's email. When clicked, the user is redirected to your callback URL with a verification token.
Headers
| Header | Type | Description |
|---|---|---|
| x-api-key required | string | Your Auth1 API key |
| Content-Type required | string | application/json |
Request Body
| Parameter | Type | Description |
|---|---|---|
| email required | string | Recipient email address |
| callbackUrl required | string | URL to redirect the user after clicking the magic link. A token query parameter is appended. |
Response 200 OK
| Field | Type | Description |
|---|---|---|
| success | boolean | true if the email was sent |
| message | string | Status message |
curl -X POST https://auth-api.z101.ai/api/auth/sms/magic-link/request \
-H "Content-Type: application/json" \
-H "x-api-key: auth1_pk_YOUR_KEY" \
-d '{
"email": "user@example.com",
"callbackUrl": "https://yourapp.com/auth/callback"
}'
const res = await fetch('https://auth-api.z101.ai/api/auth/sms/magic-link/request', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'auth1_pk_YOUR_KEY'
},
body: JSON.stringify({
email: 'user@example.com',
callbackUrl: 'https://yourapp.com/auth/callback'
})
});
resp = requests.post(
"https://auth-api.z101.ai/api/auth/sms/magic-link/request",
headers={
"Content-Type": "application/json",
"x-api-key": "auth1_pk_YOUR_KEY"
},
json={
"email": "user@example.com",
"callbackUrl": "https://yourapp.com/auth/callback"
}
)
Example Response
{
"success": true,
"message": "Magic link sent"
}
Verify Code
Verify the 6-digit OTP code entered by the user. On success, returns a JWT session token and refresh token.
Request Body
| Parameter | Type | Description |
|---|---|---|
| phoneVerificationId required | string | UUID returned from the SMS OTP request |
| verificationCode required | string | 6-digit code entered by the user |
| email required | string | Email used in the original SMS request |
Response 200 OK
| Field | Type | Description |
|---|---|---|
| user | object | Contains id, phone, and email |
| token | string | JWT access token (expires in 1 hour) |
| refreshToken | string | Refresh token (expires in 30 days) |
curl -X POST https://auth-api.z101.ai/api/auth/sms/verify \
-H "Content-Type: application/json" \
-H "x-api-key: auth1_pk_YOUR_KEY" \
-d '{
"phoneVerificationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"verificationCode": "123456",
"email": "user@example.com"
}'
const res = await fetch('https://auth-api.z101.ai/api/auth/sms/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'auth1_pk_YOUR_KEY'
},
body: JSON.stringify({
phoneVerificationId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
verificationCode: '123456',
email: 'user@example.com'
})
});
const { user, token, refreshToken } = await res.json();
resp = requests.post(
"https://auth-api.z101.ai/api/auth/sms/verify",
headers={
"Content-Type": "application/json",
"x-api-key": "auth1_pk_YOUR_KEY"
},
json={
"phoneVerificationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"verificationCode": "123456",
"email": "user@example.com"
}
)
data = resp.json()
token = data["token"]
Example Response
{
"user": {
"id": "usr_abc123",
"phone": "+18005551234",
"email": "user@example.com"
},
"token": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "rt_d4e5f6a7b8c9..."
}
Session Management
After verification, use these endpoints to manage user sessions. All session endpoints require a Bearer token in the Authorization header.
Get Current Session
| Header | Description |
|---|---|
| Authorization required | Bearer <token> from the verify response |
curl https://auth-api.z101.ai/api/auth/session \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Refresh Token
| Parameter | Type | Description |
|---|---|---|
| refreshToken required | string | The refresh token received from verify or a previous refresh |
curl -X POST https://auth-api.z101.ai/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "rt_d4e5f6a7b8c9..." }'
Logout
| Header | Description |
|---|---|
| Authorization required | Bearer <token> - Invalidates the session server-side |
curl -X POST https://auth-api.z101.ai/api/auth/logout \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Webhooks
Auth1 sends real-time HTTP POST notifications to your configured webhook URL when authentication events occur. Configure webhooks in your Dashboard under Settings.
Events
- user.created Fired when a new user record is created during their first verification.
- user.verified Fired when a user successfully completes OTP or magic link verification.
- login.success Fired on every successful authentication (includes returning users).
- login.failed Fired when verification fails (wrong code, expired code, max attempts).
- fraud.detected Fired when a VOIP number is blocked or risk score exceeds your threshold.
Payload Format
{
"id": "evt_a1b2c3d4e5f6",
"event": "user.verified",
"timestamp": "2026-03-23T14:30:00Z",
"data": {
"userId": "usr_abc123",
"email": "user@example.com",
"phone": "+18005551234",
"method": "sms_otp",
"riskScore": 0.12,
"isVoip": false,
"ip": "203.0.113.42"
}
}
Signature Verification
Every webhook request includes an x-auth1-signature header containing an HMAC-SHA256 signature of the raw request body, signed with your auth1_sk_ secret key. Always verify this signature before processing.
import { createHmac } from 'crypto';
function verifyWebhook(body, signature, secret) {
const expected = createHmac('sha256', secret)
.update(body)
.digest('hex');
return expected === signature;
}
// In your Express handler:
app.post('/webhooks/auth1', (req, res) => {
const sig = req.headers['x-auth1-signature'];
if (!verifyWebhook(req.rawBody, sig, process.env.AUTH1_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process the event...
res.sendStatus(200);
});
2xx status within 10 seconds. Auth1 retries failed deliveries with exponential backoff up to 3 times over 24 hours.VOIP Detection
Auth1 automatically classifies every phone number before sending an OTP. VOIP numbers (Google Voice, TextNow, Burner, etc.) are flagged in real-time, letting you block or challenge suspicious signups.
How It Works
- Every SMS request checks the phone number against carrier databases and proprietary heuristics.
- The
phoneTypefield returnsmobile,landline, orvoip. - The
isVoipboolean provides a quick check for conditional logic. - By default, VOIP numbers are allowed but flagged. Configure blocking rules in your Dashboard.
Configuration Options
| Setting | Default | Description |
|---|---|---|
| voipAction | flag |
flag = allow but mark, block = reject with error, challenge = require additional verification |
| voipBlockMessage | null |
Custom error message shown when a VOIP number is blocked |
| allowedVoipProviders | [] |
Whitelist specific VOIP providers (e.g., ["vonage_business"]) |
carrierInfo response field.Risk Scoring
Auth1 assigns a fraud risk score (0.0 to 1.0) to every authentication attempt. The score combines multiple signals in real-time.
Score Breakdown
| Range | Risk Level | Recommended Action |
|---|---|---|
| 0.0 - 0.3 | Low | Allow through. Legitimate user. |
| 0.3 - 0.6 | Medium | Allow but monitor. Consider additional verification for sensitive actions. |
| 0.6 - 0.8 | High | Challenge the user with a secondary factor or manual review. |
| 0.8 - 1.0 | Critical | Block the attempt. Very likely fraudulent. |
Signals Used
- Phone type -- VOIP, prepaid, and landline numbers increase the score.
- Velocity -- Multiple attempts from the same IP or phone in a short window.
- Geolocation mismatch -- IP country vs. phone country code discrepancy.
- Known fraud patterns -- Number ranges and IPs associated with prior abuse across all Auth1 tenants.
- Device fingerprint -- Browser/device anomalies when using the client-side SDK.
Custom Branding
Personalize SMS messages, emails, and magic link pages with your company branding. Configure in the Dashboard or via the API.
SMS Templates
Customize the OTP message text. Use the {{code}} placeholder for the verification code and {{appName}} for your tenant's display name.
Your {{appName}} verification code is {{code}}. Expires in 10 minutes.
Email Branding
- Logo URL -- Displayed in the magic link email header.
- Primary color -- Applied to buttons and accents in the email template.
- From name -- The sender name shown in the user's inbox (e.g., "YourApp Security").
- Reply-to -- Where user replies go.
SDKs
Official client libraries for the most popular platforms. All SDKs include TypeScript definitions and handle retries, error mapping, and token refresh automatically.
Node.js
Server-side SDK for Express, Fastify, Next.js, and any Node runtime.
Python
Works with Django, Flask, FastAPI. Python 3.8+ required.
React
Drop-in components: <Auth1Provider>, <VerifyForm>, and useAuth1() hook.
Node.js Example
import Auth1 from '@auth1/sdk';
const auth = new Auth1({
apiKey: process.env.AUTH1_API_KEY,
tenant: 'your-tenant'
});
// Send OTP
const { phoneVerificationId, isVoip, riskScore } =
await auth.sms.send({
phone: '+18005551234',
email: 'user@example.com'
});
// Verify code
const session = await auth.sms.verify({
phoneVerificationId,
code: '123456',
email: 'user@example.com'
});
console.log(session.token); // JWT access token
Python Example
from auth1 import Auth1Client
client = Auth1Client(
api_key="auth1_pk_YOUR_KEY",
tenant="your-tenant"
)
# Send OTP
result = client.sms.send(
phone="+18005551234",
email="user@example.com"
)
print(result.is_voip) # False
print(result.risk_score) # 0.12
# Verify code
session = client.sms.verify(
phone_verification_id=result.phone_verification_id,
code="123456",
email="user@example.com"
)
React Example
import { Auth1Provider, VerifyForm, useAuth1 } from '@auth1/react';
function App() {
return (
<Auth1Provider apiKey="auth1_pk_...">
<VerifyForm
onSuccess={(session) => console.log('Verified!', session)}
onVoipDetected={() => alert('VOIP numbers not allowed')}
/>
</Auth1Provider>
);
}
// Or use the hook directly:
function CustomLogin() {
const { sendOTP, verifyCode, loading, session } = useAuth1();
// Build your own UI...
}
Error Codes
All errors return a JSON body with error (machine-readable code) and message (human-readable description). HTTP status codes follow REST conventions.
{
"error": "CODE_EXPIRED",
"message": "Verification code has expired. Please request a new one.",
"statusCode": 400
}
| Code | HTTP | Description |
|---|---|---|
| VALIDATION_APIKEY_NOTFOUND | 401 | The x-api-key header is missing or the key does not exist. |
| VALIDATION_APIKEY_INACTIVE | 403 | API key has been deactivated. Reactivate in your Dashboard. |
| VOIP_NOT_ALLOWED | 403 | The phone number was identified as VOIP and your policy is set to block. |
| INVALID_PHONE | 400 | Phone number is not in valid E.164 format. |
| INVALID_EMAIL | 400 | Email address is malformed or empty. |
| CODE_EXPIRED | 400 | Verification code has expired (10-minute TTL). Request a new one. |
| CODE_INVALID | 400 | Verification code does not match. |
| TOO_MANY_ATTEMPTS | 429 | Maximum verification attempts exceeded for this code. Request a new one. |
| SMS_DELIVERY_FAILED | 502 | SMS could not be delivered by either provider (Twilio + SNS). Phone may be invalid or unreachable. |
| RATE_LIMIT_EXCEEDED | 429 | You have exceeded the per-minute or per-hour rate limit. See Rate Limits. |
| TOKEN_EXPIRED | 401 | JWT access token has expired. Use the refresh token to obtain a new one. |
| TOKEN_INVALID | 401 | JWT is malformed or signature verification failed. |
| INTERNAL_ERROR | 500 | An unexpected server error occurred. Contact support if persistent. |
Rate Limits
Auth1 enforces rate limits to protect service quality and prevent abuse. Limits vary by endpoint and plan.
Rate Limit Headers
Every response includes rate limit headers so you can proactively manage your usage:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed in the current window |
| X-RateLimit-Remaining | Requests remaining in the current window |
| X-RateLimit-Reset | Unix timestamp when the window resets |
429 Response
When a rate limit is exceeded, you receive a 429 Too Many Requests response:
{
"error": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please retry after 42 seconds.",
"retryAfter": 42,
"statusCode": 429
}