Billing
Prepaid credits, BRL only, R$50 minimum. Tyxter charges one flat transport fee when Meta accepts an outbound WhatsApp message, discounted by your plan. Sandbox is free. Production API-key access is blocked at or below -R$5, except for supported recovery endpoints.
Recover from a credit block
A credit block engages at or below -R$5 and lifts as soon as the balance is above -R$5. The Billing page shows a persistent alert while the refreshed wallet reports production credit access blocked. An organization owner or admin can open the existing top-up flow from that alert; other members see recovery guidance. Add enough credit to make the balance positive. The alert clears when the refreshed production_blocked field is false. A balance above -R$5 but still below zero lifts the block without paying an unpaid phone rental month. A positive balance may still be too low to cover the next rental fee. Clearing this credit block does not clear other account limits. Sandbox remains unaffected by this credit block.
How it works
- Every organization has exactly one
credit_balance, denominated in BRL. - Top ups are one-off Stripe Payment Intents. We complete the top up in-transaction when Stripe's webhook arrives.
- Each billable event (provider-accepted production WhatsApp transport, the monthly rental of a number Tyxter provisions for you,
tts.characters,llm.tokens.used, successful production transcription, and each payment Tyxter accepts) writes aUsageRecordpriced against the active rate card — and, for the per-message transport fee, discounted by your plan. - Sandbox is free to your wallet, but sandbox message records still mirror active rate-card pricing so you can test reconciliation before production — they never debit the balance or consume package quota. Sandbox payment fees are recorded at the amounts production would charge, also without debiting the balance (see Payment fees). Other sandbox meters are written at
cost_brl0.
Top up
Top-ups are created from the dashboard, where the signed-in user can use Stripe Elements or PIX without exposing dashboard session endpoints as public integration APIs. The balance is credited atomically when Stripe's webhook marks the intent as succeeded.
5000 centavos). Lower amounts get a 400 validation_error.Refunds
Unused prepaid credit can be refunded if you ask support within 7 days of the top-up or package purchase it came from, up to the unused balance on the day you ask. Promotional or bonus credit is never refunded, and after those 7 days unused credit is not refundable. Approved refunds are paid to the original payment method within 30 business days of the request, and the refunded amount is debited from the balance.
The monthly fee for a number Tyxter provisions is non-refundable, in full or in part, once it has been charged, including when you release or disconnect the number, delete the WABA, or Meta blocks sending; the first month is charged once the line is provisioned. A fee returns to the balance automatically only while it is still a reservation, which only the first month ever is: it returns when provisioning fails. Releasing a number stops future renewals.
Balance and ledger
The ledger is a cursor-paginated stream of credits (top ups) and debits (usage records). Each entry carries the trace_id that produced it so you can reconcile a charge back to the exact message. A non-zero uncollected_brl on a debit entry is the part of a usage charge that could not be collected without crossing the -R$5 production credit floor; a rental line written before rental fees were debited in full can carry one too. Entries are listed newest first by date (recorded_at for a debit), and no rental reservation appears. How rental lines are dated, and why your balance can move without a new entry, is set out in How number rental is billed. A payment completion fee is the exception: its hold and its release are listed as hold and release entries (see Payment fees).
Phone rental renewal decisions (deprecated)
Deprecated: for each number's current month, read the renewal field of GET /v1/phone-numbers and GET /v1/phone-numbers/{id} (see the renewal policy). This route keeps answering with the renewal cycles recorded by the earlier prepaid renewal design; no new cycle is recorded. Under the current policy the month is charged on its 1st (see How number rental is billed), so a recorded cycle tracks no prepayment. Each cycle keeps its immutable period and amount, safe lifecycle timestamps, and whether it was funded, at risk, renewed, released, or cancelled. A cancelled cycle records an operational lifecycle closure, not a non-payment release; a month charged on its 1st may then show as cancelled. Status and recommended actions describe the stored cycle, not a fresh wallet assessment. The business number display is nullable after release, and no provider identifiers, reservation data, raw evidence, or notification-recipient data is returned. The next_renewal_at and release_cutoff_at dates are captured provider schedule and cutoff snapshots, separate from the UTC billing period. Later invalidation does not erase these historical dates. The renewal_warning_48h_at and renewal_warning_24h_at dates are always null: those warnings are retired. The grace_selected_at and grace_ends_at dates describe retained grace; an unknown end stays null. A renewed retained cycle records a wallet charge and can still have active grace or outstanding wallet debt.
Rate card
Rate cards are effective-dated. The active card is the one whose window covers now, and it is the authoritative source for the meter rates below — the transport fee, the payment fees and the Meta reference rates. Plan fees, multipliers, throughput, and phone allowances are not on the rate card; those live on the plan catalog further down. Each entry carries a kind so you can tell what Tyxter actually debits (billed) from what is reproduced for reference only (meta_reference).
What Tyxter charges
Tyxter bills one flat transport fee when Meta accepts an outbound WhatsApp message — msg.transport, R$0.05 per message — whatever the conversation category. A subscription plan discounts that fee by a multiplier. It is a discount on the per-message rate, not a bundled quota: you still pay for every message, just less per message.
msg.transport R$0.05 / message base rate
x 1.00 = R$0.05 Free (no subscription)
x 0.60 = R$0.03 Standard
x 0.32 = R$0.016 GrowthThe other meters Tyxter bills to your credit balance:
phone.number.month R$50.00 / number / month (numbers Tyxter provisions for you)
phone.management.month R$20.00 / number / month (numbers imported from your own Salvy account, once no Standard or Growth plan covers them)
msg.instagram.outbound R$0.05 / message
tts.characters R$0.0001 / character rendered
llm.tokens.used R$0.015 / 1k tokens (input + output)
template.generation R$0.05 / generation (production only)These are list prices; the rate card in force is the source for each meter’s price: read it on GET /v1/rate-cards/current.
Production inbound-audio transcription uses stt.audio.second when Tyxter’s platform credential runs the provider and stt.audio.second.byok when your connected OpenAI STT credential does. Set up OpenAI STT BYOK in the media guide. The chosen source and meter stay fixed for that run, including automatic retries. A new manual retry may select the configuration available at that time. Disconnecting your OpenAI STT credential withdraws the override, so every transcription that was not already attributed to it — including one still queued — meters at stt.audio.second on Tyxter’s platform credential again. Starting 24 August 2026 at 00:01 America/Sao_Paulo (03:01 UTC), the platform rate is R$0.0043 per audio second and the BYOK rate is R$0.0005 per audio second. A 60-second successful transcript is R$0.2580 with Tyxter’s credential or R$0.0300 with BYOK. Pricing uses the rate card effective at the usage event, so earlier usage keeps its earlier price. Consult GET /v1/rate-cards/current for the currently effective card. If the selected meter has no active entry, Tyxter fails the transcript before reading audio or calling the provider and records transcription_billing_rate_unavailable. It does not silently switch to the platform credential or create zero-priced production usage.
msg.transport and msg.failed_processing. Every other meter above bills at its flat rate on every plan — an outbound Instagram message costs R$0.05 whether you are on Free or on Growth.Payment fees
Accepting a payment is a service, so Tyxter charges two fees for every payment it accepts: a merchant payment request created with POST /v1/payments or from the dashboard, and an agentic payment created with POST /v1/agentic/payments. The fees apply whichever credential runs the payment, your own provider connection or the Tyxter platform Iniciador app.
payment.initiation R$0.10 / payment charged when the payment is accepted, kept whatever the outcome
payment.completion R$0.0001 / principal centavo 1% of the amount, held when the payment is accepted- A R$100.00 payment. Creating it needs R$1.10 of available balance: R$0.10 is charged and R$1.00 is held. If the payment is paid, the R$1.00 hold is charged and the payment costs R$1.10 in total. If the provider confirms that it failed, expired or was cancelled and complete create history rules out an earlier uncertain payable payment, the R$1.00 returns to your balance and R$0.10 stays charged. In production, unknown create history keeps the hold reserved.
- Rounding. Fees are computed at four decimal places, rounded half-up, with no minimum and no maximum: a R$0.01 payment holds R$0.0001. The completion fee is computed on the amount at creation; partial payments and changed amounts are not supported.
- Funding. In production your balance must cover both fees when you create the payment, with no negative-balance grace. Otherwise creation fails with
402 insufficient_balanceand nothing is created or charged; top up and retry with the sameIdempotency-Key. If the fee prices cannot be read, creation fails with503 payment_fee_pricing_unavailable; retry later. Both errors carry theerror.feedbackpointer on the /v1 routes. While production credit is blocked (see Recover from a credit block above), a production API key is refused before that with402 credit_balance_exhausted. - What is never charged. A request refused before the payment is accepted, a replay with the same
Idempotency-Key, worker retries, provider callbacks and status changes, status reads and polling, request approval, cancel, authorization creation and revocation, bank listing, wallet top-ups and subscription payments. A retry without anIdempotency-Keycreates a second payment and is charged again. - When a hold is resolved. The hold stays until the payment provider confirms the outcome; no timer releases it. In production, while a payment is open for more than 24 hours, or after it ends without a confirmed outcome,
fees.completion.statereads unresolved and merchant recovery keeps asking the provider with capped spacing and bounded work per run; agentic recovery makes at most 24 automatic terminal reads per payment. A merchant payment link that the payer never uses keeps its hold until the provider reports a final status and safe release can be proved. - Refunds. A refund or chargeback after a payment was paid does not return the completion fee. A refund or dispute that the provider reports before the paid outcome reached Tyxter also charges the held fee, because it shows the payment collected money.
- Spend limits. Fee usage counts toward a project’s month-to-date production spend like any other usage: the initiation fee when the payment is accepted, the completion fee when it is charged. A spend limit does not refuse a payment creation, and a fee that reaches the cap does not fire the
spend_limit.hitwebhook; later sends then fail with402 spend_limit_exceededuntil you raise the cap or the month ends. - Where fees appear. Each payment response carries a
feesobject with both amounts, the completion state and the pricing version.GET /v1/billing/ledgerlists apayment.initiationdebit, aholdentry for the completion fee, and later areleaseentry or apayment.completiondebit;held_brlonGET /v1/billing/balanceincludes outstanding production holds. OnGET /v1/usage/recordsa fee record hasmeter_idpayment.initiationorpayment.completion, quantity 1 (one fee, not centavos) and the payment id asmessage_id. - Sandbox. A sandbox payment records the same fees at the amounts production would charge, with
fees.simulatedtrue, but never checks or moves your balance, so it is never refused for funds. The sandbox status route and the hosted sandbox pages settle or release its hold like a provider outcome.held_brlcounts production holds only; list sandbox fee entries withGET /v1/billing/ledger?environment=sandbox.GET /v1/usage/recordsneeds no filter: it lists the records of the environment the API key belongs to, so a sandbox key lists its sandbox fee records. - Dashboard. A payment created from the dashboard is charged the same fees. The dashboard form does not show them before you submit, and its refusals carry no
error.feedbackpointer. - When the prices took effect. The prices apply to every payment accepted since the release that introduced them was deployed. A payment accepted before then owes no fee and its fees field is null.
GET /v1/rate-cardslists both prices on the card that was current at that release from that card’s owneffective_from, which is earlier than the release; no fee was charged before it. Cards that had already ended list both meters at zero. ReadGET /v1/rate-cards/currentfor the current prices.
How number rental is billed
These rules cover the phone.number.month rental of a production number Tyxter provisions for you. Ordering a number in sandbox is free and reserves nothing. All times are UTC; 00:00 UTC on the 1st is 21:00 the day before in Brasília (UTC-3).
- One full fee per UTC calendar month, never prorated. The activation fee pays for the whole month in which the number becomes active, whatever the day. A number activated on the 30th pays for that month and, if you keep it, for the whole next month too.
- The activation fee is reserved when an owner or admin approves the order, not when the order is created. Approval needs the whole fee in your balance, otherwise it fails with
402 insufficient_balanceand the order keeps waiting for approval until it expires. Your balance drops at once, with no ledger line yet. The line appears when the carrier delivers the number and is dated at that moment. If provisioning fails before delivery, the reservation is returned to your balance. - Later months are charged on their 1st. From 00:05 UTC on the 1st, the month that starts is charged for every production number you hold, at the rate card in force at that instant, with a ledger line dated 00:00 UTC on the 1st of that month. Nothing is reserved ahead of the month. A renewal notice comes seven days before the month begins and states your balance at that moment, the rental charges due on the 1st and, when the balance is short, the top-up needed, or that your auto top-up covers it. This policy applies from the November 2026 renewal.
- A number bought late in a month. The activation fee pays for the month of activation, and the next month is charged on its 1st however close that is. A number activated on Oct 28 pays its activation fee that day and November four days later.
- Full debits and the credit floor. The monthly charge is debited in full even when that takes your balance below -R$5; your balance then shows the debt, and you are told by email and in the dashboard. The activation fee needs the whole fee available, so it never takes your balance negative. At or below -R$5, production API-key access is refused with
402 credit_balance_exhausted, except for supported recovery endpoints; the block lifts once the balance is back above -R$5. - Unpaid at the end of the month. On the free plan, a number whose month is still unpaid on the last UTC day of that month is released to the carrier. A month is unpaid while your balance stays below zero after its charge. The charge is not refunded, and a released number cannot be recovered; order a new one once your balance covers the activation fee. On a paid plan, an unpaid number is not released automatically.
- Keeping the number. Top up any time before the last UTC day of the month to keep the number: once your balance is back at zero or above, that month counts as paid. Lifting the -R$5 block alone is not enough. On the free plan, while the month stays unpaid, you are reminded by email and in the dashboard seven days and again 24 hours before the release.
- Spend limits. A project spend limit never refuses a rental fee, but counts it toward the month its ledger line is dated in. A rental line dated in the current month can reach a cap set at or below the fee, and sends then fail with
402 spend_limit_exceededuntil you raise the cap or the month ends. A rental fee that reaches the cap does not fire thespend_limit.hitwebhook. - Ledger dates. Every rental line shows the full fee as
amount_brl. The line for a renewal month is dated 00:00 UTC on the 1st of the month it pays and written by the 00:05 UTC run. The activation line is dated when the number is delivered, so a number that becomes active in a later UTC month has its line dated in an earlier month than the one it pays. A rental line written after its date is listed at that date, below newer entries. - Balance changes with no new ledger line. The activation reservation moves your balance at once, and its line appears when the number is delivered; a returned reservation adds the money back with no line. Payment fee holds are listed differently (see Payment fees). When Tyxter collects the
uncollected_brlremainder of an older rental line, your balance drops with no new line and that line then showsuncollected_brl0. - Release and disconnection. Releasing a number never refunds a month that has already been charged, including the month in which you release it. An activation reservation is returned only when provisioning fails before delivery. A disconnected number that Tyxter still holds at the carrier keeps billing until you release it.
phone.number.month is a rental pass-through for numbers Tyxter provisions on your behalf. A number you connect from your own Meta WhatsApp Business account is never metered — R$0 per month. A number imported from your own Salvy account is free while you have a Standard or Growth plan and through the end of the UTC month in which that plan ends; after that, keeping Tyxter’s management of it costs the monthly phone.management.month fee, charged on the 1st, described in Phone numbers. Either kind still counts toward your plan’s production phone-number allowance.Read managed-number payment and service
GET /v1/billing/phone-management reads the API key's project and environment. Charged coverage.state: prepaid alone does not prove payment. current_month_payment_status is paid or unpaid for the current enrollment's funded UTC month, using durable unpaid-month evidence, and not_charged without a funded fee. service_state distinguishes serving, disabled_unpaid_month_end, funding_required and not_serving; provider eligibility, enrollment fences and structural suspension affect service separately from payment. This is not a general send-eligibility verdict.
disable_at is the free-plan month-end deadline for live, unfenced, unended charged coverage whose month stays unpaid; paid plans have no deadline. It remains visible during the release window and is null from the 18:00 UTC cutoff. Provider eligibility and structural suspension do not remove billing disable exposure. Sandbox funded zero fees read paid, otherwise not_charged, with no unpaid state, deadline or unpaid-disable service state. summary.next_charge_brl totals only fees at summary.next_charge_at, or null without a scheduled charge; monthly_total_brl remains the total across all scheduled instants. Older responses may omit these added nullable fields.
Example dates
Each example is a number ordered, approved, delivered and active on the same day.
- Bought on 2026-10-03. The activation fee is reserved on Oct 3, its line is dated Oct 3, and it pays for October. The November renewal notice comes on Oct 25; November is charged from 00:05 UTC on Nov 1 with a line dated Nov 1. On the free plan, if November is still unpaid on Nov 30, the number is released.
- Bought on 2026-10-28. The activation line is dated Oct 28 and pays for October. November is charged from 00:05 UTC on Nov 1 with a line dated Nov 1, four days after the activation fee: lines dated Oct 28 and Nov 1 pay for two different months, October and November.
Failed message processing
Eligible persisted WhatsApp failures before provider acceptance use msg.failed_processing, initially 10% of the transport rate. Permanent template, recipient and asset mistakes qualify. Internal or unknown faults, ambiguous network failures, temporary upstream errors, capacity deferrals and account restrictions are free, as is API validation that creates no message. After provider acceptance, the full transport fee remains due even if delivery fails; a message cannot receive both charges. Historical failures without an eligibility receipt are not backbilled.
At the repository fixture transport price R$0.0500, failure processing is R$0.0050 on Free, R$0.0030 on Standard and R$0.0016 on Growth. Consult the live rate card for current prices. The failure-time card and settlement-time plan are snapshotted in the existing usage record transport breakdown, with no Meta reference or conversation category. Failure processing never consumes package quota. Cash collection is limited by credit headroom; any uncollected remainder remains recorded. Sandbox models prices without cash or package debit.
Meta reference rates
Meta bills your outbound WhatsApp messages directly to your own Meta account, per delivered message, at a rate that depends on which of its categories the message falls into. Tyxter is not the billing party for them, never debits them from your credit balance, and never marks them up. They appear on the rate card as kind: "meta_reference".
estimated_external_meta_cost only after an official BRL source and its effective date pass independent verification; until then the amount is null and missing quantity is reported explicitly.When available, the estimate is calculated from the immutable rate selected at each usage event's timestamp. It stays separate from cost_brl, your credit balance, ledger, invoice, package quota, and the always-zero pre-BSP meta_pass_through_fee_brl. Meta's own account and invoice remain authoritative.
Sandbox usage reports the same estimate fields so you can model production Meta costs before going live. Sandbox messages are simulated inside Tyxter — Meta never delivers or bills them, so a sandbox estimate is a modeling aid, not an incoming charge.
Why Meta invoices you and not Tyxter — and who owns the WhatsApp Business Account that invoice belongs to — is set out on the Tyxter and Meta page.
Plans
A plan is a monthly subscription that lowers the per-message transport fee and raises your throughput and phone-number limits. Free is the absence of a subscription rather than something you buy — you get the base rate and the smallest limits, with no monthly fee.
Plans, like the credit balance, attach to the organization: one subscription covers every project and environment under it, and the discounted per-message rate applies to traffic from all of them. There is no per-project plan or wallet. Per-project attribution survives the shared wallet — invoices are generated per project and a monthly spend limit can be set per project in the dashboard. Integrations that run one project per end customer are covered on the Multi-tenant platforms page.
| Plan | Monthly | Per WhatsApp message | Sustained throughput | Production numbers |
|---|---|---|---|---|
| Free | — | R$0.05 | 30 msg/s | 1 |
| Standard | R$209.90 | R$0.03 | 60 msg/s | 3 |
| Growth | R$419.90 | R$0.016 | 120 msg/s | No fixed limit |
GET /v1/billing/plans is the live catalog and the source of truth for the money columns. Every offering carries monthly_fee_brl, annual_pix_fee_brl, platform_fee_multiplier, max_phones, and the already-multiplied net_transport_rate_brl — read that last field and you have the exact per-message rate the plan bills, with no arithmetic. It lists what you can buy, so Free is not in it. To read the plan your organization is on right now, Free included, call GET /v1/billing/plan, where status: "none" means Free. Paying a year up front by PIX is also offered, at each plan’s annual_pix_fee_brl.
The catalog also exposes salvy_byok_enabled as plan eligibility: an eligible plan can import numbers from your own Salvy account, with no management fee while it stays active and through the end of the UTC month in which it ends. Standard and Growth are eligible; Free, pending payment, and custom plans are false by default. A paid plan also keeps the numbers Tyxter rents for you from the month-end release for non-payment, and the numbers you imported from the month-end disable. Eligibility is separate from the rollout fence, so availability follows the deployment rollout. An already paid term keeps management free through the end of the UTC month in which its period ends, even if a later renewal payment fails.
Sustained throughput is the ceiling your plan sets on outbound sends, with a bucket of exactly twice that many messages available for a burst. It is a ceiling, not a guarantee: each number sends at whichever is lower, your plan’s rate or that number’s own Meta messaging limit — so a number Meta still rates at 30 msg/s sends at 30 msg/s on every plan. The dashboard shows the effective limit per number.
The phone-number allowance counts active production numbers of both kinds — provisioned by Tyxter and brought from your own Meta account — across every project in the organization, whichever WABA each number belongs to. Going past it returns 402 plan_phone_limit_reached on the next order, provision, connect or Salvy import (POST /v1/phone-numbers/import-salvy), and again when an owner or admin approves an order; numbers you already have are never removed when you move to a smaller plan.
Numbers Tyxter provisions for you have their own limit, separate from that allowance: 1 on Free, 3 on Standard and 10 on Growth by default. On Growth that reads as up to 10 Tyxter-provisioned numbers by default (R$50/number/month) — more on request · unlimited bring-your-own numbers, because Growth sets no plan allowance at all; on Free and Standard the allowance above still counts your own numbers too. The ceiling counts only active production numbers Tyxter provisioned: a number you brought from your own Meta account never counts toward it, and sandbox provisioning is never capped. An order or provision request past the ceiling, or an approval that would pass it, returns 409 phone_number_limit_reached — release a Tyxter-provisioned number to free its slot, or contact us and we will raise the limit for your organization. The plan allowance is evaluated first, so an organization already at its allowance sees 402 plan_phone_limit_reached and should upgrade rather than ask for a higher ceiling. The ceiling is not published on GET /v1/billing/plans; max_phones there is the plan allowance, which counts numbers of both kinds.
Subscribing, switching, and cancelling are documented on the Billing API reference.
Spend limit
Set a monthly BRL cap per project from the dashboard. Once month-to-date production spend reaches the cap, every send path refuses new work with 402 spend_limit_exceeded until the next calendar month rolls over — or you raise the cap: POST /v1/messages, POST /v1/batches, the MCP send and broadcast tools, and dashboard sends and broadcasts. A running broadcast stops before its next page of recipients and emits message_batch.failed with error_message: "spend_limit_exceeded"; an automation message step fails its run with the same code. A spend_limit.hit webhook fires on the crossing, unless a rental fee or a payment fee caused it. The cap limits what you send; it does not stop the monthly rental fee of a number Tyxter provisions for you, which is charged regardless and counts toward the spend of the month its ledger line is dated in (see How number rental is billed). It does not refuse a payment creation either, and payment fees count toward month-to-date spend (see Payment fees).
Low-balance alerts
When the balance crosses the configured threshold downward (default R$10), a credit.low_balance webhook fires exactly once per decrement that caused the crossing. Subscribe to it to auto-top-up.
Invoices
Monthly CSV roll-up per project. BuildInvoiceUseCase is idempotent on (project_id, period_start); the download URL is a 15-minute presigned S3 GET.
For a per-phone read, poll GET /v1/phone-numbers and GET /v1/phone-numbers/{id} with phone_numbers:read, including while credit is exhausted. Their renewal field reports the current month: the next charge on the 1st, whether the month is unpaid with the recommended action, and on the free plan when an unpaid number is released (see How number rental is billed). The renewal field can report at_risk while status is active. The Billing page joins that shared current assessment to recorded history by scoped phone ID; loading or missing current data is never treated as healthy. See the phone-number guide for all-page polling and recovery without email.