Sowa API Documentation

REST API for Sowa Answers. Provision numbers, list calls, and receive call-completed webhooks.

Authentication

Include your API key in the Authorization header:

Authorization: Bearer lsk_live_xxx

Create API keys in Dashboard → API Keys.

Base URL

https://sowaanswers.com/api/v1

Endpoints

POST /numbers

Provision a number and configure call handling. Requires webhook_url (HTTPS).

// Request
{
  "business_name": "Acme Plumbing",
  "webhook_url": "https://your-app.com/webhooks/Sowa",
  "booking_link": "https://acme.com/book",
  "forward_to": "+1234567890"
}

// Response
{
  "data": {
    "id": "num_xxx",
    "phone_number": "+15875347708",
    "status": "active",
    "webhook_url": "https://your-app.com/webhooks/Sowa"
  }
}

GET /numbers

List numbers provisioned for this API key.

// Response
{
  "data": [
    {
      "id": "num_xxx",
      "phone_number": "+15875347708",
      "status": "active",
      "webhook_url": "https://your-app.com/webhooks/Sowa",
      "created_at": "2025-03-01T12:00:00Z"
    }
  ]
}

GET /numbers/:id

Get a single number by ID.

DELETE /numbers/:id

Release a number from this API key. Returns { "data": { "deleted": true } }.

GET /calls

List calls. Query params: limit (default 20, max 100), offset.

// Response
{
  "data": [
    {
      "id": "call_xxx",
      "phone_number": "+15551234567",
      "timestamp": "2025-03-01T14:30:00Z",
      "duration_seconds": 45,
      "intent_summary": "Customer needs same-day plumbing repair"
    }
  ],
  "meta": { "total": 150, "limit": 20, "offset": 0 }
}

GET /calls/:id

Fetch a single call with full transcript and intent.

// Response
{
  "data": {
    "id": "call_xxx",
    "phone_number": "+15551234567",
    "timestamp": "2025-03-01T14:30:00Z",
    "duration_seconds": 45,
    "intent": {
      "summary": "Customer needs same-day plumbing repair",
      "urgency": "high",
      "requested_action": "schedule_visit",
      "extracted_data": {}
    },
    "transcript": "Full transcript text..."
  }
}

POST /calls/:id/follow-up

Send SMS follow-up to the caller. Optional body: { "message": "Custom text" } (max 1600 chars). Omit for default thanks + booking link.

// Response
{
  "data": { "sent": true }
}

Webhooks

When a call completes, we POST to your webhook_url with:

{
  "event": "call.completed",
  "id": "call_xxx",
  "phone_number": "+15551234567",
  "timestamp": "2025-03-01T14:30:00Z",
  "duration_seconds": 45,
  "intent": {
    "summary": "Customer needs same-day plumbing repair",
    "urgency": "high",
    "requested_action": "schedule_visit",
    "extracted_data": {}
  },
  "transcript": "Full transcript..."
}

We include X-Sowa-Signature (HMAC-SHA256 of the body). Verify it using Sowa_WEBHOOK_SECRET (contact support for the secret). Respond with 200 within 10 seconds. We retry up to 3 times on failure.

Quick start

Provision a number:

curl -X POST https://sowaanswers.com/api/v1/numbers \
  -H "Authorization: Bearer lsk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url":"https://your-app.com/webhooks/Sowa","business_name":"Acme"}'

List numbers:

curl -X GET "https://sowaanswers.com/api/v1/numbers" \
  -H "Authorization: Bearer lsk_live_YOUR_KEY"

List calls:

curl -X GET "https://sowaanswers.com/api/v1/calls?limit=20" \
  -H "Authorization: Bearer lsk_live_YOUR_KEY"

Send follow-up SMS to a caller:

curl -X POST "https://sowaanswers.com/api/v1/calls/call_xxx/follow-up" \
  -H "Authorization: Bearer lsk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"Thanks for calling! Book here: https://acme.com/book"}'

Error responses

Errors use a consistent format:

{
  "error": {
    "code": "invalid_request",
    "message": "Missing required field: webhook_url"
  }
}

HTTP codes: 400 (validation), 401 (invalid key), 403 (forbidden), 404 (not found), 429 (rate limit), 500 (server error).