Quickstart
1. Workspace login
Log in as an owner or admin.
Workspace routes use a Cognito workspace ID token. Use it for admin/operator routes such as line token rotation, inbox reads, and workspace sends.
curl -X POST 'https://app.ezw.solutions/api/auth/login' \
-H 'Content-Type: application/json' \
-d '{
"email": "owner@example.com",
"password": "password"
}'
2. Create line token
Create or rotate a line-scoped API token.
Channel API routes use a line API token that starts with ezw_line_. It is scoped to exactly one WhatsApp line.
curl -X POST 'https://app.ezw.solutions/api/lines/{lineId}/api-token' \
-H 'Authorization: Bearer {idToken}'
3. Check health
Confirm the line is sendable before sending.
Do not flatten health into connected or disconnected. The response separates lifecycle, effective send state, and sendability.
curl 'https://app.ezw.solutions/api/v1/health?wakeup=false&channel_type=web' \
-H 'Authorization: Bearer {lineApiToken}'
4. Send idempotently
Queue a message with an idempotency key.
The API returns 202 because delivery is asynchronous. Workers reconcile provider delivery later.
curl -X POST 'https://app.ezw.solutions/api/v1/messages/text' \
-H 'Authorization: Bearer {lineApiToken}' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: client-order-123' \
-d '{
"to": "+972501234567",
"body": "Your order is ready"
}'
Base URLs
Production
Workspace API: https://app.ezw.solutions
Channel API v1: https://app.ezw.solutions/api/v1
Local operator runtime
Workspace API: http://127.0.0.1:3010
Channel API v1: http://127.0.0.1:3010/api/v1
Authentication
| API family |
Token |
Use for |
Do not use for |
| Channel API v1 |
Authorization: Bearer ezw_line_... |
Machine-to-machine health, text sends, URL media sends, and line webhook configuration for one line. |
Workspace admin/operator routes, inbox UI actions, team management, or cross-line operations. |
| Workspace API |
Authorization: Bearer {idToken} |
Logged-in owner/admin/operator actions: line token management, QR, inbox, assignments, notes, image sends, signed media reads. |
Channel API v1 routes. |
Current support matrix
| Capability |
Endpoint |
Auth |
Status |
| Check line health |
GET /api/v1/health |
Line API token |
Supported. |
| Send direct text |
POST /api/v1/messages/text |
Line API token |
Supported, including optional CTA URL button. |
| Send URL media |
POST /api/v1/messages/media |
Line API token |
Supported for external URL image, video, audio, and document. |
| Configure line webhooks |
GET/POST /api/v1/webhooks |
Line API token |
Supported for current line. |
| Configure webhooks from workspace |
GET/POST /api/lines/{lineId}/webhooks |
Workspace ID token |
Supported for allowed owner/admin users. |
| Create or rotate line token |
POST /api/lines/{lineId}/api-token |
Workspace ID token |
Supported for users allowed to manage the line. |
| Workspace reply |
POST /api/lines/{lineId}/send |
Workspace ID token |
Supported for text and one image attachment. |
| Read inbox data |
GET /api/conversations, GET /api/conversations/{conversationId}/messages |
Workspace ID token |
Supported with tenant and line visibility checks. |
| Fetch archived media |
GET /api/attachments/{attachmentId}/url |
Workspace ID token |
Supported through short-lived signed URLs. |
| Live update hints |
GET /api/live/stream |
Workspace ID token |
Supported through SSE hints. Refetch durable APIs for truth. |
Check channel health
Use this before sending and before diagnosing client automation failures. wakeup=false makes the check read-only.
curl -X GET 'https://app.ezw.solutions/api/v1/health?wakeup=false&channel_type=web' \
-H 'Authorization: Bearer {lineApiToken}'
{
"channelId": "{lineId}",
"channelType": "web",
"wakeupRequested": false,
"health": {
"status": {
"code": 4,
"text": "AUTH"
}
},
"line": {
"displayName": "Billing",
"phoneNumber": "+972...",
"lifecycleState": "connected",
"effectiveSendState": "sendable",
"sendable": true
}
}
Send text with Channel API v1
Use this for machine-to-machine sends from the line resolved by the line API token. Use exactly one target: to or conversationId.
curl -X POST 'https://app.ezw.solutions/api/v1/messages/text' \
-H 'Authorization: Bearer {lineApiToken}' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: send-once-123' \
-d '{
"to": "+972501234567",
"body": "Test message",
"ctaUrlButton": {
"displayText": "Open offer",
"url": "https://example.com/offers/123"
}
}'
| Field |
Required |
Notes |
to |
Conditional |
Direct recipient phone number. Use one of to or conversationId. |
conversationId or conversation_id |
Conditional |
Use this for webhook replies when available. Do not derive phone numbers from provider-specific ids. |
body |
Yes |
Text body. Empty strings are rejected. |
ctaUrlButton |
No |
Requires displayText or text, plus an HTTP/HTTPS URL. |
Idempotency-Key |
Recommended |
Header takes precedence over body idempotencyKey. |
Workspace API essentials
Workspace routes act as logged-in users. They enforce organization scope, line visibility, and membership permissions.
Send workspace reply
curl -X POST 'https://app.ezw.solutions/api/lines/{lineId}/send' \
-H 'Authorization: Bearer {idToken}' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: workspace-send-001' \
-d '{
"conversationId": "{conversationId}",
"bodyText": "Thanks, I am checking this now."
}'
Send one workspace image
curl -X POST 'https://app.ezw.solutions/api/lines/{lineId}/send' \
-H 'Authorization: Bearer {idToken}' \
-H 'Idempotency-Key: image-send-001' \
-F 'conversationId={conversationId}' \
-F 'bodyText=Optional caption text' \
-F 'media=@/absolute/path/photo.jpg;type=image/jpeg'
Webhooks
Webhooks let client systems receive durable event deliveries for the configured line. Configure by line token or by workspace token.
Line token
Configure current line webhook
curl -X POST 'https://app.ezw.solutions/api/v1/webhooks' \
-H 'Authorization: Bearer {lineApiToken}' \
-H 'Content-Type: application/json' \
-d '{
"targetUrl": "https://agency.example.com/ezw/webhook",
"events": ["messages.post", "statuses.post", "chats.post"],
"payloadFormat": "whapi",
"enabled": true,
"persistent": true
}'
Workspace token
Configure webhook for a managed line
curl -X POST 'https://app.ezw.solutions/api/lines/{lineId}/webhooks' \
-H 'Authorization: Bearer {idToken}' \
-H 'Content-Type: application/json' \
-d '{
"targetUrl": "https://agency.example.com/ezw/webhook",
"events": ["messages.post", "statuses.post"],
"enabled": true
}'
Webhook deliveries are sent as JSON with X-EZW-Webhook-Event, X-EZW-Line-Id, X-EZW-Webhook-Id, and X-EZW-Delivery-Id headers. Return any 2xx status to accept a delivery.
Read the webhook guide
Read inbox data
Use workspace tokens for inbox reads. SSE events are hints only; clients must refetch durable DB-backed APIs.
curl 'https://app.ezw.solutions/api/conversations?lineId={lineId}&limit=25' \
-H 'Authorization: Bearer {idToken}'
curl 'https://app.ezw.solutions/api/conversations/{conversationId}/messages?limit=50' \
-H 'Authorization: Bearer {idToken}'
curl -N 'https://app.ezw.solutions/api/live/stream' \
-H 'Authorization: Bearer {idToken}' \
-H 'Accept: text/event-stream'
Common status codes
| Status |
Meaning |
200 | Read succeeded. |
201 | Token or webhook configuration was created or updated. |
202 | Send was durably queued or an idempotent attempt already existed. |
400 | Invalid query, payload, target, media, webhook, or idempotency key. |
401 | Missing or invalid bearer token. |
403 | Authenticated actor is not allowed to perform the operation. |
404 | Tenant-scoped resource was not visible or does not exist. |
409 | Optimistic conflict or line not currently sendable. |
501 | Required source of truth or media bucket is not configured. |
Non-negotiable implementation boundaries
- The API is for support inbox workflows, client notifications, and scoped customer-admin campaign workflows, not cold outbound tooling.
- Every customer-owned record is organization-scoped.
- Line API tokens are scoped to exactly one WhatsApp line.
- Outbound sends are idempotent and asynchronous.
- Provider echoes must not be treated as authoritative assignment or ownership state.
- Redis and live events are never the source of truth. Refetch DB-backed APIs.
- Session credentials and provider runtime details stay behind EZWhatsApp provider contracts.