Authentication & User Management Authentication methods, user CRUD, getting started patterns
Authentication Methods
All authenticated endpoints require: Authorization: Bearer {token}
The token can be a JWT (from Basic Auth or OAuth), an API key, or a 2FA-upgraded JWT.
Method 1: Basic Auth to JWT
Send HTTP Basic Auth (email:password) to get a JWT.
/current/user/auth/
Authorization: Basic {base64(email:password)}
Returns auth_token (JWT). If the account has 2FA enabled, the returned token has limited scope until 2FA verification is completed.
Method 2: API Keys
Long-lived tokens for service-to-service communication. Created via the API or the web UI. Used with the same Authorization: Bearer {api_key} header format as JWTs.
Method 3: OAuth 2.0 PKCE
For desktop/mobile apps and MCP-connected agents. No password passes through the agent. Access tokens last 1 hour, refresh tokens 30 days. S256 challenge method only. See the OAuth 2.0 reference for the full flow.
Method 4: 2FA
When 2FA is enabled on an account, Basic Auth returns a limited-scope JWT. Complete authentication via POST /current/user/auth/2factor/auth/{token}/ with the 2FA code. The response contains a full-scope JWT.
Getting Started
Option 1: Use a Human's Existing Account (API Key)
A human creates an API key and gives it to you. You operate as that user with their permissions, org, and billing.
Human instructions: "Go to Settings > Devices & Agents > API Keys and click Create API Key. Optionally enter a memo to label the key (e.g., 'Agent access'), then click Create. Copy the key immediately -- it is only displayed once. Direct link: https://go.fast.io/settings/api-keys"
Once you have the key: Authorization: Bearer {api_key}. No further steps needed.
Option 2: Create Your Own Agent Account (Autonomous)
Create your own account to work independently.
POST /current/user/withemail_address,password,tos_agree=true,agent=trueGET /current/user/auth/with Basic Auth to get JWT- Verify email:
POST /current/user/email/validate/withemail— sends verification codePOST /current/user/email/validate/withemailandemail_token— validates the code
POST /current/org/create/withdomain(required, 2-80 chars lowercase alphanumeric + hyphens)POST /current/org/{org_id}/create/workspace/withfolder_name,name,perm_join,perm_member_manage
Agent accounts get the agent plan: free, 50 GB storage, 5,000 credits/month, no expiration.
Option 3: Agent Account Invited to a Human's Org
- Create an agent account (steps 1-2 from Option 2)
- Give the human your agent's email address
- Human invites agent to their org or workspace
- Accept:
POST /current/org/{org_id}/members/join/orPOST /current/workspace/{workspace_id}/members/join/ - You now operate within their resources with granted permissions
Option 4: PKCE Browser Login (No Password Sharing)
Most secure option. Works with SSO. No credentials pass through the agent.
- Agent initiates PKCE flow via
POST /current/oauth/authorize/withcode_challenge,code_challenge_method=S256,client_id,redirect_uri,response_type=code - User opens the returned URL in browser, signs in, approves access
- Browser displays authorization code — user copies it to agent
- Agent calls
POST /current/oauth/token/withgrant_type=authorization_code,code,code_verifier - Access tokens last 1 hour; refresh via
POST /current/oauth/token/withgrant_type=refresh_token
Which option to choose
- Human wants you to manage their account → Option 1 (API key)
- You're building something independently → Option 2 (agent account + own org)
- You need to work within a human's existing org → Option 3 (agent account + invitation)
- Human wants to authorize agent without sharing credentials → Option 4 (PKCE)
User Creation
POST /current/user/
Create a new user account.
Auth: None (IP-throttled)
Rate Limits: 5 per minute, 10 per hour, 20 per day (by IP)
Request Parameters
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
| email_address | string | Yes | Valid email format; domain must accept email; must be unique | User's email address. Tags (e.g., +tag) are stripped for storage and uniqueness checks, but the original is preserved. |
| password | string | Yes | Must pass password validity checks | Account password. |
| tos_agree | string | Yes | Must be "true" |
Must be "true" to accept Terms of Service. |
| agent | string | No | "true" or "false" |
Set "true" for AI agent accounts. Sets account_type to "agent" permanently. Agent accounts skip email validation and use the agent plan. |
| first_name | string | No | Must pass name validation | User's given/first name. |
| last_name | string | No | Must pass name validation | User's family/last name. |
| phone_country | string | No | Numeric country calling code | Phone country code. Required if phone_number is provided. |
| phone_number | string | No | Numeric phone number | Phone number. Required if phone_country is provided. |
Request Example
curl -X POST "https://api.fast.io/current/user/" \
-d "email_address=jane.doe@example.com" \
-d "password=SecureP@ss123" \
-d "tos_agree=true" \
-d "first_name=Jane" \
-d "last_name=Doe" \
-d "agent=true"
Success Response (200 OK)
{
"result": "yes",
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| result | string | "yes" on success |
| current_api_version | string | API version ("1.0") |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid email was supplied." | Email format invalid |
APP_ERROR_INPUT_INVALID (1605) | 400 | "The email domain is invalid or cannot receive email." | Email domain validation failed |
APP_ERROR_INPUT_INVALID (1605) | 400 | "The email supplied is already in use." | Email already registered (after normalization) |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid password was supplied." | Password does not meet requirements |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid tos_agree value was create." | TOS value not a valid boolean string |
APP_ERROR_INPUT_INVALID (1605) | 400 | "You declined to accept the terms of service." | TOS set to "false" |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid first name was supplied to create." | First name fails validation |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid last name was supplied to create." | Last name fails validation |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid phone country code was supplied." | Invalid phone country code |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid phone number was supplied." | Invalid phone number |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid phone number or country code was supplied." | Full phone number validation failed |
APP_DENIED (1680) | 403 | "Your attempt to create an account was not accepted." | Risk/fraud check failed |
APP_INTERNAL_ERROR (1600) | 500 | "We were unable to create your user account..." | Internal commit failure |
Notes
- Email addresses are normalized by stripping tag extensions (e.g.,
user+tag@example.combecomesuser@example.com) for storage and uniqueness lookup; the original email is preserved separately. - Country code is detected from the client IP and stored automatically.
agent=trueis permanent and cannot be changed after account creation.- Agent accounts skip email validation requirements and can authenticate immediately.
User Management Endpoints
POST /current/user/update/
Update the current authenticated user's profile information.
Auth: Required (JWT)
Rate Limits: 1 per 3s, 2 per 10s, 5 per minute, 20 per hour, 100 per day (by user)
Request Parameters
All fields are optional. Only provided fields are updated.
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
| email_address | string | No | Valid email format; unique; domain must accept email | New email address. Resets email verification status. |
| password | string | No | Must pass validity checks | New password. |
| first_name | string | No | Must pass name validation | Updated given/first name. |
| last_name | string | No | Must pass name validation | Updated family/last name. |
| phone_country | string | No | Numeric country code; 2FA must be disabled first | Updated phone country code. Pass "null" or empty to clear. |
| phone_number | string | No | Numeric phone number; 2FA must be disabled first | Updated phone number. Pass "null" or empty to clear. |
| owner_defined | string (JSON) | No | Must be valid JSON if provided | Custom owner-defined properties. Pass null or empty to clear. |
Request Example
curl -X POST "https://api.fast.io/current/user/update/" \
-H "Authorization: Bearer {jwt_token}" \
-d "first_name=Jane" \
-d "last_name=Smith"
Success Response (200 OK)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid email was supplied to update." | Invalid email format |
APP_ERROR_INPUT_INVALID (1605) | 400 | "The email domain is invalid or cannot receive email." | Invalid email domain |
APP_CONFLICT (1608) | 409 | "There email you specified is not available." | Email already in use |
APP_RESTRICTED (1681) | 403 | "You must disable 2-Factor before updating your phone." | 2FA enabled when trying to change phone |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid password was supplied to update." | Invalid password |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid first name was supplied to update." | Invalid first name |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid last name was supplied to update." | Invalid last name |
APP_ERROR_INPUT_INVALID (1605) | 400 | "Owner-defined properties must be valid JSON." | Invalid JSON in owner_defined |
Notes
- Changing the email address resets email verification status.
- Phone number changes require 2FA to be disabled first.
- If no fields have changed, the endpoint returns success with no database update.
POST /current/user/close/
Close (soft-delete) the current user's account.
Auth: Required (JWT)
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| email_address | string | Yes | Must match the user's current email address (confirmation). |
| dryrun | string | No | If truthy, checks eligibility without closing the account. |
Request Example
curl -X POST "https://api.fast.io/current/user/close/" \
-H "Authorization: Bearer {jwt_token}" \
-d "email_address=jane.doe@example.com"
Success Response (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Dry Run Response (Cannot Close, 202 Accepted)
{
"result": "no",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_USER_NOT_FOUND (1653) | 404 | "User not found to close." | User object invalid |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid email was supplied to close account." | Invalid email format |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An incorrect email was supplied to close account." | Email does not match user's email |
APP_ERROR_INPUT_INVALID (1605) | 400 | "Cannot close user account that owns active organizations..." | User owns active organizations |
Notes
- 2FA verification is required if 2FA is enabled on the account.
- Users who own active organizations must close or transfer ownership first.
- The
dryrunparameter checks closure eligibility without actually closing the account. - On closure: subscriptions are cancelled, SSO connections are removed, the account is flagged as closed.
POST /current/user/email/
Check if an email address is already in use.
Auth: None (IP-throttled)
Rate Limits: 50 per 30s, 500 per day (by IP)
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | Yes | Email address to check availability. |
Request Example
curl -X POST "https://api.fast.io/current/user/email/" \
-d "email=jane.doe@example.com"
Email Available (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Email In Use (406 Not Acceptable)
{
"result": "no",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "You provided an invalid email to check." | Invalid email format or missing |
Notes
- The email is normalized (tags stripped) before lookup.
result: "yes"= available,result: "no"= already in use.
POST /current/user/email/reset/
Request a password reset email.
Auth: None (IP-throttled)
Rate Limits: 2 per 2s, 10 per 10 minutes (by IP)
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | Yes | Email address of the account. |
Request Example
curl -X POST "https://api.fast.io/current/user/email/reset/" \
-d "email=jane.doe@example.com"
Success Response (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "You provided an invalid email to check." | Invalid email format |
APP_INTERNAL_ERROR (1600) | 500 | "We were unable to send a verification email." | Email send failure |
Notes
- For security, this endpoint always returns success regardless of whether the email exists in the system.
POST /current/user/email/validate/
Send or validate an email verification code. Two-step flow.
Auth: Required (JWT)
Rate Limits: 1 per 3s, 2 per 10s, 5 per minute, 20 per hour, 100 per day (by user)
Mode 1: Send Verification Code
When email_token is NOT provided, sends a new validation code to the user's email.
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | Yes | Must match the authenticated user's email address. |
Mode 2: Validate Code
When email_token IS provided, validates the code and marks the email as verified.
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | Yes | Must match the authenticated user's email address. | |
| email_token | string | Yes | Verification code received via email. |
Request Example (Send Code)
curl -X POST "https://api.fast.io/current/user/email/validate/" \
-H "Authorization: Bearer {jwt_token}" \
-d "email=jane.doe@example.com"
Request Example (Validate Code)
curl -X POST "https://api.fast.io/current/user/email/validate/" \
-H "Authorization: Bearer {jwt_token}" \
-d "email=jane.doe@example.com" \
-d "email_token=123456"
Success Response (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_AUTH_INVALID (1650) | 401 | "Your credentials were not supplied or invalid." | User not authenticated |
APP_NOT_ACCEPTABLE (1606) | 406 | "Your email address is already verified." | Email already verified |
APP_CONFLICT (1608) | 409 | "Your credentials do not match the email you provided." | Email mismatch with authenticated user |
APP_NOT_ACCEPTABLE (1606) | 406 | "You provided an invalid or expired token to validate email." | Invalid or expired code |
APP_DENIED (1680) | 403 | "Provided code has expired, get a new code and try again." | Code expired |
POST /current/user/password/{code}/
Set a new password using a password reset code.
Auth: None (code-based authentication)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {code} | string | Yes | Password reset code from the reset email. |
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| password1 | string | Yes | New password. |
| password2 | string | Yes | New password confirmation. Must match password1. |
Request Example
curl -X POST "https://api.fast.io/current/user/password/abc123def456/" \
-d "password1=NewSecureP@ss" \
-d "password2=NewSecureP@ss"
Success Response (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_DENIED (1680) | 403 | "An invalid code was provided, cannot reset password." | Invalid code format |
APP_DENIED (1680) | 403 | "Provided code was not found or expired, cannot reset password." | Code not found or wrong type |
APP_DENIED (1680) | 403 | "Provided code has expired, get a new code and try again." | Code expired |
APP_CONFLICT (1608) | 409 | "Provided code belongs to another user account and cannot be used." | Code/user mismatch |
APP_MISSING (1609) | 404 | "The provided code belongs to an invalid user." | User not found for code |
APP_CONFLICT (1608) | 409 | "The provided passwords don't match." | password1 and password2 differ |
APP_NOT_ACCEPTABLE (1606) | 406 | "Both password fields must be provided and match." | Missing password fields |
APP_INTERNAL_ERROR (1600) | 500 | "The provided password could not be processed..." | Encryption failure |
Notes
- The reset code is consumed (deleted) after successful password change.
- A new JWT is created after the password is set.
GET /current/user/password/{code}/details/
Get details of a password reset code (check if valid/expired).
Auth: None (code-based)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {code} | string | Yes | Password reset code to check. |
Request Example
curl -X GET "https://api.fast.io/current/user/password/abc123def456/details/"
Success Response (200 OK)
{
"result": "yes",
"response": {
"email": "jane.doe@example.com"
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.email | string | The email address associated with the reset code. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_DENIED (1680) | 403 | "An invalid code was provided, cannot reset password." | Invalid code format |
APP_DENIED (1680) | 403 | "Provided code was not found or expired, cannot reset password." | Code not found |
APP_DENIED (1680) | 403 | "Provided code has expired, get a new code and try again." | Code expired |
APP_CONFLICT (1608) | 409 | "Provided code belongs to another user account..." | Code/user mismatch |
APP_LOCKED (1682) | 423 | "The account has been restricted and cannot be updated." | Account locked/suspended/closed |
GET /current/user/phone/{country_code}-{phone_number}/
Validate a phone number and country code combination.
Auth: Required (JWT)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {country_code}-{phone_number} | string | Yes | Country code and phone number separated by a hyphen (e.g., 1-5551234567). |
Request Example
curl -X GET "https://api.fast.io/current/user/phone/1-5551234567/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "You provided an invalid phone number to check." | Invalid format |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid phone country code was supplied." | Invalid country code |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid phone number was supplied." | Invalid phone number |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid phone number or country code was supplied." | Full number validation failed |
GET /current/user/pin/
Get the user's support PIN and identity verification hash.
Auth: Required (JWT)
Request Example
curl -X GET "https://api.fast.io/current/user/pin/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"supportcode": "1234",
"intercom": "a1b2c3d4e5f6..."
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.supportcode | string | 4-digit support PIN. Defaults to "0000" if not set. |
| response.intercom | string | HMAC-SHA256 identity verification hash. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_USER_NOT_FOUND (1653) | 404 | "Unable to fetch the user details." | User not found |
APP_INTERNAL_ERROR (1600) | 500 | "Internal temporary error, please try again later." | Failed to load credentials |
GET|POST /current/user/sso/signin/{provider}/
SSO (Single Sign-On) authentication flow.
Auth: None (IP-throttled)
Rate Limits: 30 per 5s, 60 per 30s, 600 per 5 minutes (by IP)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {provider} | string | Yes | SSO provider name: google, apple, or microsoft. |
GET: Get SSO Redirect URL
Returns the OAuth2 authorization URL for the specified provider.
curl -X GET "https://api.fast.io/current/user/sso/signin/google/"
GET Response (200 OK)
{
"result": "yes",
"response": {
"provider": "google",
"redirect_url": "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=...",
"return_url": "https://fast.io/sso/callback/google"
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.provider | string | The provider name. |
| response.redirect_url | string | URL to redirect the user to for SSO authentication. |
| response.return_url | string | Callback URL the provider will redirect back to. |
POST: Process SSO Callback
Processes the OAuth2 callback with the authorization code from the provider.
| Parameter | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | Authorization code from the SSO provider. |
| state | string | Yes | State token for CSRF protection. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid provider name was supplied." | Invalid provider name format |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An unknown provider name was supplied." | Provider not in allowed list |
APP_ERROR_INPUT_INVALID (1605) | 400 | "Cookies must be enabled and passed to this API." | Missing state cookie |
APP_DENIED (1680) | 403 | "Permission was not granted by the provider." | OAuth error returned from provider |
APP_SSO_ERROR_AUTH (1690) | 401 | "Invalid or missing input in a required field was received." | Missing code or state |
Notes
- Supported providers:
google,apple,microsoft. - GET generates a state token (requires cookies) and returns the redirect URL.
- POST exchanges the authorization code for tokens and creates/links the user account.
GET /current/user/assets/
List available user asset metadata types (e.g., profile photo specifications).
Auth: None
Request Example
curl -X GET "https://api.fast.io/current/user/assets/"
Notes
- Returns the schema/specifications for available asset types, not actual assets.
GET /current/user/available_profiles/
Check what profile types (orgs, workspaces, shares) the current user has access to.
Auth: Required (JWT)
Request Example
curl -X GET "https://api.fast.io/current/user/available_profiles/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"has_orgs": true,
"has_workspaces": true,
"has_shares": false
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.has_orgs | boolean | Whether the user has access to any organizations. |
| response.has_workspaces | boolean | Whether the user has access to any workspaces. |
| response.has_shares | boolean | Whether the user has access to any shares. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_USER_NOT_FOUND (1653) | 404 | "Unable to fetch the user details." | User not found |
GET /current/user/{user_id}/details/
Get user profile details.
Auth: Required (JWT)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {user_id} | string | No | 20-digit user ID. If omitted, returns the current user's details. |
Request Example
curl -X GET "https://api.fast.io/current/user/1234567890123456789/details/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"user": {
"id": "12345678901234567890",
"account_type": "human",
"email_address": "jane.doe@example.com",
"first_name": "Jane",
"last_name": "Doe",
"locked": false,
"profile_pic": "https://assets.fast.io/..."
}
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.user.id | string | 20-digit user ID. |
| response.user.account_type | string | "human" or "agent". |
| response.user.email_address | string | User's email address. |
| response.user.first_name | string | Given name. |
| response.user.last_name | string | Family name. |
| response.user.locked | boolean | Whether the account is locked. |
| response.user.profile_pic | string | Profile photo URL. |
Self-Only Fields (included only when viewing your own profile)
| Field | Type | Description |
|---|---|---|
| 2factor | boolean | Whether 2FA is enabled. |
| closed | boolean | Whether the account is closed. |
| country_code | string | Country of residence. |
| created | string | Registration date. |
| phone_country | string | Phone country code. |
| phone_number | string | Phone number. |
| suspended | boolean | Suspension status. |
| tos_agree | string | ToS agreement date. |
| updated | string | Last profile update time. |
| valid_email | boolean | Email verified status. |
| valid_phone | boolean | Phone verified status. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_USER_NOT_FOUND (1653) | 404 | "Unable to fetch the user details." | User not found |
GET /current/user/me/autosync/{state}/
Enable or disable profile photo auto-synchronization from SSO providers.
Auth: Required (JWT)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {state} | string | Yes | "enable" or "disable". |
Request Example
curl -X GET "https://api.fast.io/current/user/me/autosync/enable/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_DATASTORE (1600) | 500 | "There was an internal error processing your request..." | Commit failure |
GET /current/user/me/allowed/
Check if the user's country (based on IP geolocation) allows creating shares or organizations.
Auth: None (IP-throttled)
Rate Limits: 100 per minute, 1000 per day (by IP)
Request Example
curl -X GET "https://api.fast.io/current/user/me/allowed/"
Success Response (200 OK)
{
"result": "yes",
"response": {
"allowed": true
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.allowed | boolean | Whether the user's location allows resource creation. |
| response.reasons | array | Array of blocked reason strings. Only present when allowed is false. |
GET /current/user/me/limits/orgs/
Check free organization creation eligibility.
Auth: Required (JWT)
Rate Limits: 60 per minute, 1000 per day (by IP and user)
Request Example
curl -X GET "https://api.fast.io/current/user/me/limits/orgs/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"can_create_free_org": true,
"existing_free_orgs": 0,
"cooldown_remaining": 0,
"max_free_orgs": 1
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.can_create_free_org | boolean | Whether the user can create a free organization. |
| response.existing_free_orgs | integer | Number of existing free organizations owned by the user. |
| response.cooldown_remaining | integer | Seconds remaining before next creation is allowed. |
| response.max_free_orgs | integer | Maximum number of free organizations allowed. |
| response.reason | string | Reason creation is not allowed. Only present when can_create_free_org is false. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_USER_NOT_FOUND (1653) | 404 | "Unable to fetch the user." | User not found |
GET /current/user/me/list/shares/
List all shares accessible to the current user.
Auth: Required (JWT)
Rate Limits: 100 per minute, 1500 per hour, 5000 per day (by user)
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| archived | string | No | "false" |
"true" to show archived shares, "false" to show non-archived. |
Request Example
curl -X GET "https://api.fast.io/current/user/me/list/shares/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"shares": [
{
"id": "12345678901234567890",
"name": "Project Files",
"type": "send",
"archived": false
}
]
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.shares | array | Array of share resource objects. Each includes parent workspace and org info. |
Notes
- Shares are gathered from three sources: owned by the user, invited to, and joined.
- Duplicates are removed by share ID.
- Does NOT include shares from workspaces the user has access to — only shares with direct user relationships.
GET /current/user/{user_id}/assets/
List set assets (e.g., profile photo) for a user.
Auth: Required (JWT)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {user_id} | string | Yes | 20-digit numeric user ID. |
Request Example
curl -X GET "https://api.fast.io/current/user/12345678901234567890/assets/" \
-H "Authorization: Bearer {jwt_token}"
POST|DELETE /current/user/{user_id}/assets/{asset_name}/
Upload or delete a user asset.
Auth: Required (JWT)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {user_id} | string | Yes | 20-digit numeric user ID. |
| {asset_name} | string | Yes | Asset type name (e.g., profile_pic). |
POST: Upload Asset
Multipart form data with exactly one file upload.
| Parameter | Type | Required | Description |
|---|---|---|---|
| (file) | file | Yes | The asset file. Exactly one file must be included. |
| metadata | array | No | Optional metadata. Must be a valid array if provided. |
DELETE: Delete Asset
No request body required.
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_REQUEST_TYPE (1651) | 400 | "Only user may modify." | Non-owner attempting to modify |
APP_POST_FILE_MISSING (1604) | 400 | "Asset upload missing" | No file in POST request |
APP_ERROR_INPUT_INVALID (1605) | 400 | "metadata invalid" | Invalid metadata parameter |
Notes
- Only the user themselves can modify their own assets.
- Uploading or deleting disables profile photo auto-sync.
GET|HEAD /current/user/{user_id}/assets/{asset_name}/read/
Read the binary content of a user asset.
Auth: Required (JWT)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {user_id} | string | Yes | 20-digit numeric user ID. |
| {asset_name} | string | Yes | Asset type name (e.g., profile_pic). |
Notes
- Returns raw binary bytes with appropriate content-type headers, not JSON.
- HEAD returns headers only.
Invitations
GET /current/user/invitation/{invitation_id}/details/
Get details for a specific invitation.
Auth: Required (JWT)
Rate Limits: 10 per minute, 20 per 10 minutes, 30 per hour (by user)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {invitation_id} | string | Yes | Invitation ID (numeric) or invitation key (alphanumeric). |
Request Example
curl -X GET "https://api.fast.io/current/user/invitation/12345678901234567890/details/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"invitation": {
"id": "12345678901234567890",
"entity": "98765432101234567890",
"state": "pending",
"email": "jane.doe@example.com"
},
"owner": {
"id": "11111111111111111111",
"account_type": "human",
"email_address": "admin@example.com",
"first_name": "Admin",
"last_name": "User",
"profile_pic": "https://assets.fast.io/..."
},
"org": {
"id": "22222222222222222222",
"name": "Example Org"
}
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.invitation | object | Invitation resource. |
| response.owner | object | User resource of the profile owner. |
| response.org | object or null | Org resource if the invitation is for an org-owned entity. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid invitation ID was supplied." | Invalid ID format |
APP_ERROR_INPUT_INVALID (1605) | 400 | "Invitation not found." | Invitation does not exist |
APP_INTERNAL_ERROR (1600) | 500 | "Failed to load the invitation profile or its owner." | Profile or owner load failure |
GET /current/user/invitation/{invitation_id}/public/details/
Get public details for an invitation without authentication.
Auth: None (IP-throttled)
Rate Limits: 15 per 10s, 100 per hour, 500 per day (by IP)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {invitation_id} | string | Yes | Invitation ID (numeric) or invitation key (alphanumeric). |
Request Example
curl -X GET "https://api.fast.io/current/user/invitation/12345678901234567890/public/details/"
Success Response (200 OK)
{
"result": "yes",
"response": {
"invitation": {
"id": "12345678901234567890",
"state": "pending"
},
"owner": {
"id": "11111111111111111111",
"account_type": "human",
"first_name": "Admin",
"last_name": "User"
},
"org": {
"id": "22222222222222222222",
"name": "Example Org"
}
},
"current_api_version": "1.0"
}
Notes
- Returns a more limited view than the authenticated version.
- If the profile or owner cannot be loaded,
ownerwill benull.
POST /current/user/invitations/acceptall/
Accept all pending invitations.
Auth: Required (JWT)
Rate Limits: 10 per minute, 20 per 10 minutes, 30 per hour (by user)
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| invitation_key | string | No | Optional invitation key. If the user's email is not validated, this key can identify invitations. |
Request Example
curl -X POST "https://api.fast.io/current/user/invitations/acceptall/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"current_api_version": "1.0"
}
Notes
- If email is validated, all pending invitations matching that email are accepted.
- If email is not validated, use
invitation_keyto identify invitations.
GET /current/user/invitations/list/
List all pending invitations for the current user.
Auth: Required (JWT)
Rate Limits: 10 per minute, 20 per 10 minutes, 30 per hour (by user)
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| invitation_key | string | No | Optional invitation key for users without validated email. |
Request Example
curl -X GET "https://api.fast.io/current/user/invitations/list/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"invitations": [
{
"id": "12345678901234567890",
"entity": "98765432101234567890",
"state": "pending",
"email": "jane.doe@example.com"
}
]
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.invitations | array | Array of invitation resource objects. |
User Authentication Endpoints
GET /current/user/auth/
Authenticate via HTTP Basic Auth. Returns JWT token.
Auth: HTTP Basic Auth (email:password)
Rate Limits: 60 per hour, 240 per day (by IP)
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| expires | integer | No | Server default | Custom JWT expiration time in seconds. |
Request Example
curl -X GET "https://api.fast.io/current/user/auth/" \
-u "jane.doe@example.com:SecureP@ss123"
Success Response (200 OK)
{
"result": "yes",
"response": {
"expires_in": 86400,
"auth_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"2factor": false
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.expires_in | integer | JWT token expiration time in seconds. |
| response.auth_token | string | JWT access token. If 2FA is enabled, has twofactor scope (restricted). Otherwise has user scope (full access). |
| response.2factor | boolean | true if 2FA is enabled. Token has limited scope until 2FA verification is completed. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_REQUEST_TYPE (1651) | 400 | "The expires time specified is invalid." | Invalid expires parameter |
APP_AUTH_INVALID (1650) | 401 | "Your credentials were not supplied or invalid." | Missing Basic Auth header |
APP_AUTH_INVALID (1650) | 401 | "Username is not valid." | Invalid email format |
APP_AUTH_INVALID (1650) | 401 | "Password is not valid." | Invalid password format |
APP_USER_NOT_FOUND (1653) | 404 | "The username was not found." | Email not registered |
APP_AUTH_INVALID (1650) | 401 | "The password on this account is not set, use SSO." | SSO-only account (no password set) |
APP_AUTH_INVALID (1650) | 401 | "Your credentials supplied are invalid." | Wrong password |
APP_AUTH_INVALID (1650) | 401 | "Your account is suspended..." | Account suspended |
APP_AUTH_INVALID (1650) | 401 | "Your account is locked..." | Account locked |
APP_AUTH_INVALID (1650) | 401 | "Your account is suspended due to abuse." | Account flagged for abuse |
APP_AUTH_INVALID (1650) | 401 | "Your account is closed by you." | Account closed |
Notes
- Email tags (e.g.,
user+tag@example.com) are stripped before lookup. - If 2FA is enabled, complete the 2FA verification flow to upgrade the token.
- SSO-only accounts cannot use this endpoint.
GET /current/user/auth/check/
Validate current JWT and get user ID.
Auth: Required (Bearer token)
Rate Limits: 20 per 3s, 50 per 10s, 100 per minute, 5000 per hour, 20000 per day (by IP)
Request Example
curl -X GET "https://api.fast.io/current/user/auth/check/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"id": "12345678901234567890"
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.id | string | The 20-digit numeric user ID. |
Notes
- Lightweight health-check for token validity. Only validates that the JWT is structurally valid and not expired.
GET /current/auth/scopes/
Token scope introspection. Returns information about the current token's scope, auth type, and agent status.
Auth: Required (Bearer token)
Rate Limits: 60 per minute, 600 per hour (by user and IP)
Request Example
curl -X GET "https://api.fast.io/current/auth/scopes/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"auth_type": "jwt_v2",
"scopes": ["org:12345:rw", "org:67890:rw"],
"scopes_detail": [],
"is_agent": true,
"agent_name": "My MCP Agent",
"full_access": false
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.auth_type | string | Token type: "jwt_v2" (scoped JWT), "jwt_v1" (legacy JWT), or "api_key". |
| response.scopes | array | Array of scope strings in entity_type:entity_id:access_mode format. Empty for v1 JWTs and API keys. |
| response.scopes_detail | array | Hydrated scope details with entity information. Empty when scopes are empty. |
| response.is_agent | boolean | Whether the token represents an agent. |
| response.agent_name | string or null | Agent display name. null if not set or not an agent. |
| response.full_access | boolean | Whether the token has unrestricted access. true for v1 JWTs and API keys. |
API Keys
POST /current/user/auth/key/
Create a new API key.
Auth: Required (JWT, scope: user or admin)
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| memo | string | No | Label/description for the key. |
Request Example
curl -X POST "https://api.fast.io/current/user/auth/key/" \
-H "Authorization: Bearer {jwt_token}" \
-d "memo=CI/CD Pipeline Key"
Success Response (200 OK)
{
"result": "yes",
"response": {
"api_key": "abcdefghij1234567890abcdefghij12"
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.api_key | string | The newly created API key. Only shown once — store it securely. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_AUTH_INVALID (1650) | 401 | "Your credentials were not supplied or invalid." | Missing or invalid JWT |
APP_AUTH_INVALID (1650) | 401 | "The scope of your credentials are not sufficient." | JWT scope not user or admin |
APP_INTERNAL_ERROR (1600) | 500 | "You are at the maximum number of API keys, {max}." | Maximum key limit reached |
APP_ERROR_INPUT_INVALID (1605) | 400 | "You provided an invalid Memo." | Invalid memo format |
Notes
- 2FA verification is required if 2FA is enabled.
- The full key value is only returned at creation time. Subsequent reads return masked versions.
GET /current/user/auth/key/{key_id}/
Get details of an API key (key value is masked).
Auth: Required (JWT, scope: user or admin)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {key_id} | string | Yes | The API key's unique identifier. |
Request Example
curl -X GET "https://api.fast.io/current/user/auth/key/key_12345/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"api_key": {
"id": "key_12345",
"api_key": "****************************ab12",
"memo": "CI/CD Pipeline Key",
"created": "2024-01-15 10:30:00 UTC"
}
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.api_key.id | string | Unique key identifier. |
| response.api_key.api_key | string | Masked API key (only last 4 characters visible). |
| response.api_key.memo | string | Key description/label. |
| response.api_key.created | string | Key creation timestamp in UTC. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "You provided an invalid Token to get details of." | Invalid key ID format |
APP_ERROR_NOT_FOUND (1609) | 404 | Key not found | Key does not exist |
DELETE /current/user/auth/key/{key_id}/
Delete an API key.
Auth: Required (JWT, scope: user or admin)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {key_id} | string | Yes | The API key's unique identifier. |
Request Example
curl -X DELETE "https://api.fast.io/current/user/auth/key/key_12345/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "You provided an invalid Token to Delete." | Invalid key ID format |
APP_ERROR_NOT_FOUND (1609) | 404 | "You provided a Token that was not found." | Key not found or belongs to another user |
APP_ERROR_DELETE_ERROR (1610) | 500 | "There was an error deleting the API Key." | Internal deletion failure |
Notes
- 2FA verification is required if 2FA is enabled.
- Returns "not found" if the key belongs to a different user (does not reveal ownership).
GET /current/user/auth/keys/
List all API keys for the user.
Auth: Required (JWT)
Request Example
curl -X GET "https://api.fast.io/current/user/auth/keys/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"results": 2,
"api_keys": [
{
"id": "key_12345",
"api_key": "****************************ab12",
"memo": "CI/CD Pipeline Key",
"created": "2024-01-15 10:30:00 UTC"
},
{
"id": "key_67890",
"api_key": "****************************cd34",
"memo": "Backup Script",
"created": "2024-02-20 14:00:00 UTC"
}
]
},
"current_api_version": "1.0"
}
No Keys Response (200 OK)
{
"result": "yes",
"response": {
"results": 0,
"api_keys": null
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.results | integer | Number of API keys. |
| response.api_keys | array or null | Array of API key objects, or null if none exist. |
| response.api_keys[].id | string | Unique key identifier. |
| response.api_keys[].api_key | string | Masked API key (only last 4 characters visible). |
| response.api_keys[].memo | string | Key description/label. |
| response.api_keys[].created | string | Key creation timestamp in UTC. |
Two-Factor Authentication (2FA)
GET /current/user/auth/2factor/
Get current 2FA status.
Auth: Required (JWT, scope: user or admin)
Request Example
curl -X GET "https://api.fast.io/current/user/auth/2factor/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"state": "enabled",
"totp": false
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.state | string | 2FA status: "enabled" (fully verified), "unverified" (added but not verified), or "disabled" (not configured). |
| response.totp | boolean | Whether the 2FA method is TOTP (Time-based One-Time Password). |
POST /current/user/auth/2factor/{channel}/
Enable 2FA on the account.
Auth: Required (JWT, scope: user or admin)
Path Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| {channel} | string | No | sms |
2FA delivery channel: sms, call, whatsapp, or totp. |
Request Example
curl -X POST "https://api.fast.io/current/user/auth/2factor/sms/" \
-H "Authorization: Bearer {jwt_token}"
Success Response for SMS/Voice/WhatsApp (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Success Response for TOTP (202 Accepted)
{
"result": "yes",
"response": {
"binding_uri": "otpauth://totp/fast.io:jane@example.com?secret=ABCDEF..."
},
"current_api_version": "1.0"
}
Response Fields (TOTP only)
| Field | Type | Description |
|---|---|---|
| response.binding_uri | string | TOTP provisioning URI for QR code display. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_EXISTS (1607) | 409 | "2Factor already added, please remove first." | 2FA already enabled |
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid channel was supplied." | Invalid channel name |
APP_NOT_ACCEPTED (1606) | 406 | "2Factor cannot be added, you need a valid phone_number and phone_country..." | No phone number configured |
Notes
- User must have a valid phone number and country code on their account before enabling 2FA (for non-TOTP channels).
- After adding 2FA, it enters
unverifiedstate. Must complete verification viaPOST /current/user/auth/2factor/verify/{token}/. - For TOTP, display the
binding_urias a QR code for the user to scan.
POST /current/user/auth/2factor/verify/{token}/
Verify a 2FA setup code to confirm enrollment. Transitions 2FA from unverified to enabled state.
Auth: Required (JWT)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {token} | string | Yes | 2FA verification code (e.g., 6-digit code). |
Request Example
curl -X POST "https://api.fast.io/current/user/auth/2factor/verify/123456/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Verification Failed (406 Not Accepted)
{
"result": "no",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid token was supplied to validate." | Invalid token format |
APP_NOT_ACCEPTABLE (1606) | 406 | "2Factor is not enabled." | 2FA not configured |
Notes
- If 2FA is already in the
enabledstate, returns success without modification. - This is the final step of the 2FA setup flow.
POST /current/user/auth/2factor/auth/{token}/
Authenticate with a 2FA code. Upgrades a limited-scope JWT to a full-scope JWT.
Auth: Required (JWT, scope: user, twofactor, or admin)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {token} | string | Yes | Valid 2FA verification code (e.g., 6-digit TOTP or SMS code). |
Request Example
curl -X POST "https://api.fast.io/current/user/auth/2factor/auth/123456/" \
-H "Authorization: Bearer {twofactor_jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"expires_in": 86400,
"auth_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.expires_in | integer | JWT expiration time in seconds. |
| response.auth_token | string | New JWT with full user scope. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid token was supplied to authenticate." | Invalid token format |
APP_NOT_ACCEPTED (1606) | 406 | "2Factor is not enabled on this account." | 2FA not enabled |
APP_NOT_ACCEPTED (1606) | 406 | "The supplied token failed to authenticate." | Wrong 2FA code |
APP_AUTH_INVALID (1650) | 401 | "Internal Error." | JWT creation failure |
DELETE /current/user/auth/2factor/{token}/
Disable (remove) 2FA from the account.
Auth: Required (JWT, scope: user or admin)
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {token} | string | Yes | Valid 2FA verification code. Required only if 2FA is in enabled (verified) state. |
Request Example
curl -X DELETE "https://api.fast.io/current/user/auth/2factor/123456/" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_ERROR_INPUT_INVALID (1605) | 400 | "An invalid token was supplied, valid token required to remove 2Factor." | Invalid token format |
APP_NOT_ACCEPTED (1606) | 406 | "The supplied token failed to authenticate." | Token verification failed |
APP_INTERNAL_ERROR (1600) | 500 | "2Factor could not be removed, please contact support." | Internal removal failure |
Notes
- If 2FA is
enabled(verified), a valid 2FA code is required to remove it. - If 2FA is
unverified, it can be removed without a code. - If 2FA is already disabled, returns success.
2FA Code Delivery Endpoints
Request a 2FA code via different channels. All require auth (accepts user, twofactor, or admin JWT scope).
/current/user/auth/2factor/send/sms/
Send code via SMS
/current/user/auth/2factor/send/call/
Send code via voice call
/current/user/auth/2factor/send/whatsapp/
Send code via WhatsApp
Success Response (202 Accepted)
{
"result": "yes",
"current_api_version": "1.0"
}
Failure Response (406 Not Accepted)
{
"result": "no",
"current_api_version": "1.0"
}
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_AUTH_INVALID (1650) | 401 | "Your credentials were not supplied or invalid." | Invalid JWT |
APP_AUTH_INVALID (1650) | 401 | "The scope of your credentials are not sufficient." | Wrong JWT scope |
APP_NOT_ACCEPTABLE (1606) | 406 | "2Factor is not enabled." | 2FA not configured on account |
Notes
- 2FA must be enabled (or in unverified state) for codes to be sent.
- Returns
result: "no"if the code send fails (e.g., invalid phone number).
Complete 2FA Flows
Complete 2FA Login Flow
1. GET /current/user/auth/
- Send email:password via HTTP Basic Auth
- Response includes "2factor": true and limited-scope auth_token
2. GET /current/user/auth/2factor/send/sms/ (or /call/ or /whatsapp/)
- Request a fresh 2FA code
- Uses the limited-scope (twofactor) JWT
3. POST /current/user/auth/2factor/auth/{code}/
- Submit the 2FA code
- Receive a new JWT with full "user" scope
- Use this token for all subsequent requests
Complete 2FA Setup Flow
1. POST /current/user/auth/2factor/{channel}/
- Choose channel: sms, call, whatsapp, or totp
- Phone number must be configured on account (for non-TOTP)
- State becomes "unverified"
- For TOTP: receive binding_uri for QR code
2. Receive code via selected channel (or scan QR code for TOTP)
3. POST /current/user/auth/2factor/verify/{code}/
- Submit the verification code
- State becomes "enabled"
- 2FA is now active on the account
Complete 2FA Removal Flow
1. DELETE /current/user/auth/2factor/{code}/
- Must provide valid 2FA code if state is "enabled"
- Can remove without code if state is "unverified"
- 2FA is fully removed from the account
User Search
GET /current/users/search/
Search for users by name or email across contacts and the platform user directory.
Auth: Required (JWT)
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| search | string | Yes | Search term. Matches against user names and email addresses. Must not be blank. |
Request Example
curl -X GET "https://api.fast.io/current/users/search/?search=john" \
-H "Authorization: Bearer {jwt_token}"
Success Response (200 OK)
{
"result": "yes",
"response": {
"contacts": {
"john.doe@example.com": "John Doe",
"jane.johnson@example.com": "Jane Johnson"
}
},
"current_api_version": "1.0"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| response.contacts | object | Map of email address (key) to display name (value) for each matched user. |
Error Responses
| Error Code | HTTP Status | Message | Cause |
|---|---|---|---|
APP_AUTH_INVALID (1650) | 401 | "Authentication required" | Missing or invalid JWT token |
APP_ERROR_INPUT_INVALID (1605) | 400 | "This value should not be blank." | Missing or empty search parameter |
APP_INTERNAL_ERROR (1600) | 500 | "Internal error" | Search backend unavailable |
Notes
- Searches across two sources: the user's contacts and the platform user directory. Results are merged and deduplicated by email.
- Response format is a flat key-value map (email → name), not an array of objects.
Response Envelope
Success
{"result": "yes", "current_api_version": "1.0", ...}
Error
{
"result": "no",
"error": {
"code": 195654,
"text": "Human-readable message",
"documentation_url": "https://api.fast.io/llms.txt",
"resource": "POST /current/user/"
}
}
Common Error Codes
| Code | Name | HTTP Status |
|---|---|---|
1600 | APP_INTERNAL_ERROR | 500 Internal Server Error |
1605 | APP_ERROR_INPUT_INVALID | 400 Bad Request |
1606 | APP_NOT_ACCEPTABLE | 406 Not Acceptable |
1607 | APP_ERROR_INPUT_DUPLICATE / APP_EXISTS | 409 Conflict |
1608 | APP_CONFLICT | 409 Conflict |
1609 | APP_ERROR_NOT_FOUND / APP_MISSING | 404 Not Found |
1610 | APP_ERROR_DELETE_ERROR | 500 Internal Server Error |
1650 | APP_AUTH_INVALID | 401 Unauthorized |
1651 | APP_REQUEST_TYPE | 400 Bad Request |
1653 | APP_USER_NOT_FOUND | 404 Not Found |
1671 | APP_ENHANCE_CALM | 429 Too Many Requests |
1680 | APP_DENIED | 403 Forbidden |
1681 | APP_RESTRICTED | 403 Forbidden |
1682 | APP_LOCKED | 423 Locked |
1690 | APP_SSO_ERROR_AUTH | 401 Unauthorized |
Rate Limiting
Response headers: X-Rate-Limit-Available, X-Rate-Limit-Expiry, X-Rate-Limit-Max
When exceeded: HTTP 429 with error code 1671 (APP_ENHANCE_CALM).
ID Formats
- User IDs: 20-digit numeric string (e.g.,
"12345678901234567890") "me"can be used as user_id in user endpoints to reference the authenticated user- User endpoints also accept email address as an identifier
Token Types
| Type | Format | Lifetime | Use |
|---|---|---|---|
| JWT (Basic Auth) | RS256-signed JSON Web Token | Configurable (default varies) | General API access |
| JWT (OAuth) | RS256-signed JSON Web Token | 1 hour | OAuth-based API access |
| Refresh Token | Opaque string | 30 days | Obtaining new access tokens (OAuth only) |
| API Key | Alphanumeric string | Long-lived (no expiry) | Service-to-service communication |
Security Best Practices
- Always use HTTPS for all API communication.
- Store refresh tokens and API keys securely (OS keychain, encrypted storage).
- Never log tokens in client-side logs or analytics.
- Rotate refresh tokens — always store the new token from a refresh response.
- Verify the
stateparameter in OAuth callbacks to prevent CSRF. - Handle 401 responses by attempting a token refresh; if refresh fails, re-authenticate.
- Revoke tokens on logout by calling the revoke endpoint and clearing local storage.