403 when access is absent.
Every active team can create QuickLinks for testing numbers. QuickLinks for real
numbers require Pay-As-You-Go; see
Free team limits. Creating a link does not fund a
number: pairing checks the number’s funding before starting the connection. Frozen
teams and inactive projects cannot start onboarding. Meta Cloud API and Test Numbers
retain their separate access requirements.
Links remain active until the number connects or you cancel them. They do not
grant messaging access.
Meta Cloud API onboarding requires team beta access and an active project.
Configuring Meta app IDs alone does not enable it. Unavailable optional Meta Cloud API
choices are hidden; a project that forces Meta Cloud API cannot issue a link without
access. Withdrawing access stops new onboarding and history requests while preserving
reconciliation of operations already accepted by Meta. A pending invitation can report
cloud_onboarding_unavailable; this does not report success or delete Meta assets.
Team-owned Meta apps
Teams with an active Branded QuickLink add-on and Meta Cloud API onboarding access can configure their own Meta app and Embedded Signup configuration for QuickLinks. Your app needs the Meta permissions and approvals required for the numbers you connect. Saving credentials does not grant those approvals or enable onboarding access. The app secret is submitted once and is not returned by the settings page. Replacing a configuration applies to new invitations; existing invitations keep their saved app. Disconnecting revokes saved configurations for unfinished onboarding. It does not delete customer-owned Meta assets or disconnect established numbers. A payment dispute blocks use of the saved app until the dispute is resolved; its settings remain available to view.When Branded QuickLink ends
Your team-owned app stays in use while the add-on is active, after you cancel renewal until the paid period ends, and during the three-day payment recovery period after a failed renewal payment. When access ends:- New QuickLinks and Customer invitations use Polymorfa’s standard Meta app and presentation. Creating them does not fail because of your saved app.
- Unfinished invitations that were issued with your team-owned app stop before their next Meta step. Send a new link.
- Connected Numbers keep running. Polymorfa does not stop, disconnect or delete a Number because the add-on ended or because you disconnected your app.
- Your saved app configuration is kept until you disconnect it. It becomes usable again when the add-on is active again.
Check and renew Meta Cloud API credentials
Polymorfa periodically validates the saved Meta credentials of each Number connected through the Meta Cloud API. Each check confirms that the access token is valid, that it has thewhatsapp_business_messaging and
whatsapp_business_management permissions for the WhatsApp Business Account,
that Meta reports the phone number as connected, and that the app is subscribed
to the account’s webhooks. Checks of Numbers that share a WhatsApp Business
Account are spaced apart. A check only reads from Meta; it never stops or
restarts the Number.
Read the latest result with
GET /messaging/{session}/cloud-credentials.
checkedAt is the time of the last completed validation. status is:
failureCode is one of token_expired, token_invalid, token_app_mismatch,
app_credentials_rejected (the saved app secret no longer matches the Meta
app), permission_missing, phone_not_registered, webhook_not_subscribed,
credentials_unreadable, meta_unavailable or meta_response_invalid.
To renew the authorization, stop the Number, then use a project token with
quicklink:manage to call
POST /messaging/{session}/cloud-credentials/reauthorize.
The response contains a QuickLink bound to the same Number and phone number. It
always uses the Meta Cloud API and your team-owned app while Branded QuickLink is
active. Share the link with the person who manages the Number’s Meta assets.
After they complete Embedded Signup, the Number starts with the renewed
credentials and is checked again within minutes. Track progress with
GET /messaging/quicklinks/{id}.
The renewal link has purpose reauthorization in QuickLink status. You can
cancel it before Meta work starts, and the existing Number stays in Polymorfa.
Once Meta work starts, the cancellation endpoint returns 409; check the link’s
status before taking another action.
Reauthorization returns 409 state_conflict while the Number is running and
501 operation_not_supported for a Number that also has a linked-device
connection. Both endpoints require Meta Cloud API onboarding beta access and
return 403 feature_unavailable without it.
An active Branded QuickLink add-on also lets you hide Powered by Polymorfa.
Canceling renewal preserves this benefit until paid time ends. After the entitlement
expires, QuickLinks show the watermark again; your saved preference is retained.
The current branding entitlement applies when the page loads and after history or
test-setup updates, including for links created before the entitlement changed.
Saving hideWatermark: true without the add-on returns 402 with code
addon_required. Saving a team-owned Meta app without it returns 403.
Fund linked-device pairing
Your team needs enough prepaid credit for the number’s first 24-hour window. Credit is reserved before pairing material is issued and consumed when WhatsApp confirms the connection. If funding is unavailable, the page asks the recipient to contact the sender. Add credit or review project billing priority, then send a new link. The pairing-code endpoint returns402 with billing_credit_required;
reading the page state reports failed with that error code.
Free team limits
Teams on Free can’t create QuickLinks for real numbers. Creating one returns409 with the error code
payg_required. QuickLinks for testing numbers and Link a real number now
in the Console remain available. Linking a real number beyond the team’s
allowance also returns payg_required. Upgrade the team to use these links;
see Free and Pay-As-You-Go teams.
Create a QuickLink
You can create the same hosted link from three places.- Console
- API
- Customers
Open a project, go to Numbers, select New number, then choose
Send a QuickLink. Review the settings for that link, generate it, then
copy the URL, share it, or show it as a QR code for a
phone camera. Console shows the link moving from Opened to Linked to
Connected, and adds the number to the list when the recipient confirms.
For a Meta Cloud API number, the link stays at Linked while the
readiness checks run, and Console names
the recovery step when a check fails. While Meta has not answered a check,
Cancel QuickLink stays available.To pair a phone that is with you, choose Link a real number now instead.
Console runs an authenticated pairing flow inside the dialog. The embedded attempt cannot be shared or opened outside the Console.
Request fields
Start withprojectId. A project token already identifies its project, so it
can send an empty JSON object. A team key must specify projectId when the
team has more than one project.
QuickLink starts by confirming the recipient’s number before starting a connection.
The saved Allow phone changes setting controls whether a prefilled number can be replaced;
unprefilled invitations accept a number from the recipient. Changing a number waits for any
Linked Devices attempt to stop. An unresolved Meta operation must finish before switching.
Brazilian mobile numbers are checked with and without the ninth digit. The entered number
remains the number used for Meta setup; Linked Devices uses the resolved WhatsApp identity.
When both forms are registered, the recipient selects their account. Lookup hints are not proof
of ownership or Meta eligibility. Editing the entered number clears the account choices; the
recipient checks the new number before selecting an account.
A number confirmed as not registered on WhatsApp can use dedicated Meta Cloud API setup only when that
connection is allowed. With no supplied number, eligible links can open Meta’s number setup;
Meta decides which number options are available. Polymorfa does not guarantee a supplied number.
configuration.connectionPreference: "both" lets the recipient choose one allowed connection. It does not connect both transports.
QuickLink snapshots your saved project settings. Before creating a link, choose
its connection type, pairing methods, optional prefilled number, and history
sync policy. API creation accepts these choices under configuration. Page text,
appearance, support, privacy, terms, and callback URLs come from saved settings
and cannot be changed for an individual link.
Creation accepts these invitation fields:
Omitted configuration fields inherit saved defaults. Set
configuration.defaultMethod to null to choose pairing codes on phones and
QR codes on laptops.
Configure page text and appearance in team or project QuickLink settings.
Configure privacy, terms, and callback URLs in project QuickLink settings.
For example, offer phone pairing with history disabled:
What the recipient sees
The hosted page shows your business name, logo, and accent, and offers the enabled methods:- Scan QR code on a laptop or a second device. The page refreshes the code automatically until WhatsApp links.
- Enter a code on the phone itself. The recipient types their number, receives a one-time code, and enters it under Link with phone number instead in WhatsApp.
Track and finish the connection
Use either of these paths to learn the outcome. Callback URLs. Configure success and failure URLs in the project’s QuickLink settings. Each invitation snapshots those destinations when it is created. Creation requests cannot replace or clear them. Confirmation uses the success URL. Cancellation uses the failure URL withstatus=cancelled and
reason=cancelled; connection failures use status=failed and a reason such as
phone_mismatch or connection_failed. The hosted page returns after displaying
the failure notice. After a Meta Cloud API or Hybrid connection, the hosted page
states that Meta confirmed the setup checks and waits for the recipient to
select Continue before opening the success URL. The checks do not send a
message, so send and receive a test message before using the Number. Unresolvable links cannot supply a trusted callback
and remain on the unavailable-link page.
For example:
externalId is included in the callback and
the resulting session response. It may repeat across invitations. Customer
correlation remains separate in externalCustomerId.
Treat the query string as a hint and confirm the session state with
GET /platform/sessions/{session} or the session webhooks.
Status polling. GET /messaging/quicklinks/{id} returns the current status for
the caller that created the link:
An expired link returns
404.
Meta Cloud API readiness checks
After Meta accepts event delivery for the WhatsApp Business Account, Polymorfa checks the number before starting it. The link stayslinked while the checks
run. The first check that fails moves the link to failed with its own
errorCode, and the number does not start. The link becomes connected only
after every check passes and the recipient confirms.
When Meta does not answer a check, for example during a Meta outage, the check
is neither passed nor failed. The link stays
linked and onboarding.errorCode
is meta_readiness_unknown. Polymorfa checks again every two minutes and
continues when Meta answers. You can cancel the link while it waits. If the
link expires first, it fails with meta_readiness_unknown.
A reauthorization link checks access, phone registration and the webhook
subscription. It does not check the payment method or quality of a Number that
is already in use.
The checks run once, during setup. Afterwards, sends from the Number return a
specific error when Meta reports a problem:
whatsapp_authorization_required,
whatsapp_payment_method_required
or whatsapp_number_not_registered.
Credential checks continue as described in
Check and renew Meta Cloud API credentials.
Cancel a QuickLink
DELETE /messaging/quicklinks/{id} invalidates a pending link. For an initial
real-number link, a 202 response means Number cleanup was requested. The
Number remains in your project until cleanup finishes; check its status before
creating a replacement. Cancelling a supplementary link leaves the existing
Number in place. Console will not generate a replacement while the current
link is active. Cancel it first, or wait until it connects or fails. Connected
links cannot be cancelled; manage the Number instead.
Console-created links can be inspected and cancelled only by the member who
created them.
Saved settings
In the Console, open team or project Settings → QuickLink. You can:- enable or disable QuickLinks for the scope;
- allow recipients to replace a prefilled phone number, or keep it locked;
- choose the offered methods and which one opens first;
- write the headline, description, and success message the person reads;
- add a support link, and privacy and terms links for the confirmation step;
- upload a logo, reuse the team logo or the project icon, and set the accent, theme, corner shape, and footer;
- set project success and failure callback URLs and choose the chat-history behavior.
Direct pairing
Direct-pairing access If you need to build your own pairing interface, direct-pairing access must cover the Number before you call Get QR code or Request a pairing code. Without that access, these methods return403. Use QuickLink instead.
Where to go next
Sessions
Manage the connected number after it lands in your project.
Customer pairing links
Assign connected numbers to Customers with durable, revocable links.
Webhooks
Observe the resulting session lifecycle.
Client tokens
Browser-safe credentials for messaging, separate from pairing.
Connection preference
connectionPreference and connectionEnforcement are separate from Linked
Devices methods. Saved project settings provide the defaults. A normal
QuickLink creation request can override the safe invitation fields under
settings; Console presents those fields before generation. The resolved
settings are snapshotted at issuance.
The default is cloud with prefer. The settings are copied into each link
when it is created; editing saved settings does not change existing links.
Select a connection card, then choose Continue to start connecting. The preferred card appears first and is selected initially. Switching between connection types keeps the card height and action footer fixed. Longer instructions scroll within the card. Both connection views place Use Meta Cloud API instead or Use Linked Devices instead at the bottom left when switching is allowed, and Cancel at the bottom right. Actions use filled buttons with a secondary style for switching and a subtle red tint for Cancel. The page footer reads Powered by Polymorfa. Visitors can switch between light and dark themes and select English (ENG) or Brazilian Portuguese (BR) using the icon-only theme and language menus below the card on the left, with the Polymorfa attribution on the right. These choices do not change the invitation’s connection policy or the creator’s custom text.
both cannot be forced. Optional Cloud choices are hidden when hosted Cloud
signup is unavailable. Creating a forced-Cloud link in that case fails.
Meta Cloud API setup offers Keep using the WhatsApp Business app for an
eligible existing app number, or Use WhatsApp without the Business app for
a new or existing Meta Cloud API number. Customers connect their own numbers and pay
Meta directly for messaging.
Coexistence history
Configure a project webhook subscription forhistory.sync, contact.sync,
and message.echo. QuickLink settings remind you to configure a destination.
Enable HMS separately if you also want supported messages stored by Polymorfa.
History sync never enables storage automatically.
A business can decline history sharing in WhatsApp, including when the link’s
history setting is enabled. history.sync delivers Meta’s refusal, progress,
and history batches. Cloud history payloads contain kind: "history" and
value; linked-device history retains its compressed chunk format.
contact.sync contains kind: "contacts" and value. message.echo contains
source: "whatsapp_business_app" and value.
Confirming the connection does not wait for history import. Track progress
through webhooks or the link’s onboarding status. A synchronization request
being accepted is separate from import completion. HMS stores supported message
metadata, preserves the original message ID, timestamp and direction, and applies its
retention policy. Media references marked mediaStorage: "not_fetched" do not
mean the media bytes were stored. Standalone contacts are delivered by webhooks.
If onboarding.errorCode is sync_status_unknown, Meta did not confirm a
contacts or history request. The connection can remain active while import
status is uncertain. Check incoming history events and contact support with the
QuickLink ID before attempting another signup. Do not create another invitation
to retry the import: the original request may already have been accepted.
The Linked Devices flow centers the QR code and offers Or use your phone number to log in underneath when both methods are allowed. Mobile browsers start with phone-number pairing when it is allowed. Resizing a desktop window does not change the initial method. The theme follows the device by default. A saved project theme sets the initial appearance; visitors can override it by choosing System, Light, or Dark. Language starts from the visitor’s first supported browser language, English or Portuguese. If neither appears, the page starts in English. Visitors can switch language on the page.
When you supply externalId, native session.* lifecycle webhooks include that reference alongside the session name. It does not replace the event ID or grant access to the session.
Customers identify the person or business responsible for Numbers. They do not
store a phone number; supply any expected phone on the individual invitation.
meta_registration_rejected means Meta explicitly refused number registration.
Correct the registration restriction before starting another connection attempt.
An uncertain request outcome remains pending until it can be reconciled.
existing_cloud_registration_unverified means Meta did not report the number as
either connected to Cloud API or ready for a new registration. Polymorfa stops
before sending a registration PIN, so a PIN held by the number’s current provider
is not replaced. The account owner resolves the number’s registration and PIN
with that provider, then creates another invitation.
When you supply prefillPhone, creation attempts to check whether the number is
registered on WhatsApp. It first selects a connected Number that has previously
observed the exact phone, then a connected Number with the same country calling
code, then any connected Number. The selected customer and conversation are
never exposed. A confirmed unregistered number returns 400 with
phone_not_registered. If no connected Number can answer, the registration
state remains unknown and the invitation continues with the project’s allowed
connection choices. The same rule applies when the recipient enters or changes
the number after opening the link. Invalid phone numbers still stop at the
phone step. Missing profile names or photos do not invalidate a registered
number. Customer invitations apply the same resolution to
expectedPhone.
cloud_start_failed means the runner reported that the Meta Cloud API connection
could not start. Correct the reported connection restriction before issuing a
new invitation. Polling the failed invitation does not retry startup.
Customer invitations save these settings when the invitation is created, before
it is opened. Their resolved phone identity is saved with the invitation;
opening it does not replace that identity with a later lookup result.
For a resolved prefilled number, the recipient sees Logging in as, the
formatted international number and the inferred WhatsApp account type in one
identity card. Polymorfa does not reuse another customer’s saved contact name
or profile-photo access. When no provider-global display name is available, the
card uses the number and a neutral profile icon. Not you? cancels the
invitation through its saved failure callback.
The connected number must match a prefilled invitation, including when the
recipient scans a QR code. A mismatch fails confirmation and does not complete
the invitation.
meta_subscription_rejected means Meta explicitly refused the WABA webhook
subscription. Correct the app permissions or WABA access restriction before
creating a new invitation. An uncertain subscription result stays pending until
it can be reconciled.
While the subscription is pending, onboarding.errorCode is
meta_subscription_status_unknown when Meta reports a different webhook callback
for the Polymorfa app on that WABA. Polymorfa does not overwrite that callback.
It checks again every 10 minutes and continues setup when Meta reports the
Polymorfa callback. Ask the account owner to check the app’s webhook
subscription, or cancel the invitation to stop. If the invitation expires first,
it fails with the same code; create a new invitation after the owner resolves
the callback.
If confirmation returns a temporary error, retry confirmation while the invitation
is valid. A retry does not repeat completed onboarding. If the invitation has
expired, check the resulting Number before creating another invitation.
An uncertain contacts sync cannot be confirmed from a later contact-change event.
Contact support before retrying. Repeating Meta’s one-time synchronization may
require the business owner to disconnect the Meta Cloud API connection and complete
Embedded Signup again; this interrupts that connection and is never automatic.
Pairing on your phone
After requesting a pairing code, mobile browsers offer Open WhatsApp. Open Linked devices in the app that owns the number and enter the code. If the link opens a chat or a different installed app, open the correct WhatsApp app manually. The pairing code is never included in the external link. Browsers with picture-in-picture support also offer Keep code visible. This opens only when you select it. If the browser rejects the request, copy the code and switch to WhatsApp. The floating code closes when the pairing panel is removed or the code changes. You can open a newly issued code even if the previous picture-in-picture request is still loading. Browser and operating-system support varies. If Meta signup times out before returning its complete result, check the connection status and reload the page before starting another signup. Switching connection methods on the same page does not restart the expired signup window. New invitations created after a team loses access to its team-owned Meta app use the available Polymorfa Meta app or Linked Devices according to the project’s connection policy. Existing invitations retain their saved app binding.Session configuration
Onboarding choices are frozen when the link is issued. Ongoing session settings inherit platform, team, and project defaults unless the session overrides a field. A changed default updates sessions that still inherit it. See Session configuration for updates and resets. Unknown configuration fields are rejected. Presentation, legal links, and callbacks cannot be set on an individual link. Configuration never grants HMS access or overrides the recipient’s history decision.Simulated connections
For a testing number, includeconfiguration.testing. Set a country and initial
simulation configuration, then list the fields the recipient may customize:
editable list accepts at most three fields. An empty list keeps
all creator settings fixed. Simulation does not connect to real WhatsApp accounts.
Trusted-server Meta setup
Create a QuickLink first. Confirm the phone throughPOST /quicklink/{token}/phone. If both connection types are offered, select
Official API through POST /quicklink/{token}/connection with
{ "connection": "cloud" }; a sole allowed Cloud connection is selected after
phone confirmation. Then call POST /messaging/cloud-api/embedded-signup
with the quicklinkId to advance Meta Cloud API setup. Include result when
submitting the Embedded Signup result. For an initial invitation with history
mode ask or force_on, first record the recipient’s choice through
POST /quicklink/{token}/history with { "historySync": true | false }.
A QuickLink that adds Official API to an existing Number reuses that Number’s
history decision; its history endpoint is unavailable. The
Meta signup result does not record that consent; advancing while it is pending
returns 409. To request history after the recipient accepts, also set
result.historySync to true in the Embedded Signup request. A missing or
false result flag does not request history. The call uses the invitation’s reserved
session and saved Meta app settings; it cannot choose a different session or
supply app credentials. Console-only attempts and Test Numbers cannot use this
endpoint. The caller needs quicklink:manage and access to the invitation’s project.
Track the onboarding stage with GET /messaging/quicklinks/{id}. For a
single-connection QuickLink, call POST /quicklink/{token}/confirm once the
stage reaches connected. For an eligible Hybrid Link, complete Linked Devices pairing for
the same Number and wait for hybridPhase: "ready" before confirming.
Confirmation finishes the invitation, completes any attached Customer pairing,
and returns the success redirect URL. The Embedded Signup response alone does
not confirm the QuickLink.
Test history fixtures
Upload fixture messages withPOST /messaging/testing/{projectId}/history-fixtures.
The body contains messages, each with id, senderPhone, text, timestamp,
and fromMe. Send at most 100 messages within a 512 KiB request. Message IDs must
be unique and senders must belong to the project’s test-number pool. Test access
and sandbox:write are required.
Pass the returned fixtureId as
configuration.testing.configuration.historyFixtureId when creating a test
QuickLink. Fixtures provide simulated history for message retrieval; uploading a
fixture does not publish live message events or enable HMS.