API

Open API for commerce, messaging, campaigns, and contacts.

This reference focuses on the QirimWa endpoints that clients are most likely to integrate first for orders, bookings, WhatsApp messaging, and tenant-scoped operations. Every endpoint below is already present in the backend and documented with payload shape and realistic response samples.

Base setup

Integration basics

Base URL: `http://localhost:4000`

Authentication: use JWT via `Authorization: Bearer <token>` or rely on the `qirimwa_token` cookie when the caller is the QirimWa web app.

Response format: secured endpoints return JSON under a top-level `data` object.

Tenant scope: all contacts, conversations, direct messages, and campaigns are automatically scoped to the authenticated tenant.

Auth example
curl -X POST http://localhost:4000/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "owner@qirimwa.local",
    "password": "qirimwa12345"
  }'

{
  "token": "<jwt>",
  "user": {
    "id": "f278570a-3aa9-41a9-a4ce-349c117ce628",
    "tenantId": "b8f2f032-9c5a-46f8-94de-b38f3c4971e8",
    "role": "owner",
    "name": "QirimWa Owner",
    "email": "owner@qirimwa.local"
  }
}
Coverage

Integration groups

Contacts
GET /contacts
POST /contacts
Messages
GET /conversations
GET /conversations/:id
POST /conversations/:id/reply
POST /whatsapp/send-message
POST /whatsapp/send-template
Campaigns
GET /campaigns
POST /campaigns
Contacts

Manage customer records inside the tenant workspace

Endpoint

List contacts

GET/contacts

Returns all contacts in the authenticated tenant workspace. This is the primary entry point for contact sync and CRM-side lookup inside QirimWa.

Sample request
curl http://localhost:4000/contacts \
  -H "Authorization: Bearer <token>"
Sample response
{
  "data": [
    {
      "id": "2c4e0f0c-f11c-4fd4-bec8-c1a2e7fa612a",
      "tenantId": "b8f2f032-9c5a-46f8-94de-b38f3c4971e8",
      "name": "Maya Santoso",
      "phone": "+628123456789",
      "email": "maya@example.com",
      "tags": ["vip", "jakarta"],
      "pipelineStage": "qualified",
      "lastMessageAt": "2026-04-04T08:45:12.000Z",
      "createdAt": "2026-04-01T10:15:00.000Z"
    }
  ]
}
Endpoint

Create contact

POST/contacts

Creates a new tenant-scoped contact so the workspace can use it in inbox workflows, campaign targeting, and customer history.

Payload
Field
Type
Required
Description
name
string
Yes
Contact display name.
phone
string
Yes
Phone number in customer-facing format.
email
string
No
Optional email address.
tags
string[]
No
Optional labels for segmentation or operator context.
pipelineStage
string
No
Optional lightweight CRM stage.
Sample request
curl -X POST http://localhost:4000/contacts \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Maya Santoso",
    "phone": "+628123456789",
    "email": "maya@example.com",
    "tags": ["vip", "jakarta"],
    "pipelineStage": "qualified"
  }'
Sample response
{
  "data": {
    "id": "2c4e0f0c-f11c-4fd4-bec8-c1a2e7fa612a",
    "tenantId": "b8f2f032-9c5a-46f8-94de-b38f3c4971e8",
    "name": "Maya Santoso",
    "phone": "+628123456789",
    "email": "maya@example.com",
    "tags": ["vip", "jakarta"],
    "pipelineStage": "qualified",
    "createdAt": "2026-04-04T09:12:00.000Z"
  }
}
Messages

Read inbox state and trigger outbound delivery

Endpoint

List conversations

GET/conversations

Returns the inbox conversation list for the tenant. Use this to build conversation sidebars or sync message operations into an external console.

Sample request
curl http://localhost:4000/conversations \
  -H "Authorization: Bearer <token>"
Sample response
{
  "data": [
    {
      "id": "5102604a-467f-4ba4-bd19-b8b95f6d3b6c",
      "contactName": "Maya Santoso",
      "contactPhone": "+628123456789",
      "lastMessagePreview": "Need ETA before I confirm",
      "lastMessageAt": "2026-04-04T09:10:00.000Z",
      "state": "open",
      "assignedAgentName": "Nadia",
      "unreadCount": 2,
      "aiPausedUntilHuman": true
    }
  ]
}
Endpoint

Get conversation detail

GET/conversations/:id

Loads message history, conversation state, assignment, and contact context for a specific conversation.

Replace `:id` with a valid conversation UUID from `GET /conversations`.
Sample request
curl http://localhost:4000/conversations/5102604a-467f-4ba4-bd19-b8b95f6d3b6c \
  -H "Authorization: Bearer <token>"
