Wocha Docs

Phone API

Account API endpoints for phone number verification and management

Manage phone numbers on user identities via the Account API. Phone verification is a prerequisite for SMS MFA enrolment.


Authentication

APITokenBase URL
Account APIUser access token (Authorization: Bearer eyJ...)https://TENANT.api.wocha.ai/v1/account

All endpoints require a valid user OAuth access token. Management API keys cannot call Account API routes.


Phone verification flow

Phone verification is a two-step process: initiate (POST), then verify (PUT).

sequenceDiagram
    participant App
    participant API as Account API
    participant GW as SMS Gateway
    participant User
 
    App->>API: POST /phone { phone_number }
    API->>GW: sendOtp(verification)
    GW->>User: SMS with 6-digit code
    API-->>App: { status: pending, phone_number_masked }
    User->>App: Enters code
    App->>API: PUT /phone { code }
    API->>GW: verifyOtp(code)
    API-->>App: { status: verified, phone_number }

Start phone verification

Send an OTP to the provided phone number.

POST /v1/account/phone
Authorization: Bearer {user_access_token}
Content-Type: application/json
 
{ "phone_number": "+447911123456" }

Response 201 Created:

{
  "data": {
    "status": "pending",
    "phone_number_masked": "+44 ••••• 3456"
  }
}
FieldDescription
statusAlways pending after a successful OTP send
phone_number_maskedMasked display format for the UI

The pending verification expires after 15 minutes. A new POST replaces any existing pending verification.

Errors:

StatusCodeWhen
422validation_errorInvalid E.164 phone number
429rate_limitedPer-phone or per-tenant rate limit exceeded
503service_unavailableSMS not enabled or gateway not configured
404not_foundUser identity not found
502upstream_errorOTP send failed at the provider

Verify phone number

Submit the 6-digit OTP code to verify the phone and update the identity trait.

PUT /v1/account/phone
Authorization: Bearer {user_access_token}
Content-Type: application/json
 
{ "code": "123456" }

Response 200 OK:

{
  "data": {
    "status": "verified",
    "phone_number": "+447911123456"
  }
}

On success, the phone_number trait is set on the Kratos identity and the pending verification is cleared.

Errors:

StatusCodeWhen
422validation_errorInvalid code, expired verification, or max attempts exceeded
404not_foundNo pending phone verification — call POST first
400validation_errorRequest body is not valid JSON
503service_unavailableSMS gateway not configured

Remove phone number

DELETE /v1/account/phone
Authorization: Bearer {user_access_token}

Response 200 OK:

{
  "data": {
    "status": "removed"
  }
}

Errors:

StatusCodeWhen
409conflictSMS MFA is still enrolled — remove SMS MFA first
404not_foundNo phone number registered

Code examples

cURL

# Start verification
curl -X POST "https://acme.api.wocha.ai/v1/account/phone" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{"phone_number": "+447911123456"}'
 
# Verify code
curl -X PUT "https://acme.api.wocha.ai/v1/account/phone" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'
 
# Remove phone
curl -X DELETE "https://acme.api.wocha.ai/v1/account/phone" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

JavaScript

const accountApiUrl = "https://acme.api.wocha.ai/v1/account";
const token = await getAccessToken();
 
// Start verification
const startRes = await fetch(`${accountApiUrl}/phone`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ phone_number: "+447911123456" }),
});
const { data: pending } = await startRes.json();
console.log(pending.phone_number_masked); // "+44 ••••• 3456"
 
// Verify
const verifyRes = await fetch(`${accountApiUrl}/phone`, {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ code: "123456" }),
});
const { data: verified } = await verifyRes.json();
console.log(verified.phone_number); // "+447911123456"

React SDK

import { usePhone } from "@wocha/react";
 
function PhoneSettings() {
  const { addPhone, verifyPhone, removePhone, resendCode } = usePhone();
 
  const handleAdd = async (number: string) => {
    const { phone_number_masked } = await addPhone(number);
    // Display masked number and OTP input
  };
 
  const handleVerify = async (code: string) => {
    await verifyPhone(code);
  };
}

E.164 requirements

Phone numbers must match the pattern ^\+[1-9][0-9]{6,14}$:

  • Start with + followed by country code
  • No spaces, dashes, or parentheses
  • 7–15 digits total (including country code)

Valid: +447911123456, +15551234567 Invalid: 07911123456, +44 7911 123456, 447911123456


On this page