API reference

Authentication

Create an account, verify mobile and email, then obtain JWT tokens for dashboard APIs. Server-to-server apps should use API keys on the External API instead.

Most dashboard routes need Authorization: Bearer {accessToken}. Login and register also require a captcha challenge from GET /api/auth/captcha. OTP login is available if you prefer email codes over a password.

Sign up (dashboard or API)

Registration is multi-step so we can verify the owner’s mobile and email before the workspace is fully active. The hosted signup page runs this for you. If you call the API directly, follow the same order.

  • GET /api/auth/captcha — receive captchaId and a challenge.
  • POST /api/auth/register — email, password, confirmPassword, name, tenantName, mobile, captchaId, captchaAnswer. Returns a registrationToken, not a full login.
  • POST /api/auth/mobile/send-otp then /mobile/verify-otp with that token.
  • POST /api/auth/email/send-verification-code then /email/verify.
  • POST /api/auth/login (or login OTP) to receive accessToken and refreshToken.

A 14-day trial starts with the workspace. When the trial ends, the workspace moves onto the Free plan with limited quotas — data is kept. Upgrade anytime from Billing.

JWT vs API key

Use JWT for anything a logged-in user does: inbox, team, billing, campaigns, webhooks, API key management. Use X-API-Key only on /api/external. Never send an API key from a public browser.

GET/api/auth/captcha

Get captcha

Fetch a one-time captcha challenge required by register and password login.

URL: https://api.actiwapi.com/api/auth/captcha

Auth: None

Code examples

curl -X GET "https://api.actiwapi.com/api/auth/captcha" \
  -H "Content-Type: application/json"

Response example200

{
  "success": true,
  "data": { "captchaId": "uuid", "challenge": "data:image/png;base64,..." }
}

Try in Swagger UI

POST/api/auth/register

Register

Start signup. Returns a registrationToken used for mobile and email verification. Does not issue dashboard JWTs yet.

URL: https://api.actiwapi.com/api/auth/register

Auth: None

Request example

{
  "name": "Jane Doe",
  "email": "owner@acme.com",
  "password": "SecurePass123!",
  "confirmPassword": "SecurePass123!",
  "tenantName": "Acme Corp",
  "mobile": "919876543210",
  "captchaId": "uuid",
  "captchaAnswer": "7"
}

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/register" \
  -H "Content-Type: application/json"
  -d '{  "name": "Jane Doe",  "email": "owner@acme.com",  "password": "SecurePass123!",  "confirmPassword": "SecurePass123!",  "tenantName": "Acme Corp",  "mobile": "919876543210",  "captchaId": "uuid",  "captchaAnswer": "7"}'

Response example201

{
  "success": true,
  "data": {
    "requiresVerification": true,
    "registrationToken": "jwt-registration-token",
    "nextStep": "mobile",
    "phoneMasked": "+91******3210",
    "emailMasked": "o***@acme.com"
  }
}

Try in Swagger UI

POST/api/auth/login

Login

Authenticate with email and password to receive access and refresh tokens.

URL: https://api.actiwapi.com/api/auth/login

Auth: None

Request example

{
  "email": "owner@acme.com",
  "password": "SecurePass123!",
  "captchaId": "uuid",
  "captchaAnswer": "7"
}

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/login" \
  -H "Content-Type: application/json"
  -d '{  "email": "owner@acme.com",  "password": "SecurePass123!",  "captchaId": "uuid",  "captchaAnswer": "7"}'

Response example200

{
  "success": true,
  "data": {
    "accessToken": "eyJhbG...",
    "refreshToken": "eyJhbG...",
    "expiresIn": "7d",
    "user": { "id": "uuid", "email": "owner@acme.com", "role": "owner" }
  }
}

Try in Swagger UI

POST/api/auth/refresh

Refresh token

Exchange a valid refresh token for a new access token.

URL: https://api.actiwapi.com/api/auth/refresh

Auth: None

Request example

{ "refreshToken": "eyJhbG..." }

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/refresh" \
  -H "Content-Type: application/json"
  -d '{ "refreshToken": "eyJhbG..." }'

Response example200

{
  "success": true,
  "data": {
    "accessToken": "eyJhbG...",
    "refreshToken": "eyJhbG...",
    "expiresIn": "7d"
  }
}

Try in Swagger UI

POST/api/auth/logout

Logout

Invalidate the refresh token so it cannot mint new access tokens.

URL: https://api.actiwapi.com/api/auth/logout

Auth: None

Request example

{ "refreshToken": "eyJhbG..." }

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/logout" \
  -H "Content-Type: application/json"
  -d '{ "refreshToken": "eyJhbG..." }'

Response example200

{ "success": true, "message": "Logged out" }

Try in Swagger UI

POST/api/auth/forgot-password

Forgot password

Send a password-reset email if the address exists. Always returns success to avoid account enumeration.

URL: https://api.actiwapi.com/api/auth/forgot-password