Sample response
{
  "data": {
    "id": "5102604a-467f-4ba4-bd19-b8b95f6d3b6c",
    "state": "open",
    "assignedAgentId": "f278570a-3aa9-41a9-a4ce-349c117ce628",
    "assignedAgentName": "Nadia",
    "aiPausedUntilHuman": true,
    "contact": {
      "name": "Maya Santoso",
      "phone": "+628123456789",
      "tags": ["vip", "jakarta"]
    },
    "messages": [
      {
        "id": "585b66ba-eb66-40fd-bd14-fc42d509f10f",
        "direction": "inbound",
        "body": "Hi, is order NS-2045 still arriving today?",
        "status": "read",
        "createdAt": "2026-04-04T09:12:00.000Z"
      }
    ]
  }
}
Endpoint

Reply from inbox

POST/conversations/:id/reply

Queues an outbound message from the human operator workflow and writes the message immediately into QirimWa conversation history.

This route also pauses AI for the conversation after a human reply is inserted.
Payload
Field
Type
Required
Description
phoneNumberId
string
Yes
Connected WhatsApp phone number ID.
to
string
Yes
Destination phone number.
body
string
Yes
Reply text content.
Sample request
curl -X POST http://localhost:4000/conversations/5102604a-467f-4ba4-bd19-b8b95f6d3b6c/reply \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumberId": "1234567890",
    "to": "+628123456789",
    "body": "The parcel is on route and should arrive before 18:00 local time."
  }'
Sample response
{
  "data": {
    "conversationId": "5102604a-467f-4ba4-bd19-b8b95f6d3b6c",
    "queued": true
  }
}
Endpoint

Send direct text message

POST/whatsapp/send-message

Queues a direct outbound WhatsApp text through the connected channel without needing an inbox-originated human reply flow.

Payload
Field
Type
Required
Description
phoneNumberId
string
Yes
Connected WhatsApp phone number ID.
to
string
Yes
Destination phone number.
body
string
Yes
Message body text.
Sample request
curl -X POST http://localhost:4000/whatsapp/send-message \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumberId": "1234567890",
    "to": "+628123456789",
    "body": "Your order has been scheduled for delivery today."
  }'
Sample response
{
  "data": {
    "queued": true,
    "jobId": "41"
  }
}
Endpoint

Send WhatsApp template

POST/whatsapp/send-template

Queues an approved WhatsApp template message using the connected Business account.

Payload
Field
Type
Required
Description
phoneNumberId
string
Yes
Connected WhatsApp phone number ID.
to
string
Yes
Destination phone number.
templateName
string
Yes
Approved template name from Meta.
languageCode
string
No
Template language code. Defaults to `en_US`.
Sample request
curl -X POST http://localhost:4000/whatsapp/send-template \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumberId": "1234567890",
    "to": "+628123456789",
    "templateName": "promo_april",
    "languageCode": "id"
  }'
Sample response
{
  "data": {
    "queued": true,
    "jobId": "42"
  }
}
Campaigns

Queue and monitor broadcast execution through QirimWa

Endpoint

List campaigns

GET/campaigns

Returns tenant campaign records with current status so client apps can monitor scheduled or completed outreach.

Sample request
curl http://localhost:4000/campaigns \
  -H "Authorization: Bearer <token>"
Sample response
{
  "data": [
    {
      "id": "f79ec94c-8108-4653-b994-f8b2d73f5f1a",
      "name": "April promo blast",
      "templateName": "promo_april",
      "status": "scheduled",
      "scheduledAt": "2026-04-10T09:00:00.000Z",
      "recipientCount": 2,
      "deliveredCount": 0,
      "failedCount": 0
    }
  ]
}
Endpoint

Create campaign

POST/campaigns

Creates and queues a campaign for later execution through QirimWa workers.

Payload
Field
Type
Required
Description
name
string
Yes
Campaign display name.
phoneNumberId
string
Yes
Connected WhatsApp phone number ID used for sending.
templateId
uuid | null
No
Optional internal QirimWa template ID.
templateName
string
Yes
Approved template name used for delivery.
scheduledAt
ISO datetime
Yes
Planned execution time in UTC.
recipients
string[]
Yes
One or more phone numbers for delivery.
Sample request
curl -X POST http://localhost:4000/campaigns \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "April promo blast",
    "phoneNumberId": "1234567890",
    "templateId": "11111111-2222-3333-4444-555555555555",
    "templateName": "promo_april",
    "scheduledAt": "2026-04-10T09:00:00.000Z",
    "recipients": ["+628123456789", "+628987654321"]
  }'
Sample response
{
  "data": {
    "queued": true,
    "jobId": "77",
    "campaignId": "f79ec94c-8108-4653-b994-f8b2d73f5f1a"
  }
}
Integration note

Use QirimWa as the operational layer.

`POST /conversations/:id/reply` is the right path when a human operator sends the message from the inbox and QirimWa should update conversation history instantly.

`POST /whatsapp/send-message` and `POST /whatsapp/send-template` are more appropriate for service-to-service delivery where the caller already knows the outbound target and phone number ID.

`POST /campaigns` is tenant-scoped and worker-driven, so scheduled delivery and operational tracking remain centralized in QirimWa rather than spread across external client logic.