Development

Wāwā Assistant External Integration API — /api/v1/

Usage guide for external integrators.

  • Base URL: https://<host>/api/v1/ (<host> is provided by the platform operator)
  • Protocol: HTTPS + JSON (request body Content-Type: application/json; all responses are JSON)
  • Scope: email account discovery (read-only) plus email draft create / query / delete. Everything else (voice, reports, email content, …) is internal and not exposed.

1. Authentication

1.1 Obtaining a Token

Exchange a platform user's credentials for a long-lived access token:

POST /api/v1/token/
{
  "username": "your-username",
  "password": "your-password"
}

Successful response:

{
  "access": "<jwt>"
}
  • Tokens are valid for 90 days by default and there is no refresh token: when a token expires you get a 401 — simply call this endpoint again for a new one.
  • The token carries the user's full identity; every endpoint's data visibility equals what that user owns. Keep it safe — a leaked token is equivalent to leaked credentials (there is currently no revocation mechanism).

1.2 Sending the Token

Include a Bearer header on every subsequent request:

Authorization: Bearer <jwt>

Note: /api/v1/ accepts JWT only — browser sessions get 401. Conversely, this JWT is not valid for other namespaces (calling /api/ with it returns 403).

2. email-config — Email Account Discovery (Read-Only)

Every draft must be attached to an email account (config). Use these endpoints to find the available config ids.

GET /api/v1/email-config/
GET /api/v1/email-config/{id}/

Returns only configs owned by the token user that are not archived. The response is a fixed set of five fields and never includes credentials, OAuth data, or folder information:

FieldDescription
idConfig id — the value for config when creating a draft
email_addressThe email address
providerEmail provider; currently only OUTLOOK
statusactive / syncing / inactive / auth_failed
created_atCreation time

The list is ordered by email_address; pagination is described in §4.

3. email-draft — Email Drafts

3.1 Creating a Draft

POST /api/v1/email-draft/
{
  "config": 3,
  "in_reply_to": null,
  "to_recipients": ["alice@example.com"],
  "cc_recipients": [],
  "bcc_recipients": [],
  "subject": "Quarterly report",
  "content": "<p>Hello…</p>",
  "content_type": "html"
}
FieldRequiredDescription
configYesId of the email account to attach to; must belong to the token user and not be archived, otherwise a 400 field error
in_reply_toNoId of the email being replied to; must be visible to the user and belong to the same account as config, otherwise 400. Omit it to create a fresh (non-reply) draft
to_recipients / cc_recipients / bcc_recipientsNoArrays of email addresses
subjectNoSubject line
contentNoBody
content_typeNotext or html

On success the API returns 201 with the full draft object (including the read-only fields below). Once stored, the draft is automatically pushed to the provider's (Outlook's) drafts folder — no extra call needed. Non-Outlook accounts end up in sync_failed.

3.2 Querying Drafts

GET /api/v1/email-draft/
GET /api/v1/email-draft/{id}/
  • Only the user's own drafts; accessing someone else's draft returns 404.
  • The list supports filters, combinable: ?config=<id>, ?status=<status>; pagination in §4.
  • Besides the writable fields from creation, responses include these read-only fields:
FieldDescription
statusDraft status, see §3.4
last_errorError message from the most recent failed sync
provider_draft_idRemote (Outlook) draft id; empty until sync succeeds
sent_atSend time (reserved for the future send path; currently always empty)
created_at / updated_atCreation / update time

Syncing is asynchronous: after creating, poll status until it reaches synced or sync_failed (the API does not provide webhooks).

3.3 Drafts Are Immutable: Modify = Delete + Re-Create

A draft cannot be changed after creation — there is no PUT/PATCH (both always return 405). To "edit" a draft:

  • 1.DELETE /api/v1/email-draft/{id}/
  • 2.POST /api/v1/email-draft/ again with the new content

The new draft is pushed to Outlook as usual; the old remote draft is cleaned up by the deletion flow.

3.4 Draft State Machine

draft ──► syncing ──► synced
                └───► sync_failed
StatusMeaningDeletable
draftStored, waiting to sync
syncingBeing pushed to Outlook❌ (409 — retry later)
syncedPresent in the Outlook drafts folder
sync_failedSync failed (retries exhausted or unsupported account); see last_error
sending / sentReserved for the send path❌ (409)

3.5 Deleting a Draft

DELETE /api/v1/email-draft/{id}/
  • Only drafts in draft / synced / sync_failed can be deleted; any other status returns 409.
  • Success always returns 204. The draft becomes immediately invisible to the API (subsequent GET returns 404; it disappears from lists).
  • If the draft had already synced to Outlook, the remote draft is cleaned up asynchronously by a background task — nothing for the integrator to do.

4. Pagination

List endpoints use page-number pagination, fixed at 10 items per page, with ?page=N:

{
  "count": 23,
  "next": "https://<host>/api/v1/email-draft/?page=2",
  "previous": null,
  "results": [ … ]
}

5. Error Semantics

HTTP statusScenario
400Request body validation failed: malformed fields, or config / in_reply_to not owned by the user or violating the ownership rules (the body contains field-level errors)
401Missing / invalid / expired token (response carries WWW-Authenticate: Bearer) — obtain a new token
404Resource does not exist, or does not belong to the token user
405Method not allowed (e.g. PUT/PATCH on a draft — drafts are immutable)
409Draft status does not allow deletion (syncing / sending / sent)

6. End-to-End Example (curl)

HOST="https://<host>"

# 1. Obtain a token
TOKEN=$(curl -s -X POST "$HOST/api/v1/token/" \
  -H "Content-Type: application/json" \
  -d '{"username": "me", "password": "secret"}' | jq -r .access)

# 2. Discover available email accounts
curl -s "$HOST/api/v1/email-config/" -H "Authorization: Bearer $TOKEN"

# 3. Create a draft
curl -s -X POST "$HOST/api/v1/email-draft/" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "config": 3,
    "to_recipients": ["alice@example.com"],
    "subject": "Quarterly report",
    "content": "<p>Hello…</p>",
    "content_type": "html"
  }'

# 4. Poll sync status
curl -s "$HOST/api/v1/email-draft/42/" -H "Authorization: Bearer $TOKEN"

# 5. Delete the draft
curl -s -X DELETE "$HOST/api/v1/email-draft/42/" -H "Authorization: Bearer $TOKEN"

7. Explicitly Out of Scope

  • Attachment upload / download
  • Sending email through the API (the product stance is "Wāwā prepares, you send" — sending happens in the user's email client)
  • Webhook event notifications (poll status instead)
  • Fine-grained scopes, token revocation, batch endpoints

If you need any of the above, contact the platform operator.