OXYGENOxygen/ Docs
Safety & cost

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

WorkWhat it draws
Managed enrichment or domain provider call (Oxygen's key)Credits at the catalog price
AI column run on Oxygen's keysCredits by model tier, plus web-search cost when enabled
The same provider call on your own key (BYOK)Applicable 0.05-credit OXYGEN platform fee per successful call; vendor charges follow your provider's terms
An AI call on your own model key0 inference credits; managed grounding and workflow steps retain separate charges
Live workflow steps, tool calls, retries0.05 credits per step
Rows written inside a workflow run0 credits
Sequence sends through your connected email accounts0 credits
Workspace reads, schema changes, dry_run / smoke_test0 credits; a successful live provider read on your own key pays the applicable 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 --json

A 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, bonus and partner_bonus record credit grants. admin holds grants, re-denominations and other balance adjustments, not spending. A negative available_delta reduces the balance. Use billing usage --category admin with the audit's dates and filters to inspect those events.

Historical ledger events keep the credit units used when they occurred. A reporting window spanning a re-denomination can therefore mix old and current units: its raw credit totals and shares are not a comparison in today's units or USD. Narrow the dates to one denomination for that comparison; do not convert the entire window at today's credit rate. The re-denomination is an admin adjustment, not spending. totals.grant_credits is gross credits from grant entries; it excludes refunds and balance adjustments.

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 can differ from the settled figure because of holds at the window edges and adjustments to reserved credits, including re-denominations; 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.

PlanPrice / moCredits / moPrice / 100 creditsBYOK
Oxygen$494,900$1.00Yes before repricing; existing connected keys only afterward
Oxygen$999,900$1.00Yes
Oxygen$19919,900$1.00Yes
Oxygen$49952,395 (+5% volume bonus)$0.95Yes
Oxygen$999109,890 (+10% volume bonus)$0.91Yes
Oxygen$1,999229,885 (+15% volume bonus)$0.87Yes

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 that checkout keeps its quoted credit rate 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.

With no amount this is a read-only quote (mode: quote), creating no Stripe resources. Supplying --credits or a pack (MCP credits or pack) creates a checkout link (mode: checkout) and may create the billing customer or top-up Product; it does not charge until you pay. tax_basis: unknown means this response has not established whether tax is included or added: review tax and the final total in Stripe Checkout before payment. The quoted credit rate stays fixed for that checkout; tax and any promotion can affect the money paid. Credits post once Stripe confirms payment, including delayed payment methods. Older CLI fields named usd_per_1k_credits and subscription_usd_per_1k_credits actually hold prices per 100 credits; use the explicit per-100 fields. The quote's default_credits is the web form's initial custom amount; it is neither a purchase nor the minimum.

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.

Any unrestricted workspace member can change an existing plan, turn off renewal, resume renewal or open the Billing Portal. Starting a first subscription stays admin/owner-only; a restricted client cannot perform billing mutations.

On an ordinary month-to-month plan, upgrades apply immediately with a prorated charge; downgrades start at the next paid-period boundary. Inspect the charge and effective date before confirming.

The plan's displayed rollover_cap includes its volume bonus. Unused paid-plan credits currently accumulate without expiry, and the displayed cap is not enforced for paid subscription grants. Purchased credits never expire.

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: open Upgrade and choose Yearly · paid monthly, or run oxygen billing change --to oxygen_99 --term year --interval month (MCP oxygen_billing_change_plan, term: year, interval: month). Review and accept the twelve-month terms in Checkout. The offer is available only when annual_monthly_billing_available is true in oxygen billing balance --json.
  • Check your commitment: billing balance reports subscription.commitment, including its end date and renewal state. Payments still occur every month.

Signed plan-change confirmation previews expire after 15 minutes; create a fresh preview if one expires.

Legacy prepaid yearly plans: an upgrade that keeps prepaid yearly billing applies immediately with proration. A downgrade or a switch to monthly starts at the paid year's end. Switching to a new yearly commitment paid monthly also starts at that boundary. Turning off renewal preserves access and monthly credit slices until the paid year ends; it does not refund the prepaid year. Review the preview's amount and effective date before confirming.

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:

PlanPlan credits a monthPartner bonusIn all
$999,9001,48511,385
$19919,9002,98522,885
$49952,3957,48559,880
$999109,89014,985124,875
$1,999229,88529,985259,870

The basis is the plan's normal monthly face value, before annual payment discounts or other coupons, rather than the amount charged to the card or the plan's volume-bonus credits. For example, the $1,999 plan's monthly partner bonus is up to 29,985 credits on monthly and annual billing. Refunds or plan switches within a paid annual period can reduce the amount.

The bonus accompanies eligible paid monthly plan grants as its own partner_bonus ledger line. This includes yearly commitments paid monthly and legacy prepaid yearly plans, whose credits arrive in monthly slices of the confirmed paid year. It stays outside plan.monthly_credits and limits derived from that allowance. Publishing during a paid month can qualify a missing current-month bonus on the next grant pass; publication promises no immediate credit arrival. The first processing time has no promised deadline, including at the next renewal. first_grant_at remains null when grant history is not read: use first_grant_timing.reason and .message for the explanation. next_scheduled_monthly_grant_at is a separate scheduled date, not proof of the first bonus processing time. A refund reverses the bonus in the same proportion as the plan credits.

The bonus follows the paying organization's eligible plan and published listing. A client workspace linked with oxygen orgs billing-link draws on that pool and earns no separate bonus by publishing its own listing. The $49 plan, grandfathered plans, custom contracts, and invited or delisted listings earn none.

oxygen billing summary --json (MCP oxygen_billing_summary) reports partner_bonus.monthly_credits, eligibility, conditions and first-grant timing without granting or expiring credits. It uses the existing plan, listing and captured discount evidence; a projection does not prove a historical grant or replace the fresh Stripe check before a future bonus. A missing projection is reported as unavailable, not ineligible. oxygen billing balance --json reports the same projection, but can apply due plan grants or credit expiry. oxygen billing usage --category partner_bonus --json lists actual bonus ledger lines; credit-ledger and BYOK usage views can also apply due plan grants or credit expiry.

partner_bonus.reasonMeaning
published_partnerPublished listing and eligible plan; grants still require a confirmed paid period.
not_a_partnerThe paying organization has no directory listing.
listing_not_publishedIts listing is invited or delisted.
plan_not_eligibleIts plan earns no automatic bonus.
custom_planAn off-Stripe contract or custom allowance earns no automatic bonus.
partner_coupon_activeThe prospective exclusion policy applies and an approved PARTNERS2026 discount is active.
partner_coupon_authority_unknownThat policy applies, but discount eligibility could not be established; only the prospective bonus is withheld.

First-grant timing can instead report grant_history_not_read, grant_pass_time_unknown or paid_plan_period_required; otherwise its reason follows the eligibility reason above. The timing message explains the missing evidence or paid-period condition. Shared billing also reports shared_workspace_cannot_earn_bonus under prospective_plan_eligibility.reason.

Existing PARTNERS2026 discounts end on cancellation or when a plan change takes effect. The separate prospective bonus-exclusion policy applies only after its activation is approved and configured. When it applies to this account, partner_bonus.conditions.active_partners2026_coupon_excludes_bonus is true and coupon_authority.state reports active_partner_coupon, no_active_partner_coupon or unknown. These fields do not appear when the policy is inactive or the plan is ineligible; there is no separate customer read for the global activation setting. Captured coupon evidence is dated, and a prospective grant requires a fresh Stripe check. Base plan credits and historical grants remain unchanged. See Agency directory for the application and publication stages.

After the discount ends, a fresh check establishing no_active_partner_coupon can allow a missing current paid month's bonus on a later grant pass, provided the paying organization's listing and plan remain eligible. It does not recover excluded bonuses for earlier closed months or promise a processing deadline. This applies to monthly payments and the current monthly slice of a legacy prepaid yearly plan; previously granted credits keep their normal terms.

Credit lifecycle

StateTrigger
GrantedPlan refill or top-up
ReservedA run starts; estimated cost held against balance
CapturedRun item succeeds with cost > 0
ReleasedUnused reservation returned, including a pre-billing failure or the unused part after partial capture

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.

reasonMeaning
openThe call is still running or its charge is not final yet.
result_pending_settlementA result was delivered and its charge is being finalized.
outcome_unknownA LinkedIn lookup did not confirm a result; the credits stay held, not charged.
unmarkedA LinkedIn data request's hold carries no outcome marker, so OXYGEN cannot tell an unknown result from a delivered one that was never charged.
unsettledAny 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

ModeWho paysWhat it covers
ManagedOxygen creditsOxygen holds the provider API key. Default for enrichment providers.
Provider API key (BYOK)You pay the provider directlyYour own provider API key; plan eligibility applies.
OAuth / hosted account sign-inIntegration access; account reservations or legacy seats can still applyYour own CRM or connected sending account; separate from provider API-key eligibility.

Calls on your own provider API key may incur vendor charges under your provider's terms, and OXYGEN charges the applicable 0.05-credit platform fee per successful 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 applicable fee on each successful call, including a successful response with nothing found. enrich-column preview and columns run previews include it for every own-key lane a row can reach, and the run reserves it (waterfalls).

A successful call returns from the provider without an execution error; it can contain no usable result. A provider execution error, including one returned after dispatch, is not a successful call: OXYGEN does not capture this fee and releases its uncaptured fee hold. Once a successful call's fee is recorded, a later local failure does not undo it. Recording the fee and settling it from your balance every two hours are separate steps. A timeout or interrupted response can leave the upstream outcome uncertain: inspect recorded billing and your provider's history before retrying. An absent OXYGEN fee does not prove that your provider charged nothing. Failed or uncertain asynchronous recovery allocations stay consumed within the approved total ceiling (follower recovery).

max_credits bounds OXYGEN credits, including that platform fee; it does not cap your vendor account. A provider's free-on-miss rule does not waive the OXYGEN fee. A dispatched own-key miss has retry_safe: false; own_key_spend identifies the affected lanes. Read own-key fees and retries before execution. Your own AI model credential follows a separate rule: inference has no OXYGEN platform fee (AI pricing).

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 --json

Usage 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 --json

The 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 --json

When 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 --json

Steps 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

ActionCosts credits
tables query, rows history, cells inspectNo
tools search, tools get, integrations listNo
dry_run or smoke_test of any tool/column/workflowNo
context profile get/update, assets *No
columns add, tables rename, schema changesNo
skills list/doctor/installNo
live provider call on your own key (BYOK)Yes — the applicable 0.05-credit platform fee per successful call
live AI call on your own model keyNo inference fee — logged as a zero-credit byok_usage entry; managed grounding and workflow steps retain separate charges
Live workflow steps, retriesYes — 0.05 credits per step
Rows written inside a workflow runNo
Sequence sends through your connected email accountsNo
live AI/tool/enrichment column run on managed keysYes (per call)

Failure billing

This table describes OXYGEN-managed credit reservations in a provider cascade. It does not describe charges to your own vendor account. Own-key platform fees follow the successful-call rule above; a dispatched call or an uncertain outcome is never evidence that a retry is free.

Failure pointCredit treatment
Pre-billing (auth, validation, 429 before charge)Released
Post-billing (provider charged then returned error)Captured
Partial provider cascadeCaptured 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 pay for connected accounts, sending, supported publishing and managed email purchases. Adding a sending account (a LinkedIn account, a mailbox, a WhatsApp number, an X account or a phone number) needs a paid plan; on eligible Free workspaces credits fund the rest. 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 on Upgrade, reached from Settings → Billing → See plans or Upgrade in the sidebar. A plan-gated action opens that page. 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 billing owner that has never had a plan can take its first month of any monthly size from $99 up for half its price, rounded down to the dollar: $49 / $99 / $249 / $499 / $999 for the $99 / $199 / $499 / $999 / $1,999 sizes. Subscribe within 24 hours of first seeing the offer; a browser's first sight carries into signup, and creating Checkout starts the window if nothing has started it yet. Each later month returns to the size's regular price, and the first paid month grants its full monthly credits. The $49 size and yearly commitments do not get the offer. Checkout applies it automatically and 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, before tax. Inspect eligible sizes with billing balance before creating a payment flow.

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, credits fund connections, and adding a sending account needs the owner's paid plan. 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. Every sending account also needs a plan: on Free, connecting a LinkedIn account, WhatsApp number or X account, adding a mailbox (imported or bought) or buying a phone number fails with upgrade_required (exit code 7) before any balance check, however many credits you hold, and upgrade_url opens the plan page. Price previews and number searches stay open. Reconnecting an account that is still connected, for example after its login expired, stays open, and so does re-authorizing a mailbox you already hold. Once a LinkedIn or WhatsApp connection has been released, for example after you disconnect it, connecting it again counts as a new account. The balance must cover the account's first month: a 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 send sequences from accounts it already holds, use supported publishing and buy managed email infrastructure other than inboxes when its balance covers the reservation or purchase; adding a sending account needs a paid plan. 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 connected accounts are paid by credit reservations, 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 --json shows paused_quantity, past_due_since, disconnects_at and topup_url for the affected kind. oxygen senders list --json, oxygen whatsapp accounts --json and oxygen mailboxes list --json mark each paused account with a reservation object and add a reservations_paused line.
  • 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 --json reports the end as entitlement.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

Use oxygen billing summary --json to inspect your plan without changing it. oxygen billing balance (or the oxygen_billing_balance tool) reports next_renewal, but can also apply due credit grants or expire credits. 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 → Cancel plan, with a freeform reason field.
  • CLI: oxygen billing cancel --comment "Why you are leaving" — undo with oxygen billing resume.
  • MCP: oxygen_billing_cancel with action: "cancel" and comment; action: "resume" restores renewal.

Your written reason is recorded with the subscription in Stripe. Oxygen staff can review paid-account cancellations and their comments in the admin dashboard's Cancellations section.

Stay offer. When available, an eligible monthly subscriber can stay with 30% off the next monthly invoice, then the normal price. Preview it without changing your plan with oxygen billing retention-offer --json or oxygen_billing_cancel with action: "offer". Accept the returned offer_id with oxygen billing retain --offer <offer_id> or MCP action: "retain", offer_id: "…". No charge today. One offer per billing owner, with no existing discount; annual commitments and trials are excluded. Cancellation remains available when no offer is shown.

Previewing changes nothing and does not use your one-time offer; accepting does. Quotes have no fixed expiry timer. Acceptance rechecks eligibility, the quoted price and the next renewal date. If your plan or renewal changes, request a fresh preview before accepting.

To share feedback while keeping your plan, use oxygen feedback --message "Your feedback" or MCP oxygen_feedback, after confirming the message you want to send. This opens a support conversation rather than recording a cancellation reason.

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: a month-to-month plan stays active until the end of its current billing period and makes no further plan charges. On a yearly commitment paid monthly, cancellation turns off annual renewal; monthly payments and credit grants continue through the commitment end. A legacy prepaid yearly plan retains its paid period and monthly credit slices. In each case, 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 sending is blocked, although adding a sending account needs a paid plan; 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 --json and review every resource before confirming. A domain transfer is a different path: managed-inboxes exit keeps 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.

On this page