Connect the billing provider that processes these purchases before you set up
this workflow. See Connect Stripe
or Connect RevenueCat.
Recommended paywall setup
hyzl needs a stable identifier to ask your provider whether the member paid. Standard provider paywalls already support one.Stripe
Use a hosted Stripe Checkout Session in subscription mode. Setclient_reference_id or metadata.userId to your internal member identifier. Stripe grants access after checkout.session.completed, and hyzl uses the same identifier to match the payment.
Stripe Pricing Tables, Payment Links, and the Payment Element also work. Set the same identifier on every payment surface.
Do not create a Stripe Customer only because someone views the paywall. Stripe stopped doing that by default in 2022. Otherwise, visitors who never pay create unnecessary Customer records.
RevenueCat
Use RevenueCat Paywalls in your app. Send the RevenueCat App User ID asuserId. The older field name was appUserId.
The identifier exists at the paywall for logged-in and anonymous members. A custom paywall built with getOfferings() also exposes it.
Identify the member
Every event must include a durable identifier. SenduserId or a Stripe Customer identifier in stripeCustomerId.
For RevenueCat, send the exact identifier your app passes to Purchases.logIn(). RevenueCat can check purchases only by that identifier.
Use your authentication system identifier or another internal identifier that you never reuse. Do not use an email address or phone number. Email addresses change, and carriers recycle phone numbers.
hyzl can receive several identifiers over multiple events. It keeps identifiers already received and joins later events to the same member.
Anonymous or optional signup
Use persistent anonymous authentication when a paywall appears before signup or lets the member skip signup.- RevenueCat provides an
$RCAnonymousIDfromconfigure().Purchases.logIn()links it after signup. - Supabase and Firebase provide anonymous sign-in. The anonymous identifier can become the account identifier after signup.
userId. If anonymous authentication is unavailable, generate a server-side identifier for each device. Never send an event without a durable identifier.
Send the request
Send this request from your backend. Never expose theingest token in browser or mobile-app code.
Choose the event location
The event starts the recovery timer. hyzl waits 5 minutes to 24 hours and then checks whether the member paid. hyzl never calls a signup older than 48 hours.
Send the event at the purchase decision, preferably when the member leaves the paywall without buying.
Personalize the first text
The First text, personalized card appears below First offer text in both signup recovery modes. It starts unset. With a saved personalized message and a goal, hyzl sends that message instead of the first offer text. Otherwise, the standard first text sends unchanged. In Text only, this replaces the initial text. In Call + text, this replaces the first text after unanswered calls.Send the goal
Add the optionalgoal string to the signup event:
goal or send an empty string. Do not send the word “Other”.
hyzl quotes the value verbatim. An absent, empty, or whitespace-only goal uses the standard first text for a new enrollment. A later blank event keeps an earlier goal.
hyzl trims the goal, removes control characters, and caps it at 120 characters. A non-string goal returns 400.
Write the personalized message
- Click Customize on First text, personalized.
- Insert
{goal}where the member’s answer belongs. - Save the workflow.
{goal} placeholder works only in the personalized first text. A message without it shows an amber warning and still saves. An unknown placeholder blocks the save.
Request fields
Recommended
stage values are:
saw_valuewhen the member saw a real resultsaw_pricewhen the member saw the price but did not buypre_offerwhen the member left before the price
stage, the AI uses the generic never-paid script.
Minimum event
The minimum contactable event depends on your billing provider:- RevenueCat:
userId,phoneNumber, andconsent.attested: true - Stripe:
stripeCustomerIdoruserId, plusphoneNumberandconsent.attested: true
Stripe purchase checks look for subscriptions, including cancelled and
expired subscriptions. A one-time Stripe payment does not count as paid.
Get the URL and credential
- Open Settings and click New workflow.
- Choose Signs up, never pays.
- Choose the provider that processes purchases.
- Set the offer, wait time, daily call cap, and calling window.
- Copy the webhook URL,
ingest token, and provided code examples. - Confirm the consent acknowledgment.
- Configure the script, voice, and schedule.
- Click Finalize & Launch.
ingest token to your developer. The setup also provides a complete developer bundle.
Stable webhook URL
The URL stays the same when you edit, pause, or relaunch the workflow. You can keep it in server configuration. Deleting the workflow retires the URL. A request to a retired URL returns404 unknown_slug. The response includes the current URL in url, and Settings warns you about recent retired-URL requests.
Request examples
Edge runtimes
Let the POST finish after your endpoint returns. This avoids delaying the member or losing an unfinished request. Always include a stableeventId.
Send the event in steps
You can send available data first and add the phone number later. Use the sameuserId on every request.
hyzl joins requests by userId first, then shared email, then shared phone number. A later request never removes an earlier field.
Node
Collect consent
Add an unchecked checkbox beside the phone number field. Adapt this example with qualified legal advice for your business and location.
Follow these rules:
- Put the checkbox where you collect the phone number.
- Keep the phone field optional in a web signup.
- Leave the checkbox unchecked by default.
- Send the real state as
consent.attested, includingfalse. - Optionally send
consent.textandconsent.atfor your Telephone Consumer Protection Act evidence trail. - Keep the exact accepted wording and time in your own records.
Wait time and repeat events
After hyzl receives a phone number and consent, it waits before checking payment. The default is 5 minutes. You can choose from 5 minutes to 24 hours. A stored wait of 60 minutes appears as 1 hour when you edit the workflow. The timer starts atstartTimerAt, then occurredAt, then receipt time. A later startTimerAt on the same identity resets the timer.
Send startTimerAt from your backend. This keeps the ingest token away from the browser.
hyzl checks payment again before it queues the call. Purchases usually reach Stripe and RevenueCat within seconds.
When calls reach the daily cap, remaining calls wait until the next day. The paid check happens before this hold. Provider purchase events cancel a queued call when they arrive before dialing.
After contact, resolution, or parking, a later event can create a new cycle. The new cycle starts only after 30 days. Within 30 days, hyzl treats the event as the same signup.
One event at the paywall
Start at signup and reset at abandonment
Send the first event at signup:Add a Stripe identifier later
KeepuserId on the later event and add the Stripe Customer identifier:
Configure call timing
The daily cap and calling window apply only to this workflow. You can change both later from the workflow editor. Daily call cap: The default is 100 calls. hyzl holds extra signups for the next day instead of dropping them. Calling window: The default and widest window is 9:00 AM through 8:00 PM in the member’s local time. You can narrow this window but cannot extend it. Calls run every day of the week. A wait that ends before the window opens stays pending until the opening time.Configure the offer
By default, hyzl builds the win-back link. For Stripe, hyzl creates a Checkout Session with the coupon already applied. It sends the member a short link after the call.Send your own recovery link
Turn on merchant-provided recovery links in the workflow settings. Then sendrecoveryUrl for each member.
The URL can point to web billing, Stripe, or your app paywall. It must use HTTPS. hyzl sends it unchanged and never reads or adds parameters.
A later event can replace an earlier URL. Without a URL, the default behavior parks the member. Turn on fallback to let hyzl build a link instead.
hyzl still checks payment before every send. Only link creation changes.
Send your own discount
Turn on merchant-provided discount percentages in the workflow settings. Then sendpercentOff from 1 through 90.
hyzl quotes this percentage on the call and in the offer text. A hyzl-built Stripe link applies the same percentage at checkout.
RevenueCat codes keep their App Store Connect discount. On that path, hyzl quotes the campaign percentage that matches the code.
A later event can replace an earlier percentage. Without a percentage, the default behavior parks the member. Turn on fallback to use the workflow percentage instead.
If you also provide recoveryUrl, make sure your link provides the percentage that hyzl quotes.
Handle unanswered calls
After all attempts go unanswered, hyzl checks payment one final time. If the member remains unpaid, hyzl sends the offer once.- Stripe sends a discounted checkout link that expires 24 hours later.
- RevenueCat sends an App Store redemption code from your inventory.
- A 0% workflow sends no no-answer offer because it has no discount.
Response contract
Treat both 200 and 202 as success. Log and investigate every other response. On a network error or
5xx, retry with the same eventId.
A 202 response means stored, not called. A 200 response is normal before Finalize & Launch or during a workflow pause. Events stored while it is off do not run after you turn it on.
Every response also includes these diagnostic fields:
outcomeiscreatedfor a new member orjoinedfor a later matching event.alreadyContactedreports whether a joined member already moved beyond waiting.flowEnabledreports whether the workflow is live.contactablereports whether hyzl has a usable phone number.consentAttestedreports whether positive consent arrived.notelists conditions that currently block a call.
Cancel pending recovery
Send a cancel when the member opts out, pays elsewhere, or should no longer receive outreach. Replacepaywall_recovery_webhook in your webhook URL with paywall_recovery_cancel_webhook. Keep the same slug and bearer credential.
Send the durable identifier used during enrollment. Email or phone alone cannot identify a cancellation request.
A cancel stops only pending outreach. It stops a member in the wait and cancels a queued, undialed call. It cannot undo a sent text, placed call, or recorded recovery. It never records a purchase.
Pause behavior
hyzl stores events sent before launch or during a pause for reporting. It schedules no contact for those events. Turning the workflow on does not process events received while it was off. This prevents a backlog from causing stale calls. Send a fresh test event after the workflow is live.Test the integration
Settest: true only with a phone number you control. The test runs within one minute. It bypasses the wait, paid check, and workflow switch.
Never set test: true on a real signup. It can call a member without checking whether that member already paid. The portal test button sends this event to your own number.
After deployment, Analytics should show the event within about one minute. Inspect the response diagnostic fields if it does not become contactable.
Open the workflow card in Settings for integration warnings. The card identifies invalid phone numbers, missing identifiers, retired URLs, and other blocking fields. It also shows affected counts and the latest occurrence.
Find signups in analytics
Open Analytics and choose Signs up, never pays. The funnel tracks Signed up, Unpaid, Contacted, and Paid. The member table shows these outcomes:- Waiting means the timer is active or the phone number has not arrived.
- Due to be contacted means the wait finished and contact has not started.
- Not contacted includes the specific reason hyzl stopped.
- Reached means contact succeeded without a later purchase yet.
- Paid means the member paid within 14 days of signing up. The row shows whether they redeemed your offer or came back through your own checkout.
- Paid on their own means payment arrived before hyzl made contact. hyzl never counts or bills this outcome.
America/Los_Angeles, not the browser’s local time.
Use the developer bundle
The setup screen has a copyable developer bundle. It includes:- the implementation task and event placement
- webhook URL and credential
- consent wording and rules
- all request fields and minimum requests
- ready cURL, Node, and Swift examples
- responses, retry rules, cancellation, and verification

