Builders Program

Build with us for a whole month. Unlimited usage and add-ons, weekly calls and your own Slack channel.

Learn more
Polymorfa

Command Palette

Search for a command to run...

Sandbox

Test on WhatsApp without a real phone

Test numbers are WhatsApp accounts on a simulated network. They pair, send and receive on the same runtime as real numbers, through the same API and webhooks, and never reach a real person.

Test numbers per project
5
With the Simulation add-on
50
Per online test number-day
0 credits
Test event fixtures
9

Test numbers

A real runtime on a simulated network.

Each test number is an ordinary Linked Devices session. It connects to a simulated WhatsApp network instead of WhatsApp's servers, so your code runs the path a real number runs.

Real pairing, not mocks. The runtime shows a pairing code and the simulated phone scans it, the way a person scans one on a real phone.
The full session API. Messages and media, edits and receipts, contacts, groups, channels, presence, privacy, profiles, labels and catalogs.
  • Project-only recipients. Direct messages reach other test numbers in the project. Any other recipient returns 404.
  • Ready on creation. A new test number is connected at once and stays linked across restarts.
  • 243 countries. Pick a country and get a number in its local format.

Inspector and phone controls

Both ends of the conversation.

Open a test number in the Polymorfa Inspector desktop app, and act as its phone from the Console or the API.

Open it in Inspector. Inspector links as one more device on macOS, Windows or Linux and shares chats and state with your API session.
Act as the phone. List linked devices, send as the phone or unlink a device, the way a person does from Linked devices.

Scenarios

Test the paths that break in production.

Choose how a test number replies and whether its sends fail, and start it with chat history.

Echo replies. Set replyBehavior to echo and the number answers with your text, so a conversation test has a reply to wait for.
Rejected sends. Set failureScenario to reject-send and its sends fail, so you can test retries and alerts.
Chat history. Upload up to 100 messages as a fixture and start the number with them.

Test events

Every webhook, on demand.

Fire an event for a test number. It reaches your webhooks and the events API in the production format, marked as a test.

Signed like production. Each event is signed with your endpoint's secret and carries source: test, so your handler verifies it and can tell it apart.
Nine fixtures with overrides. From message.received to template.status. Override the sender, text, media type, status or failure reason.
  • Real round trips. Set fromSession and another test number sends the message, so you can reply to it.
  • Safe to retry. Repeat a trigger with the same Idempotency-Key and you get the same event.
  • Audited. Every trigger is recorded in your team's audit log.

In your code

Tests that run in CI.

Create test numbers, act as the phone and fire events from your test suite.

test-number.ts
import { MessagingClient } from "@polymorfa/sdk";

const messaging = new MessagingClient({
  credential: { type: "apiKey", value: process.env.POLYMORFA_KEY! },
});

const link = await messaging.quickLinks.create({
  projectId,
  configuration: {
    testing: {
      country: "BR",
      configuration: {
        accountType: "business",
        replyBehavior: "echo",
        failureScenario: "none",
      },
    },
  },
});

API surface

The Sandbox API.

Test numbers use the regular Messaging API. These routes add setup, phone controls and test events.

Test numbers

  • POST/messaging/quicklinksReserve a test number with configuration.testing
  • POST/quicklink/{token}/testing/startStart the reserved simulated account
  • POST/messaging/testing/{project}/history-fixturesUpload chat history

Phone controls

  • GET/messaging/testing/{project}/numbers/{session}/phoneRead the phone and its linked devices
  • POST…/numbers/{session}/phone/messagesSend a message as the phone
  • POST…/numbers/{session}/phone/devices/{deviceId}/unlinkUnlink a companion device

Test events

  • POST/messaging/testing/{project}/eventsFire a signed test event
  • GET/messaging/testing/{project}/events/fixturesList fixtures and their overrides

Fixtures

  • Eventmessage.receivedAn inbound message
  • Eventmessage.failedA send that failed
  • Eventcall.missedA call nobody answered
  • Eventsession.restriction_updatedA restriction change

Start with a free number

Your first real number is free. Add more numbers on Pay-As-You-Go.