developers
ES Sign up

Get started

Get a WhatsApp number

If you don't have a number for the Cloud API, use a heysteff one. It's a United States (+1) number that heysteff already verified with Meta: when you connect WhatsApp you pick it in Meta's window and it goes into your WhatsApp Business account. No SMS or calls reach any phone of yours.

Who can use it#

Step by step#

  1. In the dashboard, open Settings → Channels and, under the option to connect WhatsApp, tap Use a heysteff number. It only shows when your plan includes one and numbers are available.
  2. In the heysteff window keep "Use a heysteff number" selected and tap Continue with Meta. We reserve a number for you for 30 minutes.
  3. In Meta's window, create or choose your WhatsApp Business account and, at the number step, pick the one shown with the briefcase icon: that's the heysteff one. Don't pick "Use a virtual number" and don't add another number.
  4. Finish connecting. The number shows as connected in Channels and works with POST /v1/messages like any Cloud API number.

If you close the window before finishing, the number goes back to the pool and you can try again.

From your code (API, SDK and CLI)#

You can request the number from your code, but you can't skip Meta's step: Meta only puts a number into a business's WhatsApp account inside its signup window, with someone who logs in with Facebook and picks the number. The API reserves the number and returns connect_url, the link to that window. Open it yourself, or send it to whoever manages the business's WhatsApp account; when they finish, the number is connected in your workspace.

  1. POST /v1/numbers reserves a number for 30 minutes and returns connect_url. The link is single use and expires at connect_url_expires_at. If you ask again while a reservation is live, you get the same number, a renewed deadline and a new link (reused: true).
  2. Someone opens connect_url in a browser and follows steps 3 and 4 above.
  3. GET /v1/numbers shows the number with state: "connected" and its channel_connection_id, which you use in POST /v1/messages.
curl
# Reserve a number and get the connect link
curl -X POST https://app.heysteff.com/api/v1/numbers \
  -H "Authorization: Bearer $HEYSTEFF_API_KEY"

# Your numbers, the plan quota and whether you can get another one
curl https://app.heysteff.com/api/v1/numbers \
  -H "Authorization: Bearer $HEYSTEFF_API_KEY"
JSON
{
  "data": {
    "number": {
      "id": "6f1c2a8e-3b4d-4e5f-9a0b-1c2d3e4f5a6b",
      "phone_number": "+15550100199",
      "country": "US",
      "state": "reserved",
      "reserved_until": "2026-11-05T12:30:00.000Z",
      "connected_at": null,
      "channel_connection_id": null,
      "display_name": { "name": null, "status": null, "rejection_reason": null, "requested_at": null }
    },
    "connect_url": "https://app.heysteff.com/connect/whatsapp?token=…&pool=1",
    "connect_url_expires_at": "2026-11-05T12:30:00.000Z",
    "reused": false
  }
}
TypeScript
import { Heysteff } from '@heysteff/sdk';

const heysteff = new Heysteff({ apiKey: process.env.HEYSTEFF_API_KEY });

const { number, connect_url } = await heysteff.numbers.reserve();
console.log(`Open ${connect_url} to connect ${number.phone_number}`);

const { data, plan } = await heysteff.numbers.list();
await heysteff.numbers.requestDisplayName(data[0].id, 'Aurora Store');
await heysteff.numbers.release(number.id); // only if nobody connected it
Terminal
heysteff numbers reserve
heysteff numbers list
heysteff numbers display-name 6f1c2a8e-3b4d-4e5f-9a0b-1c2d3e4f5a6b "Aurora Store"
heysteff numbers release 6f1c2a8e-3b4d-4e5f-9a0b-1c2d3e4f5a6b
EndpointScopeWhat it does
GET /v1/numbersnumbers:readYour numbers (reserved, connected or disconnected), the display name and its review, the plan quota (plan.limit, plan.used) and whether you can get another one (offer).
GET /v1/numbers/{id}numbers:readOne number.
POST /v1/numbersnumbers:writeReserves a number and returns connect_url. 402 plan_limit if your plan has no numbers left; 409 wa_pool_empty if none are available right now.
DELETE /v1/numbers/{id}numbers:writeReleases a reservation nobody connected: the number goes back to the pool. A reservation on hold because a signup finished in Meta without confirming the number returns 409 wa_pool_number_on_hold.
POST /v1/numbers/{id}/display-namenumbers:writeAsks Meta for a new display name ({"display_name": "…"}). If Meta rejects it, returns 424 meta_display_name_rejected.

A connected number can't be released through the API. It's already in your WhatsApp account: if heysteff released it, someone else could buy it and receive your account's verification codes. DELETE returns 409 wa_pool_number_connected. To stop using it, disconnect the channel in Settings → Channels and write to [email protected].

Test keys (sk_test_) can't request numbers: create an sk_live_ key with the numbers:read and numbers:write scopes.

Display name#

When you connect, we ask Meta for your business name as the number's display name. Meta reviews it and the status shows in Channels ("Display name"). Once it's approved, we register the number again so your customers see the new name. You can request another name from Channels ("Change the display name"), with POST /v1/numbers/{id}/display-name or with the MCP.

Verification, display name and business profile#

For any WhatsApp Cloud number in your workspace (a heysteff one or your own), with its channel_connection_id and an sk_live_ key:

EndpointScopeWhat it does
GET /v1/whatsapp-numbers/{id}numbers:readThe number's health, live from Meta: quality (quality_rating: GREEN, YELLOW or RED), messaging limit (messaging_limit_tier), number status, the display name and its review (display_name) and business verification (business_verification, with verify_url, the Meta Business security center link where you verify). If one part fails, the rest still answers and the reason goes in errors.
GET /v1/whatsapp-numbers/{id}/business-profilenumbers:readThe business profile your customers see: about, description, address, email, websites, vertical and profile_picture_url.
PATCH /v1/whatsapp-numbers/{id}/business-profilenumbers:writeChanges the fields you send. The picture goes in profile_picture_url: a public https URL of a JPG or PNG (square, 192×192 px or larger, up to 5 MB) or the url from POST /v1/media.
curl
curl -X PATCH https://app.heysteff.com/api/v1/whatsapp-numbers/3a2b1c0d-9e8f-4a7b-8c6d-5e4f3a2b1c0d/business-profile \
  -H "Authorization: Bearer $HEYSTEFF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "about": "We answer Monday to Saturday",
    "websites": ["https://aurora-store.com"],
    "vertical": "RETAIL",
    "profile_picture_url": "https://aurora-store.com/logo.png"
  }'

Business verification is not done by API: Meta asks for it in its security center (verify_url). A heysteff number's display name is requested with POST /v1/numbers/{id}/display-name; your own number's, in WhatsApp Manager. In the SDK: heysteff.whatsappNumbers.get, getBusinessProfile and updateBusinessProfile; over MCP: get_whatsapp_number_status, get_whatsapp_business_profile and update_whatsapp_business_profile. The number's calls are set up in WhatsApp calls.

Who charges for messages#

Meta charges you for messages directly, on your WhatsApp account's card: heysteff isn't a Meta Solution Partner and doesn't bill those messages. Add a payment method in WhatsApp Manager before you go past Meta's free tier.

From your AI (MCP)#

Your AI reserves and hands you the link; a person finishes Meta's step in the browser.

Limits#