Billing & credits
What consumes credits, plan allowances, managed vs BYOK, and the credit lifecycle.
Oxygen uses one credit pool per organization. Managed enrichment, AI, infrastructure, and live workflow actions all draw from that pool. Prices vary by operation and are shown before live execution.
Database hosting is included in your OXYGEN plan, with no separate hosting charge. There is no per-workspace database sleep control. Separately priced operations on your data still use the credits described below.
oxygen billing balance --json returns the available and reserved balance.
What consumes credits
| Work | What it draws |
|---|---|
| Managed enrichment or domain provider call (Oxygen's key) | Credits at the catalog price |
| AI column run on Oxygen's keys | Credits by model tier, plus web-search cost when enabled |
| The same provider call on your own key (BYOK) | 0.05-credit OXYGEN platform fee per call; your provider bills the call itself |
| An AI call on your own model key | 0 credits |
| Live workflow steps, tool calls, retries | 0.05 credits per step |
| Rows written inside a workflow run | 0 credits |
| Sequence sends through your connected email accounts | 0 credits |
Workspace reads, schema changes, dry_run / smoke_test | 0 credits; a live provider read on your own key pays the BYOK fee above |
BYOK calls appear in the ledger as byok_usage entries, so provider usage stays auditable. Each entry records the platform fee it paid (byok_platform_fee_credits), and --meter byok_calls shows the fee per call, this month's calls and fee credits. The fee settles from your balance every two hours like workflow steps:
oxygen billing usage --type byok --json
oxygen billing usage --meter byok_calls --json
oxygen billing audit --group-by category --jsonA BYOK call is refused with insufficient_credits, before your provider is contacted, when your balance cannot pay its fee.
Every ledger entry carries a category. Fixed monthly charges are managed_seat, managed_mailbox, managed_inbox, managed_warmup and managed_deliverability; flexible spend is managed_ai, managed_enrichment, managed_domain, automation, linkedin_action and voice_call; byok records your own-key calls; and free, trial, subscription, purchase, admin, bonus and partner_bonus are credits arriving.
Every billing audit result ranks spend by category in spend_by_category, largest first, with each category's credits and its share of the window's spend, whatever --group-by is. Spent is credits reserved minus released in the window. It differs from the settled figure by holds still open (reserved_credits) and by holds that settle across the window edge; totals.managed_credits_captured is the settled part and equals billing usage's managed_credits_used.
Workflow steps
Only live runs draw workflow-step credits; dry_run and smoke_test cost nothing. Writing rows is free: a step that writes 1 row or 10,000 rows is one step. Steps are counted like this:
- Plain workflows and graphs: 1 step per step or billable node executed.
- Recipes: 1 step per run attempt, plus 1 per checkpoint the recipe code emits at runtime — every
ctx.tools.run,ctx.step,ctx.rows.upsert, or similar call. Loops multiply: a run that processes 100 items bills 100+ steps, regardless of how few steps the visual plan shows. - Row writes (
rows_upsert): free. The step that writes them counts once. - Retries: a retried attempt bills its re-executed steps again (already-completed checkpoints replay free).
Paid tool steps (enrichment, AI) bill their own tool price in addition to the step.
The number on the workflow page next to the schedule is a static minimum derived from the manifest. Trust the observed steps/run and the 30-day projection shown beside it (also in oxygen workflows get --json under usage.observed) — they come from your real run history. usage.credits_per_step is the step price in force, and oxygen billing usage --meter automation_actions --json reports the credits your steps billed (credits_used), each at the price in force when it ran.
A schedule is refused at enable time only when its cheapest possible month costs more than both your plan's monthly credits and the credits you can spend right now. A funded schedule keeps running while your balance covers it. For cadence guidance, see Triggers.
Plan allowances
There is one plan, Oxygen, sold at six monthly rungs. The rung is how many credits you buy; every rung carries the same capabilities.
| Plan | Price / mo | Credits / mo | Price / 100 credits | BYOK |
|---|---|---|---|---|
| Oxygen | $49 | 4,900 | $1.00 | Yes before repricing; existing connected keys only afterward |
| Oxygen | $99 | 9,900 | $1.00 | Yes |
| Oxygen | $199 | 19,900 | $1.00 | Yes |
| Oxygen | $499 | 52,395 (+5% volume bonus) | $0.95 | Yes |
| Oxygen | $999 | 109,890 (+10% volume bonus) | $0.91 | Yes |
| Oxygen | $1,999 | 229,885 (+15% volume bonus) | $0.87 | Yes |
Everything else that scales with plan size has one column per size in the pricing reference: default spend ceilings (unattended trigger deliveries and auto-runs, Agent runs, the Copilot allowance), API rate limits and table and signal limits. oxygen limits show --json returns the same values for every size under plan_bands, and spend_safety_defaults.applies_to says what each ceiling bounds.
Once the repricing epoch takes effect, connecting a new provider API key needs the $99 plan or above. A $49 workspace keeps using its previously connected keys until its plan changes. Before that epoch, $49 includes new keys too; a refused connection reports the required plan.
The free plan does not include your own keys, and a new key cannot be connected on it. A free workspace that still holds keys from an earlier plan or a trial keeps running them for 7 days, counted from the first time Oxygen sees them on the free plan. oxygen billing balance --json shows the end date in byok_credentials.free_plan_grace_until, and the billing page shows it on the plan card. After that date, runs on those keys are refused with byok_requires_paid_plan; the refusal names the plan to upgrade to and carries upgrade_url.
Plans convert at $1 per 100 credits, and the $499, $999 and $1,999 rungs add a volume bonus of 5%, 10% and 15% on top, so a bigger plan buys more credits per dollar. If you already hold one of those three rungs, the bonus starts with your next renewal. oxygen limits show --json lists every rung's monthly_credits, volume_bonus_percent and usd_per_100_credits. On-demand credits cost more per credit than plan credits and can be purchased in any 100-credit increment from 800 to 100,000, or as one of the listed packs. Purchased credits never expire. oxygen billing topup --json (MCP oxygen_billing_topup with no amount) reports the price per 100 credits in force (usd_per_100_credits), the price of the smallest and largest amount, and the packs on offer; the checkout it creates names the exact amount before you pay, and the price you were quoted is the price you are charged even if the rate changes before you pay. When a price change has been scheduled, the same response carries scheduled_rate: the instant it takes effect, the price per 100 credits from then on, and the packs offered from then on.
Starter, Pro, and Team are grandfathered: they still bill the customers who hold them, at the credits those customers signed up for, but they are no longer offered for sale. Nothing about an existing subscription changes.
Yearly billing
Yearly plans commit for twelve months and are paid monthly, with about 17% savings. Monthly payments are $40.83 / $82.50 / $165.83 / $415.83 / $832.50 / $1,665.83 before tax. The term total is twelve payments at the displayed price. Credits still arrive monthly after each paid invoice; the credit amount and volume bonus do not change. The commitment renews for another year unless you turn off renewal. Turning off renewal keeps monthly payments and credits running until the term ends. Upgrades keep the term end; downgrades and switching to monthly wait until then. Existing prepaid yearly subscriptions keep their current terms and monthly credit slices.
- Buy yearly: choose Yearly · paid monthly in Settings → Billing, or run
oxygen billing change --to oxygen_99 --term year --interval month(MCPoxygen_billing_change_plan,term: year,interval: month). Review and accept the twelve-month terms in Checkout. The offer is available only whenannual_monthly_billing_availableis true inoxygen billing balance --json. - Check your commitment:
billing balancereportssubscription.commitment, including its end date and renewal state. Payments still occur every month.
On the free tier, an eligible billing owner receives one signup grant of 1,000 credits when signup grants are enabled. Free has no monthly refill. Cancelling or downgrading does not create another grant. Read oxygen billing balance --json for the available balance and top-up options. A whole month priced from the same constants — outbound to 200 companies, line by line — is on the landing page: oxygen-agent.com/#what-it-costs.
Storage limits are resolved per plan size: rows per Table, retained Table rows per workspace, and a PostgreSQL Workspace Table database limit with a warning below it. One import file may hold as many rows as one Table. Before the repricing epoch, every plan size up to Oxygen $499, Free included, allows 3,000,000 rows per Table, 25,000,000 retained Table rows per workspace, a database warning at 20 GiB, and net-new PostgreSQL Workspace Table growth up to 30 GiB. Oxygen $999 allows 50,000,000 retained Table rows and 60 GiB (warning at 40 GiB), and Oxygen $1,999 allows 100,000,000 and 120 GiB (warning at 80 GiB); both keep 3,000,000 rows per Table until the capacity test at 5,000,000 and 10,000,000 rows per Table passes. After the repricing epoch, the source limits for Free, $49 and $99 move to 100,000, 1,000,000 and 2,000,000 rows per Table respectively. Serving those limits also requires the workspace’s persisted tenant guard to be synchronized; the epoch alone does not prove that synchronization. The pricing reference lists both sets of source values for every plan size. In oxygen limits show --json, each plan size's storage.status says whether its limits are in_force, scheduled to change at effective_at, or awaiting_capacity_test, with the values they move to in storage.target; storage_capacity.usage.largest_table names the Table a rows-per-Table limit reaches first, and a refused write names the full Table by id. The byte guard covers Table heap, indexes, and TOAST; S3/object storage is separate. A workspace billed through another workspace takes that workspace's plan size. Per-operation safety limits still bound one import, request, or action run; inspect current usage and effective limits with oxygen limits show --json. When a price or limit change has been scheduled, the same response also carries pricing_schedule: the instant it takes effect and, for every value it moves, the value in force now and the value from that instant on.
Rate limits and default spend ceilings also scale with plan size. oxygen limits show names your plan band (free or one of the six sizes) and lists every size's limits side by side, with yours marked; grandfathered plans keep the limits they already have. In the web app, Settings → Plan limits (oxygen-agent.com/limits) shows the same comparison, your workspace's spend defaults and what each one bounds, and any scheduled change with its date. The request rates for every plan size, and how to back off from a 429, are in the pricing reference, and so is the number of webhook deliveries each inbound webhook accepts a minute.
Sending limits are the same on every plan, and sending itself costs no credits. sending_limits in the same response lists them per channel: emails per mailbox (a new mailbox sends 5, 10, then 20 a day while it warms up, then its own cap, 25 a day by default), WhatsApp messages per number (20 by default, up to 40), LinkedIn invites per account, and calls per number (100 by default, up to 300, between 09:00 and 20:00 in the lead's time zone). Each channel's default and any maximum in force are in the response, with the command that changes it.
At a row or database hard limit, Oxygen blocks only writes that would increase the exceeded counter, and nothing is deleted. Reads, previews, queries, exports, row deletion, permanent Table purge, and updates that do not grow measured database storage remain available. To recover database space immediately, delete rows or preview and approve oxygen tables delete <table> --now --yes (a table with a large history answers purging and releases its space when the background purge finishes); archiving a Table or scheduling its default 14-day deletion does not reclaim space until the physical purge completes. Capacity writes resume automatically after usage falls below the boundary, or as soon as the workspace moves to a plan size with a higher limit. See Tables for the deletion lifecycle.
A full monthly plan allowance is granted only after Stripe confirms the billing period with invoice.paid. A subscription status change or an unpaid renewal never grants the next allowance.
Agency partner bonus
An agency with a published listing in the agency directory earns 15% of its plan's price in bonus credits every month, on every Oxygen plan from $99, on top of the volume bonus:
| Plan | Plan credits a month | Partner bonus | In all |
|---|---|---|---|
| $99 | 9,900 | 1,485 | 11,385 |
| $199 | 19,900 | 2,985 | 22,885 |
| $499 | 52,395 | 7,485 | 59,880 |
| $999 | 109,890 | 14,985 | 124,875 |
| $1,999 | 229,885 | 29,985 | 259,870 |
The bonus arrives with each monthly plan grant, annual plans included, as its own ledger line in the partner_bonus category. It is never counted in plan.monthly_credits, so it raises no limit or default spend ceiling derived from the plan. oxygen billing balance --json (MCP oxygen_billing_balance) reports it under partner_bonus: whether this workspace earns it, how many credits, and why not when it does not. oxygen billing usage --category partner_bonus --json lists every bonus line. The bonus follows the plan that pays for it: a client workspace linked with oxygen orgs billing-link draws on the owner's plan and earns no bonus of its own. The $49 plan, the grandfathered plans, and invited or delisted listings earn none. A listing published mid-month earns that month's bonus with the next grant, an upgrade raises it to the new plan's, and a refund of the plan payment reverses it in the same proportion as the plan credits.
Credit lifecycle
| State | Trigger |
|---|---|
| Granted | Plan refill or top-up |
| Reserved | A run starts; estimated cost held against balance |
| Captured | Run item succeeds with cost > 0 |
| Released | Run item fails before billing; reservation returned |
oxygen billing balance returns available and reserved.
Which holds make up reserved
oxygen billing usage --meter holds --days 365 --json lists each open reservation in the workspace: its credits, what it was for, its run, how long it has been held, why it is still held (reason) and whether OXYGEN returns it on its own (automatic_return). total_open_holds and total_credits_held cover every hold in the window, and totals_by_reason, totals_by_automatic_return, top_tools and top_runs break that window down without paging; page_holds covers the page, and next_cursor (--cursor) reads the next one. reconciliation relates these totals to the balance's reserved_credits: the workspace's open holds for all time, the billing account's (all its workspaces), and unattributed_reserved_credits, reserved credit no open hold accounts for, with any balance adjustments that explain it (reserved_adjustments). That remainder is not a hold, and no hold release returns it. --days defaults to 30, so older open holds need a longer window. MCP clients call oxygen_billing_usage with meter: "holds" and pass cursor the same way; when a page would not fit an MCP response, it returns fewer holds than limit (limited_for_context), and next_cursor still resumes after the last hold returned. The read is free and changes nothing; you cannot release or retry a hold from it.
reason | Meaning |
|---|---|
open | The call is still running or its charge is not final yet. |
result_pending_settlement | A result was delivered and its charge is being finalized. |
outcome_unknown | A LinkedIn lookup did not confirm a result; the credits stay held, not charged. |
unmarked | A LinkedIn data request's hold carries no outcome marker, so OXYGEN cannot tell an unknown result from a delivered one that was never charged. |
unsettled | Any other hold whose charge was never finalized. |
automatic_return says whether OXYGEN returns the hold on its own: eligible (from automatic_return_eligible_at until automatic_return_window_ends_at, on a later hourly pass), not_enabled (automatic return is not switched on), outside_window (older than the 30 days automatic return covers) or not_applicable (not part of automatic return). Only outcome_unknown and unmarked holds can be returned automatically.
Pending warm-up enrollment
For one inbox, oxygen mailboxes get <email> --json reports the enrollment's billing state in warmupTruth.billing. status: pending with hold.reason: enrollment_pending means credits are reserved while enrollment confirmation remains incomplete. hold.credits is the amount held, not a captured charge or a second monthly fee. A vendor seat can already exist or be paused while this confirmation is incomplete; a pause alone does not explain why the hold remains.
Preview recovery with oxygen mailboxes warmup enable --mailboxes <email> --json. This preview changes no provider state and spends no credits. It separates the recurring price (total_monthly_credits), existing held credits (reserved_credits), and new credits required (additional_credits). A zero max_credits allows no new reservation; approved recovery can still capture the existing hold once the enrollment is confirmed.
Warm-up on a mailbox you connected yourself is included in its 100-credit monthly connection once that connection is charged (2026-09 repricing): the preview then reports included_in_connection: true and max_credits: 0, approval reserves nothing, and an unused hold left by an earlier priced approval is released. A hold for an enrollment already handed to the provider still settles at the price that was approved.
Use the preview's plan_hash value with the CLI flag --plan, plus --approved --max-credits <max_credits>. Review any safety-pause reason before approving: do not restart an unsafe inbox merely to settle a hold, and do not disable and re-enroll it to bypass recovery. See email setup for the enrollment flow.
Managed vs BYOK
| Mode | Who pays | What it covers |
|---|---|---|
| Managed | Oxygen credits | Oxygen holds the provider API key. Default for enrichment providers. |
| Provider API key (BYOK) | You pay the provider directly | Your own provider API key; plan eligibility applies. |
| OAuth / hosted account sign-in | Integration access; account reservations or legacy seats can still apply | Your own CRM or connected sending account; separate from provider API-key eligibility. |
Calls on your own provider API key are billed by your provider, and OXYGEN charges a 0.05-credit platform fee per call. They are logged as byok_usage ledger entries (category byok). New provider keys require $99 or above after the repricing epoch, with the $49 exception described above. OAuth integration calls do not pay that API-key fee; connected accounts follow the model in connections and sending. A refusal names the smallest plan that includes it in details.minimum_plan and links to the upgrade page in details.upgrade_url.
A table column on your own key quotes the fee per row in columns run previews, a run's max_credits bounds it, and a saved auto-run without max_credits stays inside your plan's per-delivery default ceiling (spend caps). An enrichment waterfall lane on your own key pays the fee on each call, found or not. enrich-column preview and columns run previews include it for every own-key lane a row can reach, and the run reserves it (waterfalls).
The plan-scaled BYOK daily value is a monitoring threshold by default, not a blocking entitlement cap. oxygen limits show --json reports both byok_provider_daily_call_warning_threshold and byok_provider_daily_call_enforcement_mode; observe_only means calls continue after the threshold, while enforced means they stop. Explicit workspace policies created with oxygen limits provider set are enforced independently and appear in oxygen limits provider list --json.
oxygen integrations list --json shows the mode per provider. See Integrations.
Reading balance and usage
oxygen billing balance --json
oxygen billing usage --limit 50 --json
oxygen billing usage --type byok --json
oxygen billing usage --meter byok_calls --json
oxygen billing usage --category partner_bonus --json
oxygen billing audit --group-by category --jsonUsage entries include run, provider, tool, credit, and timestamp fields when available. The audit groups them for you, by provider, by day, or by any of type, category, source, tool, model, run and workspace:
oxygen billing audit --group-by provider --json
oxygen billing audit --group-by day --jsonThe web app at oxygen-agent.com/billing renders the same data with charts.
Usage per client workspace
When one plan pays for several workspaces (an agency covering its client workspaces with oxygen orgs billing-link), every credit they spend is in the paying workspace's ledger, tagged with the workspace that spent it. From the paying workspace:
oxygen billing usage --group-by workspace --json # credits each workspace spent
oxygen billing usage --workspace <id|slug> --json # one client's ledger events
oxygen billing usage --group-by workspace --category managed_ai --days 90 --json--group-by workspace adds by_workspace, one row per workspace, largest first: workspace_organization_id, name and slug, billing_owner (true for the paying workspace's own spend), credits_spent, transaction_count and byok_usage_events. credits_spent is the credits held and not released, the same figure the web app's By workspace section shows, and by_workspace_credits_spent is the total the rows add up to. When no other workspace is billed through the plan, by_workspace_note says so and names oxygen orgs billing-link. Every other filter (--category, --type, --provider, --days, --from, --to, --workspace) narrows the rows too. A workspace you are not a member of is listed by id without a name, as is one that has since been unlinked; --workspace also accepts such an id. MCP: oxygen_billing_usage with group_by: "workspace", workspace and category. In the web app, the workspace picker next to the 7/30/90-day toggle in Settings → Billing narrows every chart to one workspace.
A linked client workspace sees only its own spend: its --group-by workspace returns its own row, and naming any other workspace returns workspace_not_in_billing_pool. Both options read the credit ledger, so they are refused with unsupported_for_meter next to --meter automation_actions, byok_calls or provider_seats.
A workspace linked to another organization with oxygen orgs billing-link reads its billing at that owner. oxygen billing balance --json reports the owner's credit pool with shared_billing: true and names the owner in billing_owner_organization_id, and oxygen billing invoices --json returns an empty list, because the invoices belong to the owner. Switch to the owner workspace to read them or to top up.
Cost estimation
Before running anything paid:
oxygen tools get <tool-id> --json | jq '.data.tool.cost.managed_credit_estimate'
oxygen columns run <table-id> <column-key> --limit 1 --json
oxygen workflows templates preflight <template-id> --input-json '{...}' --mode dry_run --jsonWhen managed_credit_estimate.quote_basis is default_request, default_request_credits prices the estimator's empty input (quote_input: {}). The legacy min and floor fields repeat that quote; they are not a minimum. Required native inputs still need to be supplied, and a smaller or larger request can cost less or more. scales_with names the fields that change the quote. max: null means the catalog does not give an upper quote; native request limits can still apply. Preview the exact inputs before approving a paid call.
Spend caps enforce predictability per run.
Estimate a month
To price a whole outreach motion before you build it, name the leads, the enrichment on each lead, the sequence and the senders:
oxygen billing estimate --leads 500 --enrich work_email --email-steps 2 --linkedin-steps 1 \
--mailboxes 1 --linkedin-accounts 1 --jsonSteps are counted per channel, so a 3-step sequence of two emails and one LinkedIn invite is --email-steps 2 --linkedin-steps 1; summary restates what was priced. The estimate is free and uses the prices in force. It returns one line per cost: each enrichment at its expected and worst-case credits per row (take ids from oxygen enrichment catalog --json), each mailbox and LinkedIn account at its monthly price, and sends at 0 credits. sender_billing says whether senders are paid as sending seats in dollars or as monthly credit reservations; seat dollars are totalled separately in totals.usd_seats_per_month, because a plan's credits never pay for them. plan_fit checks your own plan (or --plan) and names the top-up it would need; recommended_plan is the cheapest plan plus top-ups that covers the month, for the expected and the worst case; each monthly_usd is all in, seats included. limits compares the sends with the per-account sending limits: limits_hit names each one the scenario exceeds, binding_limit the limit that sets a sender's monthly capacity, and senders_needed how many mailboxes or LinkedIn accounts it takes. The limits are the defaults for a newly connected account. MCP clients call oxygen_billing_estimate; in the web app the same estimate is under Settings → Plan limits → Estimate a month, and the web_url in the response opens it filled in.
What's free
| Action | Costs credits |
|---|---|
tables query, rows history, cells inspect | No |
tools search, tools get, integrations list | No |
dry_run or smoke_test of any tool/column/workflow | No |
context profile get/update, assets * | No |
columns add, tables rename, schema changes | No |
skills list/doctor/install | No |
live provider call on your own key (BYOK) | Yes — a 0.05-credit platform fee per call |
live AI call on your own model key | No — logged as a zero-credit byok_usage entry |
| Live workflow steps, retries | Yes — 0.05 credits per step |
| Rows written inside a workflow run | No |
| Sequence sends through your connected email accounts | No |
live AI/tool/enrichment column run on managed keys | Yes (per call) |
Failure billing
| Failure point | Credit treatment |
|---|---|
| Pre-billing (auth, validation, 429 before charge) | Released |
| Post-billing (provider charged then returned error) | Captured |
| Partial provider cascade | Captured for paid attempts only |
Subscriptions
Every new workspace starts on the free tier: no card required and no trial deadline. You get the full CRM, Tables, Workflows, Knowledge, Recipes, Agents, and the Workspace Copilot. Eligible billing owners receive one signup grant of 1,000 credits when signup grants are enabled; Free has no monthly refill. oxygen billing balance --json reports the credits available now. Sequences are fully authorable — build steps, preview, and enrol recipients — on the free tier.
Read oxygen billing estimate --json for the connection model in force. When sender_billing is credit_reservations, credits fund connected accounts, sending, supported publishing and managed email purchases on eligible Free workspaces as well as paid plans. The workspace’s own subscription entitlement still applies; a cancelled paid subscription does not create new Free eligibility. Your own provider keys and Instagram, TikTok, YouTube and Facebook publishing still need a paid plan. On the legacy sending_seats model, a paid plan and sending seats also gate those sending connections and actions.
Choose a paid plan for its monthly credits and plan-sized limits. Provider API keys retain the minimum-plan requirements above. Pick an amount from the visible tiers under Settings → Billing or Upgrade in the sidebar. A plan-gated action opens that selector. On credit_reservations, an eligible Free workspace instead needs enough credits for supported accounts and actions; a credit refusal calls for a top-up. Provider API keys and Instagram, TikTok, YouTube and Facebook publishing retain their plan requirements. Stripe Checkout then returns you to the page you were on. From the CLI or MCP, a refused action's upgrade_url opens the same selector, and oxygen billing change --to <plan> (MCP oxygen_billing_change_plan) starts the subscription directly: on a workspace with no plan it returns mode: first_subscription, the plan's price and monthly credits, and approval_url, the same Stripe Checkout the selector opens. Nothing is charged until you pay there, and the credits arrive once Stripe confirms the payment. Add --term year --interval month for a yearly commitment paid monthly. Only an organization admin or owner can subscribe.
First-month offer. While it runs, a workspace that has never had a plan can take its first month of the $99 size for $49. Subscribe to $99 billed monthly within 24 hours of first seeing the offer, and Stripe Checkout takes $50 off the first invoice automatically; every later month is $99, and the first month still grants the full 9,900 credits. The yearly plan and the other sizes do not get it, and a checkout that carries it has no promotion-code field. oxygen billing change --to oxygen_99 (MCP oxygen_billing_change_plan) reports it as offer (first_month_usd, regular_usd, ends_at), with amount_due_now at the first month's price and next_invoice_total at the regular one.
If a card is a hard blocker on your side (company policy, procurement), email support and we'll find a path.
Plans, invoices, discounts, payment methods, and cancellation are managed through Stripe from Settings → Billing. Oxygen keeps plan selection and credit usage inside the product.
Every charge produces an invoice, including a credit top-up. Download them under Settings → Billing → Invoices, or list them with oxygen billing invoices. To show your company's VAT or tax ID on invoices, choose VAT or tax ID on the Invoices card and add it in Stripe; checkout also asks for it. Stripe prints it on every invoice issued after you save it, never on an earlier one, so add it before your next payment.
Each org has its own subscription and credit balance by default. An agency can link a workspace with no live subscription of its own to an eligible paying organization using oxygen orgs billing-link. The owner funds its credits without gaining access to its data. plan_tier names the owner's plan; sender_billing in oxygen billing estimate --json names the connection model. On credit_reservations, a Free billing owner can fund connections with credits. On legacy sending_seats, the owner's paid plan and seats apply. See Billing ownership.
Sending seats
Legacy model only: when oxygen billing estimate --json reports sender_billing: sending_seats, a connected sender uses a dollar sending seat, separate from plan credits. LinkedIn and WhatsApp seats cost $30/month, a rented phone number $10/month, and a mailbox you bring yourself $1/month; an OXYGEN-sold managed mailbox includes its seat. oxygen billing seats --json reports purchased, grandfathered and occupied capacity. Seats belong to and are bought on the billing owner. When the response instead reports status: seats_retired, new connections use credit reservations, and adding seats is refused.
A connected LinkedIn account or WhatsApp number that stops working leaves your senders on its own and frees its seat: at once when the provider reports it stopped or disconnected, and after 7 days when it stays in a state you could still fix, such as needing a new login. Reconnecting the same number or LinkedIn profile retires the old connection instead of keeping two live ones: its sequences move to the new connection, and the old one stays listed as disconnected (with superseded_by in its metadata) and holds no seat. Disconnecting an account (oxygen senders disconnect, oxygen whatsapp disconnect) frees its seat straight away. A freed seat stays purchased until you lower the count with oxygen billing seats set.
Connected-account reservations
The prospective 2026-09 repricing changes monthly account unit prices: a LinkedIn account to 3,400 credits ($34, for outreach, publishing or both), a WhatsApp number to 3,400 ($34, the same as a LinkedIn account), and X accounts and rented phone numbers to 1,000 ($10). Before that price epoch, LinkedIn and WhatsApp reservations use 1,000 credits; X and phone reservation prices are zero. These prices do not establish that a resource has a billed commitment. Read oxygen billing estimate --json for the connection model and current prices, and oxygen billing commitments --json for existing commitments and their anchors. The pricing reference has the price table.
When reservations replace sending seats, connecting an account is judged on credits instead of a seat. The balance must cover the account's first month: a LinkedIn connect with fewer credits free to spend than its reservation fails with insufficient_credits (exit code 7). The error gives the reservation, the credits free to spend, next_step (the exact oxygen billing topup command) and topup_url. In the web app the same refusal offers the top-up. Re-authorizing a mailbox you already hold reserves nothing new. From then on oxygen billing seats reports status: seats_retired and refuses to add seats. Seats you already hold keep covering their accounts until they end at renewal, and you can still lower them.
Paid-seat coverage excludes the accounts it covers from credit reservations: with 2 LinkedIn seats and 3 connected LinkedIn accounts, only the most recently connected account needs a credit reservation. oxygen billing seats --json gives the known end of held coverage as held_seats_end_at, and after_seats_end gives each channel's monthly credit price; an unavailable date or coverage result stays unknown. The MCP tool oxygen_billing_seats returns the same notice and fields. Inspect the account's commitment before relying on its next billing date, especially after disconnecting and reconnecting it.
When sender_billing is credit_reservations, an eligible Free workspace can connect accounts, send sequences, use supported publishing and buy managed email infrastructure when its balance covers the reservation or purchase. Losing a paid plan alone no longer disconnects LinkedIn accounts or WhatsApp numbers funded by their reservations. This connection model has its own switch and takes effect only once its required repricing epoch is effective; read oxygen billing estimate --json for the model in force. On that model, OAuth connections to your own tools (HubSpot, Attio, GitHub, Composio apps) are open on every plan. Your own provider keys and Instagram, TikTok, YouTube and Facebook publishing accounts still require a paid plan.
On the credit-reservation model, sponsoring a UGC creator costs one connected LinkedIn account: the creator's LinkedIn reservation is charged to the sponsoring workspace's billing owner, not to the creator, and the creator receives no credit grant. A creator several programs sponsor still costs one reservation. oxygen ugc sponsorship preview --json shows monthly_credits and spendable_after before you confirm (in the web app, Sponsor on a program's Creators tab shows the same preview), and the reservation appears in the sponsor's oxygen billing commitments --json. Sponsorships already paid by card keep their seat and monthly credit grant until their subscription ends.
When a reservation cannot be renewed
Once credits become the only gate on connected accounts, a reservation your balance cannot cover at its renewal pauses that account straight away:
- Sending from that account stops at once. Its sequence steps wait instead of failing, queued emails from that mailbox are held, scheduled posts on it are re-armed, and a phone number cannot dial. Every other account in the workspace keeps sending.
- You are told. The billing owner gets one email per unpaid streak, and
oxygen billing commitments --jsonshowspaused_quantity,past_due_since,disconnects_atandtopup_urlfor the affected kind.oxygen senders list --json,oxygen whatsapp accounts --jsonandoxygen mailboxes list --jsonmark each paused account with areservationobject and add areservations_pausedline. - A top-up resumes it. Oxygen retries the reservation as soon as the credits land, so sending resumes within minutes. Without a top-up it retries on its own schedule.
- After 7 days without funds the account disconnects. A LinkedIn account or WhatsApp number is disconnected and its seat released, an X account is disconnected, and a mailbox you connected is set to
disabled. You can reconnect any of them later. A rented phone number is kept but cannot dial, and is released after 30 days; a released number cannot be recovered.
If a renewal payment fails
- Oxygen does not grant the next monthly plan allowance.
- Stripe retries payment for no longer than seven days (up to seven attempts in that recovery window).
- During that recovery window, the workspace can keep using its existing balance. The seven days count from the first failed payment, on a yearly plan too, never from the start of the paid year.
oxygen billing balance --jsonreports the end asentitlement.grace_ends_at. - At the seven-day boundary, execution stops everywhere: web mutations, CLI/MCP actions, Copilot, Agents, workflows, schedules, feeds, sequences, publishing, and background worker jobs. Remaining plan and purchased credits are frozen rather than deleted.
- Billing recovery, support, and read/export access remain available. Successful payment restores execution and queued work can resume.
When signup grants are enabled, the grant is issued once to an eligible billing owner. Cancelling or downgrading never mints another one, and a returning customer can start a paid subscription immediately.
Cancelling your plan
To see whether and when the card is next charged, run oxygen billing balance (or the oxygen_billing_balance tool) and read next_renewal. will_charge says whether your workspace's own plan is going to charge its card; when it is, charge_at is the date (the trial end while trialing, otherwise the period end) and the plan's monthly list price is the amount before any promotion code or tax — the exact figure is on the invoice on your billing page. cancellation_scheduled says whether a cancellation is already set, and stop_command names the command that changes it, or is empty when nothing in this workspace can stop the charge (a staff-invoiced plan, or a workspace billed through another organization).
Cancel any time, self-serve, from any of these surfaces:
- Web: Settings → Billing → Manage subscription in Stripe.
- CLI:
oxygen billing cancel— undo withoxygen billing resume. - MCP: the
oxygen_billing_canceltool (action: "cancel"or"resume").
What cancelling means:
- On the free tier: the Free plan itself has no subscription to cancel. Separately funded purchases and add-ons have their own terms and cancellation paths.
- On a paid plan: the plan stays active until the end of the current billing period; the plan makes no further charges, and the cancel reply names any sending seats, managed inboxes or creator sponsorships that keep billing on their own subscriptions. Remaining credits stay usable until then. The card stays on file with Stripe; once the plan has ended, the only things that can still charge it are purchases you start yourself (top-ups or legacy sending seats where available) and the separately billed add-ons listed below, which keep renewing until you cancel them too.
- Reversible: until the period actually ends, "Resume subscription" (or
oxygen billing resume) removes the scheduled cancellation and renewal continues normally. - After it takes effect: access follows the workspace's billing entitlement. If execution is suspended, billing recovery and read/export access remain available and your data is retained. A Free plan alone does not establish that credit-funded connections and sending are blocked; check the connection model above.
- Managed external infrastructure is funded separately and keeps its own renewal schedule after plan cancellation. To end all of it while retaining workspace records, preview
oxygen workspace infrastructure-exit --jsonand review every resource before confirming. A domain transfer is a different path:managed-inboxes exitkeeps its vendor mailboxes running while a human arranges the handoff. - Deleting your workspace (Settings → General → delete organization) ends plan billing and starts durable cleanup of its external resources. Already paid terms run to their stated end; the organization record remains until vendor cleanup is confirmed.
The Stripe billing portal remains the source of truth for payment methods, invoices, discounts, plan changes, and cancellation.
Ending external infrastructure
The zero-credit preview is available in Settings → Billing, with oxygen workspace infrastructure-exit --json, or with the oxygen_workspace_infrastructure_exit MCP tool. It lists managed inboxes and domains, warm-up and placement, dedicated egress, connected accounts, rented numbers, and fixed credit commitments. Each entry explains its known term or release timing; a date can be past, estimated, or unavailable. A credit commitment and its linked service can appear separately, so entry counts and monthly amounts are not a bill total. The preview shows the exact workspace name to confirm and changes nothing.
To proceed through the CLI, repeat with --approved --confirm <workspace> --plan-hash <hash> using the values in the fresh preview. The exit stops new renewals, releases provider resources through their paid terms, and reports progress for every resource. Records, tables, conversations, and history remain in the workspace. The OXYGEN plan is separate: oxygen billing cancel stops its own renewal. A staff user can preview a churned workspace with the global --org <slug-or-id> option and gets the same confirmation gate.
Dedicated sending IP billing
A dedicated sending IP costs 2,500 credits per 30-day period ($25 at face value). oxygen egress dedicated request is a free preview; adding --approved provisions one minimal Fly send-drain app and one static egress IP for the workspace, then debits the first period immediately. Renewal is 30 days after purchase and every 30 days thereafter—not on the first day of the calendar month.
The routing scope is the whole workspace: every current and future send, reply read and token refresh for its mailboxes uses the dedicated Fly app automatically. Google and Microsoft therefore see one address for the workspace, and your IT admin can allowlist it in Microsoft Conditional Access or Google context-aware access. It is an account-safety and tenant-isolation feature, not an inbox-placement or deliverability lever. Recipients of Gmail API and Microsoft Graph sends see Google or Microsoft relay addresses in their headers, not the dedicated IP. A Microsoft mailbox on the SMTP transport is the exception on the shared IP as well: Exchange Online may record the submitting IP in the message headers.
If the workspace does not have enough credits at renewal, the add-on enters a seven-day grace period and keeps sending while Oxygen retries. If it is still unpaid after seven days, Oxygen retires the dedicated IP and returns workspace sending to the shared Fly worker. Top up with oxygen billing topup during the grace period to keep the dedicated IP.
Cancellation is approval-gated. Preview it with oxygen egress dedicated cancel, then execute it with oxygen egress dedicated cancel --approve. Cancellation takes effect at the end of the 30-day period already paid for: there is no refund or early cutoff, the IP keeps sending until that date, and no further renewal is charged.
Related
- Spend caps — per-run limit.
- Approvals — gate before credits are spent.
- Integrations — BYOK setup.
- Triggers — cron cadence and scheduled-run sizing.
- Pricing reference — every billable unit, including legacy sending seats.
- Billing ownership — one plan covering many client workspaces.