# Billing

<!-- BEGIN GENERATED: guide-map -->
## Guide map

Read only the section needed for the next decision. Line ranges are exact
for this generated runtime target.

| Section | What it covers | Lines |
| --- | --- | --- |
| [Purpose](#purpose) | Scope, ownership, and the central operating question. | 30-38 |
| [Primary SDK Paths](#primary-sdk-paths) | Operating guidance and contracts for this section. | 39-51 |
| [Supporting References](#supporting-references) | Capability, provider, policy, and runtime guides for this outcome. | 52-59 |
| [Use This When](#use-this-when) | Tasks and conditions that belong in this guide. | 60-67 |
| [Do Not Use This For](#do-not-use-this-for) | Boundaries and the correct routes for excluded work. | 68-79 |
| [Choose A Path](#choose-a-path) | Decision hierarchy for selecting the right capability or provider. | 80-88 |
| [Mental Model](#mental-model) | Concepts and state boundaries needed for correct operation. | 89-103 |
| [Preflight](#preflight) | State, authority, inputs, and readiness to verify before execution. | 104-113 |
| [Risk And Side Effects](#risk-and-side-effects) | Effects, approvals, cost, privacy, and retry boundaries. | 114-122 |
| [Canonical Operating Pattern](#canonical-operating-pattern) | The normal end-to-end execution sequence. | 123-136 |
| [Credits And Usage](#credits-and-usage) | Workspace billing uses a unified credit meter: | 137-170 |
| [Core SDK Surfaces](#core-sdk-surfaces) | Exact source-backed callable contracts owned by this guide. | 171-186 |
| [Data Contracts](#data-contracts) | Required identities, fields, evidence, handles, and durable shapes. | 187-211 |
| [Examples](#examples) | Representative usage patterns and code. | 212-238 |
| [Verification](#verification) | Evidence required before reporting success. | 239-246 |
| [Troubleshooting](#troubleshooting) | Failure diagnosis and corrective routes. | 247-254 |
| [Related References](#related-references) | Adjacent boundaries and when to cross them. | 255-264 |
<!-- END GENERATED: guide-map -->

## Purpose

Use this reference for workspace billing, credit reporting, Stripe checkout
setup, and billing reconciliation.

This reference owns the authoritative billing view and exact `vf.billing.*`
contracts. `mailboxes.md` owns sending domains, mailbox orders, sender
readiness, and connected accounts. `safety.md` owns approval classes.

## Primary SDK Paths

<!-- BEGIN GENERATED: primary-sdk-paths -->
| Primary function | Choose it when | Required inputs | Returns | Exact contract |
| --- | --- | --- | --- | --- |
| `vf.billing.status` | Use for the current workspace subscription, entitlement, payment, and high-level billing state. | None | `billing_status` | [`billing.md`](billing.md) · installed SDK: `verbiflow/billing.py:66-80` |
| `vf.billing.plans` | Use to compare currently available plans and their authoritative limits before recommending a change. | None | `billing_plans` | [`billing.md`](billing.md) · installed SDK: `verbiflow/billing.py:82-96` |
| `vf.billing.workspace_credit_summary` | Use for current workspace credit balance, usage, and credit accounting summary. | None | `workspace_credit_summary` | [`billing.md`](billing.md) · installed SDK: `verbiflow/billing.py:98-123` |
| `vf.billing.cost_by_play` | Use when the requested cost is specifically attributable to one Workflow Play. | None | `cost_by_play` | [`billing.md`](billing.md) · installed SDK: `verbiflow/billing.py:278-324` |
| `vf.billing.reconcile` | Use only when authoritative subscription quantities must be re-synchronized after diagnosing a billing-state mismatch. | None | `billing_reconcile_result` | [`billing.md`](billing.md) · installed SDK: `verbiflow/billing.py:208-222` |
| `vf.billing.checkout_url` | Use only after the desired plan or purchase is explicit and the user wants a hosted checkout handoff. | None | `checkout_url` | [`billing.md`](billing.md) · installed SDK: `verbiflow/billing.py:176-206` |
<!-- END GENERATED: primary-sdk-paths -->

## Supporting References

Open only the child that resolves the next material decision.

| Reference | Use it for | Kind |
| --- | --- | --- |
| [`safety.md`](safety.md) | Approval, confirmation, side-effect, purchase, and external-communication boundaries. | policy |

## Use This When

- Reading workspace billing state, subscription state, plan limits, or usage.
- Listing purchasable plans or creating a Stripe checkout URL.
- Reconciling subscription/product quantities after billing changes.
- Reporting authoritative credits for a Workflow Play via
  `vf.billing.cost_by_play(...)`.

## Do Not Use This For

| Task | Use Instead |
| --- | --- |
| Sender identity readiness, connected mailbox accounts, sender matching, account movement, or sandbox email tests. | `senders.md` |
| Sending-domain search, inventory, domain purchase, or mailbox orders. | `mailboxes.md` |
| General approval policy for publish, direct send, purchase, or credit spend. | `safety.md` |
| Sequence source staging, audience repair, imports, publish, activation, transfer, or delete. | `sequences.md` |
| Draft source/filter/copy authoring or copy verification. | `sequence_authoring.md` |
| Workflow run/report/sync mechanics or Play-root operation. | `workflow_operations.md`; `workflow_schedules.md` owns sync |
| Acquisition, enrichment, personalization, row shaping, or provider search. | `audience_discovery.md`, `enrichment.md`, `copy.md`, `row_operations.md` |

## Choose A Path

1. For billing questions, inspect status, plans, workspace credit summary, or
   per-Play cost without entering a purchase flow.
2. For a plan change, inspect the live plan catalog and create checkout only
   after the exact tier and effect are approved.
3. For sending-domain, mailbox-order, or sender-readiness work, use
   `mailboxes.md`. Do not split one domain order across Billing and Mailboxes.

## Mental Model

Billing has three separate surfaces:

| Boundary | Meaning | Normal SDK Surface |
| --- | --- | --- |
| Billing status and plans | Workspace subscription, usage, plan catalog, and checkout URL creation. | `vf.billing.status(...)`, `vf.billing.plans(...)`, `vf.billing.checkout_url(...)` |
| Billing reconciliation | Server-side resync of subscription/product quantities after product changes. | `vf.billing.reconcile(...)` |
| Play cost reporting | Authoritative unified credit total for one registered Workflow Play in the current org. | `vf.billing.cost_by_play(...)` |

Credit reporting and purchase flows are not the same thing.
`cost_by_play` reports ledger-backed usage; it does not charge the customer.
Checkout creates a Stripe session and requires explicit approval immediately
before the call.

## Preflight

- Confirm workspace identity with `vf.auth.status()` or
  `vf.auth.ensure_logged_in()` before workspace-specific billing calls.
- For `cost_by_play`, preserve the exact `play_id`. If omitted, the SDK tries
  the detected Workflow Play root's `VERBIFLOW_PLAY_ID`; fail fast when the
  play identity is ambiguous.
- Before checkout, print the requested plan tier, promo code if any, and
  success/cancel URLs if provided.

## Risk And Side Effects

| Operation | Risk | Required Handling |
| --- | --- | --- |
| `vf.billing.status(...)`, `vf.billing.plans(...)` | Platform reads. | Print workspace, current plan, usage, and relevant ids. |
| `vf.billing.cost_by_play(...)` | Platform read scoped to one registered Workflow Play. | Preserve `play_id`, `scope`, `credits_used`, `credits_consumed`, `credits_reserved`, `by_owner`, and `by_capability`; report partial state if returned. |
| `vf.billing.checkout_url(...)` | Platform write that creates a Stripe Checkout session/URL. | Require explicit approval for plan purchase/upgrade. Preserve checkout URL/session metadata. |
| `vf.billing.reconcile(...)` | Platform write that resyncs subscription/product quantities. | Run only for an explicit reconciliation task; verify `billing.status()` afterwards. |

## Canonical Operating Pattern

1. Confirm workspace identity and the requested billing task.
2. For read-only billing context, call `vf.billing.status()` and print the
   plan/usage fields that answer the user's question.
3. For plan purchase/upgrade, call `vf.billing.plans()` first, then present the
   selected plan tier before creating `vf.billing.checkout_url(...)`.
4. For Workflow Play cost reporting, call `vf.billing.cost_by_play(play_id=...)`
   and report ledger-backed `credits_used`, `credits_consumed`,
   `credits_reserved`, `by_owner`, and `by_capability`. Do not use local
   snapshot usage as the authoritative total.
5. After checkout or reconciliation, verify with `vf.billing.status()` and
   preserve returned ids for follow-up.

## Credits And Usage

Workspace billing uses a unified credit meter:

- source consumed;
- enrichment consumed;
- enrichment reserved;
- Growth observed.

Use `vf.billing.workspace_credit_summary(...)` for the canonical workspace-wide
superset meter. Use `source_execution_credits(...)` or
`enrichment_credits(...)` only when a narrower source/enrichment panel is the
actual question.

`vf.billing.cost_by_play(...)` is the authoritative per-Play view when the play
id has been propagated through the relevant ledgers. Workflow snapshots may
include recorded operation usage, but snapshots are evidence, not the billing
source of truth. When reporting spend, say whether the number came from the
billing ledger or from a local snapshot/report.

### Always Report Credits AND USD

Both `cost_by_play` and `recent_usage` responses carry `credits_used`,
`usd_cost`, and `usd_per_credit` on the top-level total AND on every per-
capability and per-owner row. `usd_cost = credits_used * usd_per_credit`
(currently `$0.001` / credit). **When you report spend to the user, print
BOTH** — credits alone is jargon. Example:

> "Play `wfp_…_73e4` used **3,210 credits ($3.21)**. Top drivers: source
> consumed 2,400 credits ($2.40), Growth observed 810 credits ($0.81)."

Read `usd_per_credit` from the response rather than hard-coding the multiplier
so reports stay correct if pricing changes.

## Core SDK Surfaces

<!-- BEGIN GENERATED: core-sdk-surfaces -->
| Function | Use When | Inputs | Output And Handles To Preserve | Side Effect | Source |
| --- | --- | --- | --- | --- | --- |
| `vf.billing.checkout_url` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | <strong>Required</strong>: none<br><strong>Optional</strong>: `cancel_url` (str \| None; optional; default `None`): URL Stripe should redirect to when checkout is cancelled.; `plan_tier` (str \| None; optional; default `None`): Billing plan tier to quote or purchase.; `promo_code` (str \| None; optional; default `None`): Optional billing promotion code.; `success_url` (str \| None; optional; default `None`): URL Stripe should redirect to after successful checkout. | `dict` with Stripe checkout URL and billing session metadata.<br><strong>Common next calls</strong>: `vf.billing.status`, `vf.billing.reconcile` | platform_write | installed SDK: `verbiflow/billing.py:176-206` |
| `vf.billing.cost_by_play` | Use when you need the authoritative credit total for one Workflow Play. It is not a generic billing-status call. | <strong>Required</strong>: none<br><strong>Optional</strong>: `play_id` (str \| None; optional; default `None`): Play UUID. Pass null or omit to use the VERBIFLOW_PLAY_ID from the detected Workflow Play root's .env. | `dict` with `scope="unified_credit_meter"`, total `credits_used`, `credits_consumed`, `credits_reserved`, `by_owner`, and `by_capability`; owners include source consumed, enrichment consumed, enrichment reserved, and Growth observed. Preserve `play_id` and owner breakdown when reporting costs.<br><strong>Common next calls</strong>: `vf.billing.status`, `vf.billing.recent_usage` | read | installed SDK: `verbiflow/billing.py:278-324` |
| `vf.billing.enrichment_credits` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | <strong>Required</strong>: none<br><strong>Optional</strong>: `org_id` (str \| None; optional; default `None`): Optional workspace override for the enrichment credit read. | `workspace_enrichment_credits` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.billing.workspace_credit_summary` | read | installed SDK: `verbiflow/billing.py:152-174` |
| `vf.billing.plans` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | No inputs. | `dict` with purchasable plan tiers and current workspace billing context.<br><strong>Common next calls</strong>: `vf.billing.checkout_url` | read | installed SDK: `verbiflow/billing.py:82-96` |
| `vf.billing.recent_usage` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | <strong>Required</strong>: none<br><strong>Optional</strong>: `actor_only` (bool; optional; default `True`): Default true: scope to your own actor id (you see only your own spend in shared workspaces). Set false for workspace-wide totals.; `minutes` (int; optional; default `60`): Lookback window in minutes. Default 60, max 1440 (24h). | `recent_usage` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.billing.status`, `vf.billing.cost_by_play` | read | installed SDK: `verbiflow/billing.py:224-276` |
| `vf.billing.reconcile` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | No inputs. | `dict` with subscription/product reconciliation status.<br><strong>Common next calls</strong>: `vf.billing.status` | platform_write | installed SDK: `verbiflow/billing.py:208-222` |
| `vf.billing.source_execution_credits` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | <strong>Required</strong>: none<br><strong>Optional</strong>: `org_id` (str \| None; optional; default `None`): Optional workspace override for the source execution credit read. | `workspace_source_execution_credits` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.billing.workspace_credit_summary` | read | installed SDK: `verbiflow/billing.py:125-150` |
| `vf.billing.status` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | No inputs. | `dict` with plan, usage, subscription, and billing capability state.<br><strong>Common next calls</strong>: `vf.billing.checkout_url`, `vf.billing.reconcile` | read | installed SDK: `verbiflow/billing.py:66-80` |
| `vf.billing.workspace_credit_summary` | Use for billing, plan, checkout, purchased-domain, and mailbox-domain operations. | <strong>Required</strong>: none<br><strong>Optional</strong>: `org_id` (str \| None; optional; default `None`): Optional workspace override for the credit summary read. | `workspace_credit_summary` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.billing.source_execution_credits`, `vf.billing.enrichment_credits` | read | installed SDK: `verbiflow/billing.py:98-123` |
<!-- END GENERATED: core-sdk-surfaces -->

## Data Contracts

### Cost By Play

Preserve these fields from `vf.billing.cost_by_play(...)`:

- `play_id`;
- `scope`, normally `unified_credit_meter`;
- `credits_used`;
- `credits_consumed`;
- `credits_reserved`;
- `total_cost`;
- `total_units`;
- `event_count`;
- `usd_cost` (= `credits_used * usd_per_credit`);
- `usd_per_credit` (currently `0.001`; read from the response, do NOT hard-code);
- `by_owner` — each row carries `owner`, `credits_used`, `event_count`, `usd_cost`;
- `by_capability` — each row carries `capability_id`, `units`, `cost`, `event_count`, `owner`, `usd_cost`;
- `is_partial`;
- `partial_reason`.

`by_owner` distinguishes source consumption, enrichment consumption,
enrichment reservations, and Growth observed usage. Do not collapse those
owners when debugging double-counting or missing-attribution questions.

## Examples

Read workspace billing context:

```python
import verbiflow as vf

vf.auth.ensure_logged_in()
status = vf.billing.status()
print(status)
```

Report authoritative Workflow Play cost:

```python
import verbiflow as vf

vf.auth.ensure_logged_in()
cost = vf.billing.cost_by_play(play_id="wfp_...")
print(
    f"{cost['credits_used']:.0f} credits "
    f"(${cost['usd_cost']:.2f} @ ${cost['usd_per_credit']}/credit)"
)
for row in cost["by_owner"]:
    print(f"  {row['owner']}: {row['credits_used']:.0f} credits (${row['usd_cost']:.2f})")
```

## Verification

- `vf.billing.status()` answers the plan/usage/subscription question with the
  active workspace clearly identified.
- `vf.billing.cost_by_play(...)` returns the requested `play_id`, unified scope,
  owner breakdown, capability breakdown, and partial-state flags.
- After checkout or reconciliation, re-read `vf.billing.status()`.

## Troubleshooting

| Symptom | First Check | Fix |
| --- | --- | --- |
| `cost_by_play` raises no play id | Confirm the workflow root has a registered `VERBIFLOW_PLAY_ID` or pass `play_id` explicitly. | Register the Workflow Play or provide the exact play id. |
| `cost_by_play` returns 404 | The play id is not registered in the current workspace/org. | Verify workspace focus and play id; do not query another org's play. |
| Credit totals look different from a Play snapshot | Check whether the number came from billing ledger or local snapshot usage. | Use `cost_by_play` for authoritative billing and keep snapshot usage as evidence only. |

## Related References

| If you are doing this | Read next |
| --- | --- |
| Sender readiness, connected mailbox accounts, sender matching, or sandbox tests. | `senders.md` |
| Sending-domain search, inventory, domain purchase, or mailbox orders. | `mailboxes.md` |
| Approval classes for purchases, direct sends, publish, or large credit spend. | `safety.md` |
| Sequence staging, publish, imports, audience repair, or activation. | `sequences.md` |
| Workflow Play operation, Play sync, or run/report state. | `workflow_operations.md`; `workflow_schedules.md` owns sync |
| Personalization, enrichment, or audience discovery spend that may affect credits. | `enrichment.md`, `audience_discovery.md`, `copy.md` |
