Skip to content
WhatIsUp.dev

Channels

Channels are the WhatsApp connections under your account. The full lifecycle lives in Concepts → Channels; this page covers the wire shape.

List channels

GET/v1/channelsBearer · API key

Returns every channel owned by the authenticated customer, newest first. Soft-deleted channels are excluded.

curl -s "$WHATISUP_API/v1/channels" \
  -H "Authorization: Bearer $WHATISUP_API_KEY"
{
  "data": [
    {
      "id": "8d653c66-e4ff-43ee-97da-3de5ad5680d4",
      "customer_id": "cust_01J6...",
      "name": "primary",
      "phone_number": "5511999999999",
      "status": "connected",
      "last_seen_at": "2026-05-01T12:34:56.000Z",
      "metadata": {},
      "created_at": "2026-04-12T08:11:32.000Z",
      "updated_at": "2026-05-01T12:34:56.000Z"
    }
  ]
}

Create channel

POST/v1/channelsBearer · API key
Schema · Request body
FieldTypeRequiredNotes
namestringrequired
metadataobjectoptional
issue_scoped_keybooleanoptional
curl -sX POST "$WHATISUP_API/v1/channels" \
  -H "Authorization: Bearer $WHATISUP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"support-line","metadata":{"team":"support"}}'

The response is a Channel object. Status starts at pending — the WhatsApp connection isn't allocated yet. Fetch the QR to start one.

Schema · Response · Channel
FieldTypeRequiredNotes
idstring · uuidrequired
customer_idstring · uuidrequired
namestringrequired
phone_numberstringrequired · nullable
status`pending` \| `qr` \| `connecting` \| `reconnecting` \| `connected` \| `disconnected` \| `logged_out` \| `stopped_by_user` \| `disabled_by_admin` \| `error` \| `failed`required
last_seen_atstring · ISO 8601required · nullable
metadataobjectrequired
healthobjectoptional · nullable
created_atstring · ISO 8601required
updated_atstring · ISO 8601required

Get one channel

GET/v1/channels/:idBearer · API key

Returns the single channel. 404s for channels that belong to a different customer (we never leak a "wrong tenant" 403; both look like "not found").

Get the current QR

GET/v1/channels/:id/qrBearer · API key

Lazily starts the WhatsApp connection if one isn't running, then waits up to ~10s for a QR. Returns data:image/png;base64,… plus the raw wire-format string (handy if you want to render with your own QR library) and an expires_at.

{
  "qr": "data:image/png;base64,iVBORw0KGgo...",
  "raw": "2@dPBI4Tg9Mc...,vlD4Pmkr...",
  "expires_at": "2026-05-01T12:35:25.000Z"
}

The dashboard's Pair flow uses SSE instead — it gets the QR pushed without polling.

Soft-delete

DELETE/v1/channels/:idBearer · API key

Stops the socket, wipes auth-state, marks the row deleted. Webhook deliveries that referenced this channel stay queryable for forensics.

curl -sX DELETE "$WHATISUP_API/v1/channels/8d653c66-e4ff-43ee-97da-3de5ad5680d4" \
  -H "Authorization: Bearer $WHATISUP_API_KEY"

Returns 204 No Content.

Number health

GET/v1/channels/:id/healthBearer · API key

How likely WhatsApp is to restrict the number: level (good, warning, danger, restricted), the reasons, the last 7 days' new contacts and reply rate, and what auto-protect is doing about it. Recomputed every 15 minutes; a WhatsApp restriction shows up at once. The channel.health webhook fires when the level changes. See Keeping numbers healthy.

Schema · Response
FieldTypeRequiredNotes
level`good` \| `warning` \| `danger` \| `restricted`required
reasonsarray<`low_reply_rate` \| `very_low_reply_rate` \| `new_number` \| `whatsapp_warning` \| `whatsapp_restricted`>required
new_contacts_7dnumberrequired
reply_rate_7dnumberrequired · nullable
age_daysnumberrequired
auto_protectobjectrequired
checked_atstring · ISO 8601required · nullable
channel_idstring · uuidrequired

WhatsApp limits

GET/v1/channels/:id/limitsBearer · API key

What WhatsApp itself reports for the number: new_chats (its quota for starting chats with people who never wrote to it) and restriction (a temporary block on messaging new people, with ends_at). The channel.limits webhook fires when either changes. The gateway never refuses a send over them — a send to someone new while they apply carries a warnings entry instead.

Schema · Response
FieldTypeRequiredNotes
new_chatsobjectrequired · nullable
restrictionobjectrequired · nullable
checked_atstring · ISO 8601required · nullable
channel_idstring · uuidrequired

Send pacing

GET/v1/channels/:id/pacingBearer · API key
PUT/v1/channels/:id/pacingBearer · API key

A random pause between this number's sends and "typing…" before each, plus the auto-protect switch (off unless you turn it on). While a number is paced its sends are queued (202, status: "queued") and go out one at a time.

Schema · Request body
FieldTypeRequiredNotes
auto_protectbooleanoptional
min_gap_secondsnumberoptional
max_gap_secondsnumberoptional
typingbooleanoptional
Schema · Response
FieldTypeRequiredNotes
auto_protectbooleanoptional
min_gap_secondsnumberoptional
max_gap_secondsnumberoptional
typingbooleanoptional
channel_idstring · uuidrequired

Proxy

GET/v1/channels/:id/proxyBearer · API key
PUT/v1/channels/:id/proxyBearer · API key
DELETE/v1/channels/:id/proxyBearer · API key
POST/v1/channels/:id/proxy/testBearer · API key

Routes the number's WhatsApp traffic through your SOCKS5, SOCKS4 or HTTP(S) proxy. PUT tests the proxy first (test: false skips it) and saves nothing when the test fails; POST …/test checks a url without saving it, or the saved proxy. Up to 10 tests per minute per account (429 proxy_test_limit). The password is stored encrypted and never returned.

Schema · Request body · PUT
FieldTypeRequiredNotes
urlstringrequired
testbooleanoptional
Schema · Response
FieldTypeRequiredNotes
channel_idstring · uuidrequired
configuredbooleanrequired
scheme`socks5` \| `socks5h` \| `socks4` \| `http` \| `https`required · nullable
hoststringrequired · nullable
portnumberrequired · nullable
usernamestringrequired · nullable
has_passwordbooleanrequired
updated_atstring · ISO 8601required · nullable
last_checkobjectrequired · nullable
Schema · Test result
FieldTypeRequiredNotes
okbooleanrequired
egress_ipstringrequired · nullable
countrystringrequired · nullable
latency_msnumberrequired · nullable
errorstringrequired · nullable
warningsarray<`rotating_ip` \| `country_mismatch`>optional
checked_atstring · ISO 8601required