Users & Auth API
Manage user authentication, profiles, roles, and permissions.
Integration Patterns
Section titled “Integration Patterns”Before diving into the raw API, check out the Authentication Integration Guide for complete flows:
- Registration & Login: Email/password and OAuth (Google)
- Token Management: Guest, authenticated, and server tokens
- Protected Routes: SSR and CSR auth patterns
- Profile Management: Update user info with correct field names
Quick Integration Example
Section titled “Quick Integration Example”import { createArkySDK } from 'arky-sdk';
const sdk = createArkySDK({ baseUrl: 'https://api.arky.io', businessId: 'your-business-id', autoGuest: true, getToken: () => JSON.parse(localStorage.getItem('arky_token') || 'null'), setToken: (token) => localStorage.setItem('arky_token', JSON.stringify(token)), logout: () => localStorage.removeItem('arky_token'),});
// Registerconst { user, token } = await sdk.user.register({ email: 'user@example.com', password: 'SecurePass123!', firstName: 'John', lastName: 'Doe',});
// Get profileconst me = await sdk.user.me();
// Update profile (note: phoneNumbers is an array)await sdk.user.updateUser({ id: me.id, firstName: 'Jane', phoneNumbers: ['+1234567890'], // Array, not singular phoneNumber});See Authentication Guide for complete patterns.
Base URL
Section titled “Base URL”All User endpoints are prefixed with /v1/users.
Authentication Methods
Section titled “Authentication Methods”Arky supports multiple authentication providers:
- EMAIL: Email + password with confirmation flow
- GOOGLE: OAuth2 via Google
- GUEST: Phone number-based guest tokens
- API: API keys for server-to-server
Register
Section titled “Register”Create a new user account with email and password.
Endpoint: POST /v1/users/register
const result = await sdk.user.registerUser({ provider: 'EMAIL_REGISTER', email: 'user@example.com', password: 'SecureP@ssw0rd', reserveDomain: 'https://myapp.com', // For confirmation email link});// Confirmation email sent to usercurl -X POST https://api.arky.io/v1/users/register \ -H "Content-Type: application/json" \ -d '{ "provider": "EMAIL_REGISTER", "email": "user@example.com", "password": "SecureP@ssw0rd", "reserveDomain": "https://myapp.com" }'Response:
{ "success": true}Process:
- Password is hashed with SHA256
- User created with
is_confirmed: false - Confirmation email sent with JWT token (valid 1 hour)
- User must click link to activate account
Errors:
400: Email already exists422: Validation failed (weak password, invalid email)
Confirm Email
Section titled “Confirm Email”Activate user account after registration.
Endpoint: PUT /v1/users/confirm
await sdk.user.confirmUser({ token: 'JWT_TOKEN_FROM_EMAIL',});// Account now active, user can logincurl -X PUT https://api.arky.io/v1/users/confirm \ -H "Content-Type: application/json" \ -d '{ "token": "JWT_TOKEN_FROM_EMAIL" }'Email Login
Section titled “Email Login”Endpoint: POST /v1/users/login
const auth = await sdk.user.loginUser({ provider: 'EMAIL', email: 'user@example.com', password: 'SecureP@ssw0rd',});
console.log('Access token:', auth.access_token);console.log('Refresh token:', auth.refresh_token);console.log('Expires at:', auth.expires_at);curl -X POST https://api.arky.io/v1/users/login \ -H "Content-Type: application/json" \ -d '{ "provider": "EMAIL", "email": "user@example.com", "password": "SecureP@ssw0rd" }'Response:
{ "userId": "user_abc123", "provider": "EMAIL", "accessToken": "eyJhbGc...", "refreshToken": "eyJhbGc...", "tokenType": "Token", "expiresAt": 1698765432, "scope": "Fake", "isGuest": false}Errors:
422: Invalid email or password422: Email not confirmed400: Validation failed
Google OAuth Login
Section titled “Google OAuth Login”Step 1: Get Login URL
Endpoint: GET /v1/users/login/url
const { url } = await sdk.user.getLoginUrl({ provider: 'GOOGLE', originUrl: 'https://myapp.com', redirectUrl: 'https://myapp.com/auth/callback',});
// Redirect user to Google loginwindow.location.href = url;curl "https://api.arky.io/v1/users/login/url?provider=GOOGLE&originUrl=https://myapp.com&redirectUrl=https://myapp.com/auth/callback"Step 2: Exchange Code for Tokens
After Google redirects back with code:
const auth = await sdk.user.loginUser({ provider: 'GOOGLE', code: 'GOOGLE_AUTH_CODE', originUrl: 'https://myapp.com',});curl -X POST https://api.arky.io/v1/users/login \ -H "Content-Type: application/json" \ -d '{ "provider": "GOOGLE", "code": "GOOGLE_AUTH_CODE", "originUrl": "https://myapp.com" }'Note: If the user’s email doesn’t exist, a new user is automatically created with is_confirmed: true.
Guest Login
Section titled “Guest Login”Create a guest account using phone number.
const auth = await sdk.user.loginUser({ provider: 'GUEST', phoneNumber: '+1234567890',});
// Returns token with is_guest: truecurl -X POST https://api.arky.io/v1/users/login \ -H "Content-Type: application/json" \ -d '{ "provider": "GUEST", "phoneNumber": "+1234567890" }'Refresh Token
Section titled “Refresh Token”Obtain a new access token using a refresh token.
Endpoint: POST /v1/users/refresh (inferred)
// SDK handles refresh automatically, but you can manually call:const newAuth = await sdk.user.refreshAccessToken({ provider: 'GOOGLE', refreshToken: 'CURRENT_REFRESH_TOKEN',});curl -X POST https://api.arky.io/v1/users/refresh \ -H "Content-Type: application/json" \ -d '{ "provider": "GOOGLE", "refreshToken": "REFRESH_TOKEN" }'Note: Refresh tokens for EMAIL and GOOGLE have no expiry (exp: None). Access tokens expire in 3600 seconds (1 hour).
Logout
Section titled “Logout”Revoke OAuth tokens (Google only).
Endpoint: POST /v1/users/logout
await sdk.user.logout({ provider: 'GOOGLE', token: 'ACCESS_TOKEN', originUrl: 'https://myapp.com',});curl -X POST https://api.arky.io/v1/users/logout \ -H "Content-Type: application/json" \ -d '{ "provider": "GOOGLE", "token": "ACCESS_TOKEN", "originUrl": "https://myapp.com" }'Get Current User
Section titled “Get Current User”Fetch authenticated user profile.
Endpoint: GET /v1/users/me
Headers: Authorization: Bearer <access_token>
const user = await sdk.user.getMe({});
console.log('User ID:', user.id);console.log('Email:', user.email);console.log('Roles:', user.roles);console.log('Business configs:', user.business_user_configs);curl -H "Authorization: Bearer YOUR_TOKEN" \ https://api.arky.io/v1/users/meResponse:
{ "id": "user_abc123", "name": "John Doe", "email": "john@example.com", "isConfirmed": true, "phoneNumbers": ["+1234567890"], "addresses": [], "roleIds": ["role_xyz"], "roles": [ { "id": "role_xyz", "name": "Admin", "permissions": [...] } ], "apiTokens": [ { "id": "token_123", "name": "My API Key", "value": "••••••••", "provider": "API" } ], "businessUserConfigs": [ { "businessId": "biz_123", "settings": {} } ], "lifecycle": { "lastLoginAt": 1698765432, "onboardingCompleted": true }}Update Profile
Section titled “Update Profile”Endpoint: PUT /v1/users/update
Headers: Authorization: Bearer <access_token>
const updated = await sdk.user.updateUser({ name: 'Jane Smith', phoneNumbers: ['+1234567890'], // Array of phone numbers addresses: [ { street: '123 Main St', city: 'New York', state: 'NY', zip: '10001', country: 'US', }, ],});curl -X PUT https://api.arky.io/v1/users/update \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Jane Smith", "phoneNumbers": ["+1234567890"], "addresses": [...] }'```
</div></Tabs>
---
## Phone Verification
### Add Phone Number
**Endpoint:** `POST /v1/users/phone-number`
<Tabs client:load> <div slot="tab1">
```typescriptawait sdk.user.addPhoneNumber({ phoneNumber: '+1234567890',});// Verification SMS sentcurl -X POST https://api.arky.io/v1/users/phone-number \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "phoneNumber": "+1234567890" }'Verify Phone Code
Section titled “Verify Phone Code”Endpoint: POST /v1/users/phone-number/confirm
await sdk.user.phoneNumberConfirm({ phoneNumber: '+1234567890', code: '123456',});curl -X POST https://api.arky.io/v1/users/phone-number/confirm \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "phoneNumber": "+1234567890", "code": "123456" }'Password Management
Section titled “Password Management”Forgot Password
Section titled “Forgot Password”Send password reset email.
Endpoint: POST /v1/users/forgot-password
await sdk.user.forgotPassword({ email: 'user@example.com', reserveDomain: 'https://myapp.com',});// Reset link sent to emailcurl -X POST https://api.arky.io/v1/users/forgot-password \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "reserveDomain": "https://myapp.com" }'Reset Password (with token)
Section titled “Reset Password (with token)”Endpoint: POST /v1/users/reset-forgot-password
await sdk.user.resetForgotPassword({ token: 'RESET_TOKEN_FROM_EMAIL', password: 'NewSecureP@ssw0rd',});curl -X POST https://api.arky.io/v1/users/reset-forgot-password \ -H "Content-Type: application/json" \ -d '{ "token": "RESET_TOKEN", "password": "NewSecureP@ssw0rd" }'Change Password (authenticated)
Section titled “Change Password (authenticated)”Endpoint: POST /v1/users/reset-password
Headers: Authorization: Bearer <access_token>
await sdk.user.resetPassword({ oldPassword: 'OldP@ssw0rd', newPassword: 'NewSecureP@ssw0rd',});curl -X POST https://api.arky.io/v1/users/reset-password \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "oldPassword": "OldP@ssw0rd", "newPassword": "NewSecureP@ssw0rd" }'User Search
Section titled “User Search”Search users within a business (requires ADMIN permission).
Endpoint: GET /v1/users/search
Headers: Authorization: Bearer <access_token>
const { items, cursor } = await sdk.user.searchUsers({ query: 'john', businessId: 'biz_123', roleIds: ['role_admin'], limit: 20,});curl "https://api.arky.io/v1/users/search?query=john&businessId=biz_123&limit=20" \ -H "Authorization: Bearer YOUR_TOKEN"Roles Management
Section titled “Roles Management”Assign Role
Section titled “Assign Role”Assign a role to a user (requires ADMIN permission on business).
Endpoint: PUT /v1/users/set-role
Headers: Authorization: Bearer <access_token>
await sdk.user.setRole({ userId: 'user_abc123', roleId: 'role_manager', businessId: 'biz_123',});curl -X PUT https://api.arky.io/v1/users/set-role \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userId": "user_abc123", "roleId": "role_manager", "businessId": "biz_123" }'API Tokens
Section titled “API Tokens”Users can generate API tokens for server-to-server auth.
Generating a Token:
- Call
updateUserwithapiTokensarray:
await sdk.user.updateUser({ name: user.name, apiTokens: [ { id: 'token_new', name: 'Production API Key', value: 'arky_live_...', // Generate securely provider: 'API', }, ],});curl -X PUT https://api.arky.io/v1/users/update \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "apiTokens": [ { "id": "token_new", "name": "Production API Key", "value": "arky_live_...", "provider": "API" } ] }'Using API Tokens:
curl -H "X-API-Key: arky_live_..." \ https://api.arky.io/v1/businesses/YOUR_BUSINESS_IDError Responses
Section titled “Error Responses”Common Error Codes
Section titled “Common Error Codes”| Code | Error | Description |
|---|---|---|
400 | BAD_REQUEST | Invalid provider or malformed request |
401 | UNAUTHENTICATED | Missing or invalid token |
403 | FORBIDDEN | Insufficient permissions |
404 | NOT_FOUND | User not found or email not confirmed |
422 | VALIDATION_FAILED | Field validation errors |
Error Response Format
Section titled “Error Response Format”{ "error": "VALIDATION_FAILED", "message": "Validation errors occurred", "details": [ { "field": "email", "error": "EMAIL_EXISTS", "message": "email exists" } ]}Validation Errors
Section titled “Validation Errors”EMAIL_EXISTS: Email already registeredPASSWORD_WRONG: Invalid credentialsPASSWORD_REQUIRED: Password field missingNOT_CONFIRMED: Email not verifiedINVALID_ORIGIN_URI: OAuth origin not whitelistedINVALID_REDIRECT_URI: OAuth redirect not whitelisted
JWT Claims Structure
Section titled “JWT Claims Structure”Access Token Claims:
{ sub: "user_abc123", // User ID email: "user@example.com", // Email (optional for guests) provider: "EMAIL", // AUTH provider exp: 1698765432 // Expiry timestamp}Refresh Token Claims:
Same as access token, but exp is null (never expires).
Related
Section titled “Related”- Authentication Integration Guide - Complete auth flows and patterns
- E-commerce Integration - Checkout with authenticated users
- Reservations Integration - Book services as logged-in user