Auth: None

Request example

{ "email": "owner@acme.com" }

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/forgot-password" \
  -H "Content-Type: application/json"
  -d '{ "email": "owner@acme.com" }'

Response example200

{ "success": true, "message": "If the email exists, a reset link was sent" }

Try in Swagger UI

POST/api/auth/reset-password

Reset password

Set a new password using the token from the reset email.

URL: https://api.actiwapi.com/api/auth/reset-password

Auth: None

Request example

{ "token": "hex-token", "password": "NewSecurePass123!" }

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/reset-password" \
  -H "Content-Type: application/json"
  -d '{ "token": "hex-token", "password": "NewSecurePass123!" }'

Response example200

{ "success": true, "message": "Password updated" }

Try in Swagger UI

GET/api/auth/profile

Get profile

Returns the authenticated user and account context.

URL: https://api.actiwapi.com/api/auth/profile

Auth: JWT Bearer

Headers

HeaderValueRequired
AuthorizationBearer {accessToken}Yes
Content-Typeapplication/jsonYes*

Code examples

curl -X GET "https://api.actiwapi.com/api/auth/profile" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {accessToken}"

Response example200

{
  "success": true,
  "data": {
    "id": "uuid",
    "email": "owner@acme.com",
    "name": "Jane Doe",
    "role": "owner",
    "tenantId": "uuid",
    "tenantName": "Acme Corp"
  }
}

Try in Swagger UI

PUT/api/auth/profile

Update profile

Change display name or other profile fields for the current user.

URL: https://api.actiwapi.com/api/auth/profile

Auth: JWT Bearer

Headers

HeaderValueRequired
AuthorizationBearer {accessToken}Yes
Content-Typeapplication/jsonYes*

Request example

{ "name": "Jane Doe" }

Code examples

curl -X PUT "https://api.actiwapi.com/api/auth/profile" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {accessToken}"
  -d '{ "name": "Jane Doe" }'

Response example200

{ "success": true, "data": { "id": "uuid", "name": "Jane Doe" } }

Try in Swagger UI

POST/api/auth/change-password

Change password

Change password while logged in. Requires the current password.

URL: https://api.actiwapi.com/api/auth/change-password

Auth: JWT Bearer

Headers

HeaderValueRequired
AuthorizationBearer {accessToken}Yes
Content-Typeapplication/jsonYes*

Request example

{
  "currentPassword": "SecurePass123!",
  "newPassword": "EvenMoreSecure123!"
}

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/change-password" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {accessToken}"
  -d '{  "currentPassword": "SecurePass123!",  "newPassword": "EvenMoreSecure123!"}'

Response example200

{ "success": true, "message": "Password changed" }

Try in Swagger UI

POST/api/auth/login/send-otp

Resend login OTP

Resend the mobile OTP for an in-progress login challenge (after password login requires a second factor).

URL: https://api.actiwapi.com/api/auth/login/send-otp

Auth: None

Request example

{ "loginChallengeToken": "token-from-login" }

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/login/send-otp" \
  -H "Content-Type: application/json"
  -d '{ "loginChallengeToken": "token-from-login" }'

Response example200

{ "success": true, "data": { "phoneMasked": "+91******3210" } }

Try in Swagger UI

POST/api/auth/login/verify-otp

Verify login OTP

Complete a login challenge with the SMS/WhatsApp OTP (or Firebase ID token).

URL: https://api.actiwapi.com/api/auth/login/verify-otp

Auth: None

Request example

{
  "loginChallengeToken": "token-from-login",
  "otpCode": "123456"
}

Code examples

curl -X POST "https://api.actiwapi.com/api/auth/login/verify-otp" \
  -H "Content-Type: application/json"
  -d '{  "loginChallengeToken": "token-from-login",  "otpCode": "123456"}'

Response example200

{
  "success": true,
  "data": { "accessToken": "eyJhbG...", "refreshToken": "eyJhbG...", "expiresIn": "7d" }
}

Try in Swagger UI

Error codes

Failed requests return a JSON envelope with success: false and a human-readable message.

{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "phone": "Valid phone number is required"
  }
}
HTTPCodeDescription
400VALIDATION_ERRORRequest body or query failed validation.
401UNAUTHORIZEDMissing or invalid JWT / API key.
403FORBIDDENAuthenticated but lacking permission or entitlement.
403SUBSCRIPTION_INACTIVEAction not allowed on the current plan (including Free after trial). Upgrade or wait for entitlements.
403LIMIT_EXCEEDEDPlan limit reached (sessions, messages, API requests, etc.).
404NOT_FOUNDResource does not exist or is not in your account.
409CONFLICTDuplicate resource or invalid state transition.
429RATE_LIMITEDToo many requests; retry after backoff.
500INTERNAL_ERRORUnexpected server error.
502WHATSAPP_UNAVAILABLEWhatsApp session disconnected or provider error.