veevo.ai

API Reference

All endpoints require Authorization: Bearer rtk_... unless noted. Auth endpoints (register, login) are unauthenticated.

POST /api/auth/register

Create an account. No auth required.

Request

{
  "email": "you@company.com",
  "password": "min_8_chars",
  "companyName": "Your Company"   // optional
}

Response 201

{
  "account": {
    "id": "clx...",
    "email": "you@company.com",
    "companyName": "Your Company",
    "status": "INACTIVE"
  },
  "apiKey": "rtk_abc123...",
  "token": "eyJhbG...",
  "checkoutUrl": "https://checkout.stripe.com/...",
  "engineVoiceUrl": "https://engine.veevo.ai/voice"
}

Account starts as INACTIVE. Open checkoutUrl to complete payment. The apiKey is shown only once — store it securely. Set your Twilio voice webhook to engineVoiceUrl.

POST /api/auth/login

Get a JWT token. No auth required.

Request

{
  "email": "you@company.com",
  "password": "your_password"
}

Response 200

{
  "token": "eyJhbG..."
}

GET /api/account

Get account details, status, and resource counts.

Response 200

{
  "account": {
    "id": "clx...",
    "email": "you@company.com",
    "companyName": "Your Company",
    "status": "ACTIVE",
    "createdAt": "2026-04-01T...",
    "_count": {
      "phoneNumbers": 2,
      "apiKeys": 1
    }
  }
}

POST /api/api-keys

Create an additional API key.

Request

{
  "label": "Production"   // optional
}

Response 201

{
  "id": "clx...",
  "key": "rtk_newkey...",
  "keyPrefix": "rtk_new",
  "label": "Production",
  "createdAt": "2026-04-01T..."
}

The full key is shown only once. Store it securely.

GET /api/api-keys

List all active API keys. Only prefixes are returned, not full keys.

Response 200

{
  "apiKeys": [
    {
      "id": "clx...",
      "keyPrefix": "rtk_abc",
      "label": "Default",
      "lastUsedAt": "2026-04-05T...",
      "createdAt": "2026-04-01T..."
    }
  ]
}

DELETE /api/api-keys/:id

Revoke an API key. It will immediately stop working.

Response 200

{
  "revoked": true
}

POST /api/phone-numbers

Register a phone number with callback URLs. Must be US E.164 format. Callback URLs must be public HTTPS endpoints.

Request

{
  "phoneNumber": "+15551234567",
  "onCallStartUrl": "https://your-backend.com/calls/start",
  "onCallEndUrl": "https://your-backend.com/calls/end",
  "onErrorUrl": "https://your-backend.com/calls/error"   // optional
}

Response 201

{
  "phoneNumber": {
    "id": "clx...",
    "phoneNumber": "+15551234567",
    "onCallStartUrl": "https://your-backend.com/calls/start",
    "onCallEndUrl": "https://your-backend.com/calls/end",
    "onErrorUrl": null,
    "isActive": true,
    "createdAt": "2026-04-01T..."
  }
}

GET /api/phone-numbers

List all registered phone numbers.

Response 200

{
  "phoneNumbers": [ ... ]
}

DELETE /api/phone-numbers/:id

Remove a registered phone number.

Response 200

{
  "deleted": true
}

POST /api/outbound

Initiate an outbound call. The from number must be registered to your account.

Request

{
  "to": "+15559876543",
  "from": "+15551234567",
  "onCallStartUrl": "https://your-backend.com/calls/start",
  "onCallEndUrl": "https://your-backend.com/calls/end",
  "twilioAccountSid": "AC...",
  "twilioAuthToken": "...",
  "onErrorUrl": "https://your-backend.com/calls/error",   // optional
  "metadata": { "customerId": "cust_123" },                // optional
  "machineDetection": "Enable",                            // optional: "Enable" | "DetectMessageEnd"
  "timeout": 30                                            // optional: 5-120, default 30
}

Response 201

Returns the engine response (call SID and status).

GET /api/usage

Get call history with cost breakdowns.

Query ParamTypeDefaultDescription
limitnumber50Max 100
offsetnumber0Pagination offset

Response 200

{
  "records": [
    {
      "id": "clx...",
      "callSid": "CA...",
      "callerPhone": "+19805551234",
      "calledNumber": "+15551234567",
      "durationSeconds": 47,
      "costBreakdown": { "totalCost": 0.018 },
      "createdAt": "2026-04-05T..."
    }
  ],
  "total": 142,
  "limit": 50,
  "offset": 0
}

GET /api/usage/current

Current month and all-time usage summary.

Response 200

{
  "currentMonth": {
    "calls": 23,
    "minutes": 47,
    "estimatedCost": 2.35
  },
  "allTime": {
    "calls": 142,
    "minutes": 310
  },
  "perMinuteRate": 0.05,
  "monthlyBase": 5
}

POST /api/billing/portal

Get a Stripe Billing Portal URL to manage subscription, payment method, and invoices.

Response 200

{
  "url": "https://billing.stripe.com/p/session/..."
}

GET /api/billing/subscription

Get subscription status, pricing, and usage totals.

Response 200

{
  "status": "ACTIVE",
  "monthlyBase": 5,
  "perMinuteRate": 0.05,
  "totalCalls": 142,
  "totalMinutes": 310,
  "hasPaymentMethod": true
}

Error Codes

CodeMeaning
400Invalid request body or callback URL
401Missing or invalid API key / credentials
402Payment required — complete Stripe Checkout
403Account suspended or phone number not owned
404Resource not found
409Phone number already registered by another account
500Internal server error