API inventory

Everything Aurora Meter Pro offers a host application, with a stability class per entry. It is the authority for what the support policy covers: see Support policy.

If something is not on this page, it is not part of the supported surface, even when the module or function happens to be public in the compiled code.

test/aurora_meter/pro/api_inventory_test.exs checks this page against the code on every mix test. Every Module.function/arity below must exist, no internal module may be listed, every telemetry event and PubSub tag must appear verbatim in lib/, and the core version requirement in section 12 must match mix.exs.

Aurora Meter Pro is a commercial package. The free core has an inventory of its own, and this page never restates it: core entries are core’s promise, not Pro’s.

How to read this page

Class Meaning Change rule
stable Part of the supported surface. Covered by SemVer. No breaking change before 2.0. Additive change is allowed in a minor release.
optional-dep Stable, but it only exists when an optional dependency is installed. Same promise as stable. The dependency’s absence is documented and is never a compile error.
deprecated Still works, warns, and is removed in 2.0. Never removed during 1.x.
internal Not part of the supported surface. May change in any release, including a patch. Callers get no warning.

Since is the package version that introduced the entry. Pro 0.4.0 was never published, so everything written for it carries 1.0.0, the release that shipped it.

Test helpers (AuroraMeter.Pro.Stripe.Fake, AuroraMeter.Pro.Credits.StripeClient.Fake) are stable, but they are for host test suites. Nothing in production should depend on them, and the support policy governs them under its own heading rather than by SemVer on every helper name.

1. Facade functions

1.1 AuroraMeter.Pro

Entry Signature and return Class Since Notes
AuroraMeter.Pro.version/0 () :: String.t() stable 0.1.0 The compiled package version.
AuroraMeter.Pro.validate!/0 () :: keyword() stable 1.0.0 Validates the whole :aurora_meter_pro environment against the schema, resolves every {:system, "VAR"} once, and stores the result for the accessors. Raises AuroraMeter.Pro.ConfigError. Safe to call from a release health check.
AuroraMeter.Pro.start_link/1 (keyword()) :: :ignore stable 1.0.0 The boot checks: validate!/0, the source cutover refusal, and the Stripe account assertion. Returns :ignore and starts no process, so a supervisor containing it shows nothing under it. Options :validate, :cutover_check, :account_check.
AuroraMeter.Pro.child_spec/1 (keyword()) :: Supervisor.child_spec() stable 1.0.0 restart: :transient, which with :ignore is a clean start a supervisor never restarts. Add AuroraMeter.Pro to your tree after your Repo.
AuroraMeter.Pro.account_confirmed?/0 () :: boolean() stable 1.0.0 Whether the startup assertion confirmed :stripe_account_id against Stripe on this node. false when the check was skipped, has not run, or could not reach Stripe; a live-mode outbox enqueue then quarantines with :account_unconfirmed.

1.2 Prepaid credit top-ups

Pro sells credit; the core ledger holds it. Every grant goes through AuroraMeter.Credits.grant/3 keyed on the Stripe PaymentIntent id, so two deliveries of one payment fund the account exactly once.

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Credits.checkout/3 (tenant, pos_integer(), keyword()) :: {:ok, String.t()} | {:error, :invalid_amount | term()} stable 0.3.0 amount_cents, not micro-dollars: this is a Stripe boundary. Arity 2 exists through defaults.
AuroraMeter.Pro.Credits.checkout_params/3 (tenant, pos_integer(), keyword()) :: {:ok, map()} | {:error, :invalid_amount | term()} stable 0.3.0 Pure. Build the params without calling Stripe, for a host that posts them itself.
AuroraMeter.Pro.Credits.portal_url/2 (tenant, keyword()) :: {:ok, String.t()} | {:error, :no_customer | term()} stable 0.3.0 Billing Portal for the credit customer. Option :configuration.
AuroraMeter.Pro.Credits.account/1 (tenant) :: AuroraMeter.Pro.Schema.CreditAccount.t() | nil stable 0.3.0
AuroraMeter.Pro.Credits.customer_id/1 (tenant) :: String.t() | nil stable 0.3.0
AuroraMeter.Pro.Credits.close_account/1 (tenant) :: :ok stable 0.3.0
AuroraMeter.Pro.Credits.presets_cents/0 () :: [pos_integer()] stable 0.3.0 The configured top-up amounts, for a pricing page.
AuroraMeter.Pro.Credits.update_auto_top_up/3 (tenant, map(), keyword()) :: {:ok, Schema.CreditAccount.t()} | {:error, Ecto.Changeset.t() | :no_payment_method} stable 0.3.0 Stores a threshold and an amount per tenant and mirrors the threshold to the core’s per-tenant low-balance threshold. Arity 2 exists through defaults.
AuroraMeter.Pro.Credits.disable_auto_top_up/2 (tenant, term()) :: {:ok, Schema.CreditAccount.t()} | {:error, :not_found | Ecto.Changeset.t()} stable 0.3.0 The second argument is the reason, and it is kept.
AuroraMeter.Pro.Credits.re_enable_auto_top_up/1 (tenant) :: {:ok, Schema.CreditAccount.t()} | {:error, Ecto.Changeset.t() | :no_payment_method} stable 0.3.0 Clears the disable reason and the failure count.
AuroraMeter.Pro.Credits.on_low_balance/1 (map()) :: :ok | {:error, term()} stable 0.3.0 The core hook: config :aurora_meter, credits_low_balance_handler: &AuroraMeter.Pro.Credits.on_low_balance/1.
AuroraMeter.Pro.Credits.credit_cents/2 (non_neg_integer(), map() | nil) :: non_neg_integer() stable 1.1.0 Pure. The credit a payment buys: its metadata’s credit_cents when tax went on top (credits_tax: :exclusive), else the whole payment, and never more than was paid.
AuroraMeter.Pro.Credits.record_payment/4 (tenant, String.t(), pos_integer(), map()) :: {:ok, term()} | {:error, term()} stable 0.3.0 Arity 3 exists through an empty metadata map.
AuroraMeter.Pro.Credits.record_failure/3 (tenant, term(), String.t() | nil) :: {:ok, Schema.CreditAccount.t()} | {:error, :not_found | Ecto.Changeset.t()} stable 0.3.0 Arity 2 exists through a nil reference.
AuroraMeter.Pro.Credits.handle_event/1 (map()) :: result() stable 0.3.0 The credit half of the webhook. AuroraMeter.Pro.Webhook calls it; a host that routes Stripe events itself may call it directly. Since 1.0.0 it can answer {:refused, reason}: nothing was applied and a redelivery would be refused the same way, so a host routing events itself should answer 200 to that and 500 only to {:error, _}.
AuroraMeter.Pro.Credits.notify/1 (term()) :: :ok stable 0.3.0 Sends one event to the configured :credits_handler.
AuroraMeter.Pro.Credits.with_lock/2 (String.t(), (-> result)) :: result stable 0.3.0 The advisory lock the webhook handlers already take, so a host can serialise its own work on the same tenant key.
AuroraMeter.Pro.Credits.AutoTopUpWorker.attempt/2 (String.t(), String.t() | nil) :: {:ok, AuroraMeter.Schema.CreditTransaction.t()} | {:skip, skip()} | {:error, term()} stable 0.3.0 Directly callable as well as an Oban worker. Arity 1 exists through a nil idempotency key.
AuroraMeter.Pro.Credits.AutoTopUpSweeper.sweep/0 () :: non_neg_integer() stable 0.3.0 The level-triggered pass, for accounts that are already below the threshold.
AuroraMeter.Pro.Credits.Expirer.run/0 () :: {:ok, non_neg_integer()} deprecated 0.3.0 An Oban wrapper around AuroraMeter.Credits.expire_due/1, from when the core shipped no scheduler. The replacement has landed: AuroraMeter.Oban.CreditExpiry, in the free core. This is now a shim that delegates to it, carries @deprecated, and is removed in 2.0. Registering both in one crontab is refused by AuroraMeter.Oban.validate!/1.
AuroraMeter.Pro.Credits.Product.ensure/0 () :: {:ok, String.t()} | {:error, term()} stable 0.3.0 Finds or creates the Stripe product credit is sold against, and caches the id.
AuroraMeter.Pro.Credits.Product.reset_cache/0 () :: :ok stable 0.3.0 For tests and for a mode switch.

1.3 Subscriptions, checkout and the webhook

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Stripe.checkout_params/2 (tenant, keyword()) :: {:ok, map()} | {:error, :not_configured} stable 0.2.0 Pure. Attaches every flat price (quantity 1) and every metered price (no quantity) of the plan.
AuroraMeter.Pro.Stripe.portal_params/2 (tenant, keyword()) :: {:ok, map()} | {:error, :no_customer} stable 0.2.0 Pure.
AuroraMeter.Pro.Stripe.meter_event_params/1 (map()) :: map() stable 0.3.0 Pure. The Billing Meter event body for one usage entry.
AuroraMeter.Pro.Subscriptions.sync/1 (map()) :: {:ok, AuroraMeter.Schema.Subscription.t()} | {:error, term()} stable 0.1.0 Writes through AuroraMeter.Storage.put_subscription/1, so the core’s subscription cache is evicted on every node.
AuroraMeter.Pro.Subscriptions.sync_from_session/1 (map()) :: {:ok, AuroraMeter.Schema.Subscription.t()} | {:error, term()} stable 0.1.0
AuroraMeter.Pro.Subscriptions.plan_ref/1 (map()) :: {String.t(), String.t() | nil} additive 1.0.0 The {plan_id, plan_version} a Stripe subscription or session maps to: the item prices first, then metadata.plan_id with metadata.plan_version, then {"unknown", nil}.
AuroraMeter.Pro.Subscriptions.plan_id/1 (map()) :: String.t() deprecated 0.2.0 elem(plan_ref/1, 0). Deprecated in 1.0 and removed in 2.0: it drops the version, which is half of a commercial contract.
AuroraMeter.Pro.Transitions.schedule/3 (tenant, {atom(), String.t()}, keyword()) :: {:ok, AuroraMeter.Schema.PlanTransition.t()} | {:error, term()} additive 1.0.0 Schedules a plan change the billing provider makes first: confirm: :provider, with the target price id resolved and stored on the row before it is written.
AuroraMeter.Pro.Transitions.status/2 (tenant, String.t()) :: AuroraMeter.Schema.PlanTransition.t() | nil additive 1.0.0 Reads one transition back by tenant and reference.
AuroraMeter.Pro.Transitions.Applier.run/1 (keyword()) :: {:ok, map()} additive 1.0.0 Drives every due provider transition. An Oban worker; safe to run from every node at once.
AuroraMeter.Pro.Webhook.handle_event/1 (map()) :: AuroraMeter.Pro.Subscriptions.result() | AuroraMeter.Pro.Credits.result() | :ok stable 0.1.0 The event router, for a host that verifies and routes Stripe events itself.
AuroraMeter.Pro.Webhook.verify/3 (binary(), String.t(), String.t() | [String.t()]) :: :ok | {:error, term()} stable 0.1.0 HMAC-SHA256 over Stripe’s signed payload, with a 300 second timestamp tolerance.
AuroraMeter.Pro.Webhook.sign/3 (String.t(), integer(), binary()) :: String.t() stable 0.1.0 The signature a test needs to post a believable event.

AuroraMeter.Pro.Webhook is also a Plug (stable since 0.1.0; :path since 1.2.0). Mount it in the endpoint, above Plug.Parsers, because the signature is over the raw body: plug AuroraMeter.Pro.Webhook, path: "/webhooks/stripe". With :path it handles only a POST to exactly that path and passes every other request through untouched; a :path that is not a string starting with / raises ArgumentError at init/1. Without :path every request that reaches it is treated as a Stripe event, which suits only a pipeline that sees nothing else. A router forward cannot work: it runs after the endpoint’s parsers have consumed the body. handle_event/1 answers {:refused, :untenanted_subscription} (since 1.2.0) for a subscription event whose subscription carries no tenant_key metadata; the plug turns it into a 200.

1.4 Usage reporting, reconciliation, rollups and export

Entry Signature and return Class Since Notes
AuroraMeter.Pro.UsageReporter.report_all/0 () :: :ok | {:error, [term()]} stable 0.1.0 Reports metered deltas to Stripe Billing Meters through the aurora_meter_usage_reports ledger: at least once, under an identifier naming the window, which is what Stripe deduplicates on, so a retried send does not bill those units twice. Also an Oban worker.
AuroraMeter.Pro.Reconcile.run/1 (keyword()) :: %{local_drift: [map()], items_open: non_neg_integer()} stable 0.1.0 A local over-reporting check: it flags last_reported values greater than the persisted counter, under :local_drift; :items_open counts the provider findings waiting for a person. It does not detect unreported usage, query Stripe, or prove that an accepted meter event reached an invoice. Options :flush (default true), :since, :limit, :tenant. Arity 0 exists through defaults.
AuroraMeter.Pro.Rollup.rollup_all/1 (keyword()) :: :ok stable 0.1.0 Rebuilds month buckets from counters and day buckets from history (or events when history: false). Option :since_days (90). Arity 0 exists through defaults. Also an Oban worker.
AuroraMeter.Pro.Rollup.history/2 (tenant, String.t()) :: [AuroraMeter.Pro.Schema.Rollup.t()] stable 0.1.0 The second argument is a bucket kind ("month" or "day"), not a feature name. A feature name matches no bucket kind and returns [].
AuroraMeter.Pro.Export.usage_csv/2 (tenant, keyword()) :: String.t() stable 0.1.0 Header feature,bucket_start,value. The only option read is :bucket_kind (default "month"); :days, :from and :to are ignored. Arity 1 exists through defaults.
AuroraMeter.Pro.Export.daily_csv/3 (tenant, atom(), keyword()) :: String.t() stable 0.2.0 Header date,value. Options are passed through to AuroraMeter.history/3 (:days, :from, :to). Arity 2 exists through defaults.

1.5 Alerts

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Alerts.check_all/0 () :: :ok stable 0.1.0 Deduplicated per tenant, feature, period and threshold. A handler that fails rolls the dedup record back, so the next sweep tries again. Also an Oban worker.

1.6 Request audit log

Entry Signature and return Class Since Notes
AuroraMeter.Pro.AuditLog.record/1 (map()) :: :ok stable 0.3.0 Never raises and never blocks the request. A :tenant (or :tenant_key) is required; :method, :path and :status are what make the row worth having. Unknown keys are ignored.
AuroraMeter.Pro.AuditLog.list/2 (tenant, keyword()) :: %{data: [event()], has_more: boolean(), next_cursor: String.t() | nil} stable 0.3.0 Options :limit (50, capped at 200), :before, :status, :status_class (:success, :client_error, :server_error), :method, :path (a prefix), :mode, :from, :to. Arity 1 exists through defaults.
AuroraMeter.Pro.AuditLog.stats/2 (tenant, keyword()) :: %{total: non_neg_integer(), by_status_class: map(), p50_ms: non_neg_integer() | nil, p95_ms: non_neg_integer() | nil} stable 0.3.0 The same filters as list/2; :limit and :before are ignored. Arity 1 exists through defaults.
AuroraMeter.Pro.AuditLog.any?/2 (tenant, keyword()) :: boolean() stable 0.3.0 Has this tenant ever called the API. Arity 1 exists through defaults.
AuroraMeter.Pro.AuditLog.cursor/1 (AuroraMeter.Pro.Schema.AuditEvent.t()) :: String.t() stable 0.3.0 The keyset cursor for one row, over (inserted_at, id).
AuroraMeter.Pro.AuditLog.prune/1 (keyword()) :: {:ok, non_neg_integer()} stable 0.3.0 Deletes in bounded batches. Arity 0 exists through defaults.
AuroraMeter.Pro.AuditLog.plan/1 (keyword()) :: {:ok, non_neg_integer()} additive 1.0.0 Counts what prune/1 would delete, by the same predicate. Writes nothing. Arity 0 exists through defaults.
AuroraMeter.Pro.AuditLog.Pruner.run/1 (keyword()) :: :ok deprecated 0.3.0 The audit-log sweep, now a shim for AuroraMeter.Pro.Retention. Also an Oban worker. Arity 0 exists through defaults.
AuroraMeter.Pro.Retention.plan/1 (keyword()) :: {:ok, map()} | {:blocked, map(), [map()]} additive 1.0.0 Dry run. Writes nothing. Options :only, :older_than_days, :older_than.
AuroraMeter.Pro.Retention.prune/1 (keyword()) :: {:ok, map()} | {:blocked, map(), [map()]} additive 1.0.0 Options :only, :older_than_days, :older_than, :batch_size, :max_items. A table outside the allow list raises ArgumentError.
AuroraMeter.Pro.Retention.tables/0 () :: [atom()] additive 1.0.0 The allow-list keys.
AuroraMeter.Pro.Retention.protected/0 () :: [String.t()] additive 1.0.0 The tables a prune must never delete a row from.
AuroraMeter.Pro.Retention.operation/1 (atom()) :: String.t() additive 1.0.0 The AuroraMeter.Operations name one table’s prune pauses under.
AuroraMeter.Pro.Retention.Pruner.operations/0 () :: [String.t()] additive 1.0.0 Every operation name the worker pauses under, one per table.

AuroraMeter.Pro.Plugs.AuditLog is the Plug. Everything host-shaped arrives as a resolver function of the conn (:tenant, :actor, :metadata), so the package never guesses at a host’s schema. A :tenant resolver returning nil skips the write, which is how unauthenticated requests stay out of the log: put the plug after your authentication, not before.

1.7 Dashboard

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Dashboard.load/2 (tenant, keyword()) :: map() stable 0.2.0 Everything the components render, in one call, so a LiveView re-renders on a usage broadcast. Option credits: false. Arity 1 exists through defaults.
AuroraMeter.Pro.Dashboard.money?/1 (map()) :: boolean() stable 0.3.0 Whether the tenant has a credit ledger, which is what guards the money section.
AuroraMeter.Pro.Components.usage_dashboard/1 HEEx component optional-dep 0.1.0 Needs phoenix_live_view and phoenix_html. Attributes tenant, data, money.
AuroraMeter.Pro.Components.usage_chart/1 HEEx component optional-dep 0.2.0 Needs phoenix_live_view and phoenix_html.
AuroraMeter.Pro.Components.quota_card/1 HEEx component optional-dep 0.2.0 Needs phoenix_live_view and phoenix_html.
AuroraMeter.Pro.Components.money_section/1 HEEx component optional-dep 0.3.0 Needs phoenix_live_view and phoenix_html.
AuroraMeter.Pro.Components.styles/1 HEEx component optional-dep 0.2.0 Needs phoenix_live_view and phoenix_html. Inline CSS scoped to .aurora-dashboard, themeable through CSS custom properties.
AuroraMeter.Pro.Components.format_int/1 (integer()) :: String.t() optional-dep 0.2.0 Needs phoenix_live_view and phoenix_html, because the whole module is compiled only when Phoenix.Component is loaded.

1.8 Configuration accessors

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Config.stripe_prices/0 () :: map() stable 0.1.0
AuroraMeter.Pro.Config.stripe_metered_prices/0 () :: map() stable 0.2.0
AuroraMeter.Pro.Config.stripe_meters/0 () :: map() stable 0.1.0 Keyed by feature, unlike stripe_prices, which is keyed by plan id.
AuroraMeter.Pro.Config.prices_for/1 (atom() | String.t()) :: [String.t()] stable 0.2.0
AuroraMeter.Pro.Config.price_for/1 (atom() | String.t()) :: String.t() | nil stable 0.1.0 The first of prices_for/1.
AuroraMeter.Pro.Config.metered_prices_for/1 (atom() | String.t()) :: [String.t()] stable 0.2.0 Keyed by plan id.
AuroraMeter.Pro.Config.plan_for_price/1 (String.t() | nil) :: atom() | nil stable 0.2.0 Returns {plan_id, version} in 1.0 through a new plan_ref/1; this name keeps this shape for one major and is deprecated then.
AuroraMeter.Pro.Config.meter_for/1 (atom() | String.t()) :: String.t() | nil stable 0.1.0
AuroraMeter.Pro.Config.webhook_secret/0 () :: String.t() | [String.t()] | nil stable 0.1.0 Resolves {:system, "VAR"}.
AuroraMeter.Pro.Config.portal_configuration/0 () :: String.t() | nil stable 0.2.0 Reads :stripe_portal_configuration.
AuroraMeter.Pro.Config.alert_thresholds/0 () :: [pos_integer()] stable 0.1.0
AuroraMeter.Pro.Config.alert_handler/0 () :: (map() -> term()) | nil stable 0.1.0
AuroraMeter.Pro.Config.credits_stripe_client/0 () :: module() stable 0.3.0
AuroraMeter.Pro.Config.credits_product_id/0 () :: String.t() | nil stable 0.3.0
AuroraMeter.Pro.Config.credits_product_name/0 () :: String.t() stable 0.3.0
AuroraMeter.Pro.Config.credits_currency/0 () :: String.t() stable 0.3.0 Falls back to the core’s :credits_currency, so the two cannot disagree by accident.
AuroraMeter.Pro.Config.credits_presets_cents/0 () :: [pos_integer()] stable 0.3.0
AuroraMeter.Pro.Config.credits_min_cents/0 () :: pos_integer() stable 0.3.0
AuroraMeter.Pro.Config.credits_max_cents/0 () :: pos_integer() stable 0.3.0
AuroraMeter.Pro.Config.credits_tax/0 () :: :none | :exclusive stable 1.1.0
AuroraMeter.Pro.Config.credits_handler/0 () :: (term() -> term()) | nil stable 0.3.0
AuroraMeter.Pro.Config.auto_top_up_cooldown_seconds/0 () :: pos_integer() stable 0.3.0
AuroraMeter.Pro.Config.auto_top_up_max_failures/0 () :: pos_integer() stable 0.3.0
AuroraMeter.Pro.Config.audit_log_retention_days/0 () :: pos_integer() stable 0.3.0
AuroraMeter.Pro.Config.audit_log_writer/0 () :: :async | :sync stable 0.3.0
AuroraMeter.Pro.Config.stripe_account_id/0 () :: String.t() | nil stable 1.0.0
AuroraMeter.Pro.Config.stripe_mode/0 () :: :test | :live stable 1.0.0 Falls back to the API key’s prefix when :stripe_mode is unset.
AuroraMeter.Pro.Config.stripe_account_check/0 () :: :skip | :best_effort | :require stable 1.0.0
AuroraMeter.Pro.Config.api_version/0 () :: String.t() stable 1.0.0 The Stripe-Version Pro sends. validate!/0 writes it into config :stripity_stripe, :api_version.
AuroraMeter.Pro.Config.webhook_api_version/0 () :: :pinned | :any | String.t() stable 1.0.0 The version received events are expected to carry, which Pro cannot set and the host can.
AuroraMeter.Pro.Config.expected_webhook_api_version/0 () :: String.t() | nil stable 1.0.0 webhook_api_version/0 resolved: api_version/0 for :pinned, nil for :any.
AuroraMeter.Pro.Config.mapping_version/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.mapping_fingerprint/0 () :: String.t() stable 1.0.0 A sha256 over the three mapping maps, stable across key order. mapping_version/0 is the host’s promise that a mapping changed; this is the fact, so a change without a bump is detectable afterwards.
AuroraMeter.Pro.Config.exporter/0 () :: module() stable 1.0.0
AuroraMeter.Pro.Config.outbox_lease_seconds/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.outbox_max_attempts/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.outbox_batch_size/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.outbox_backoff_base_seconds/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.outbox_backoff_cap_seconds/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.outbox_rate_limit_delay_seconds/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.outbox_retention_days/0 () :: pos_integer() stable 1.0.0 Days a confirmed outbox item is kept.
AuroraMeter.Pro.Config.webhook_event_retention_days/0 () :: pos_integer() additive 1.0.0 Days.
AuroraMeter.Pro.Config.recovery_action_retention_days/0 () :: pos_integer() additive 1.0.0 Days.
AuroraMeter.Pro.Config.reconciliation_item_retention_days/0 () :: pos_integer() additive 1.0.0 Days a resolved reconciliation item is kept.
AuroraMeter.Pro.Config.uncertainty_horizon_seconds/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.reporter_batch_size/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.stripe_meter_ids/0 () :: map() stable 1.0.0 Keyed by feature, like stripe_meters/0, and holding a different value: the meter id, which is what a summary read takes in its path.
AuroraMeter.Pro.Config.meter_id_for/1 (atom() | String.t()) :: String.t() | nil stable 1.0.0 The meter id for one feature, or nil. A feature with no id can be exported and cannot be reconciled.
AuroraMeter.Pro.Config.adjustment_window_seconds/0 () :: pos_integer() stable 1.0.0 Stripe documents 24 hours from receipt for a meter event cancellation; the default keeps an hour under it.
AuroraMeter.Pro.Config.confirmation_delay_seconds/0 () :: non_neg_integer() stable 1.0.0
AuroraMeter.Pro.Config.confirmation_grace_seconds/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.reconciler_max_requests/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.reconciler_max_groups/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.reconciler_time_budget_ms/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.reconciler_check_invoices?/0 () :: boolean() stable 1.0.0
AuroraMeter.Pro.Config.reconciler_error_report_batch/0 () :: pos_integer() stable 1.0.0
AuroraMeter.Pro.Config.invalidate!/0 () :: :ok stable 1.0.0 Forgets the validated configuration on this node, so the next accessor validates again. For tests and for a health check that has just rewritten the environment.
AuroraMeter.Pro.Config.validated/0 () :: map() | nil stable 1.0.0 The validated configuration, or nil when none has been installed.

1.9 The source cutover

Moving a feature from buffered reporting to event reporting, once, at a period boundary. The reporter stages a buffered window only while period_start < w and the outbox accepts an event only while period_start >= w, so a period belongs to exactly one path. See the cutover guide.

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Cutover.schedule/3 (atom(), DateTime.t(), keyword()) :: {:ok, struct()} | {:error, :already_scheduled | :not_a_period_start | :in_the_past | Ecto.Changeset.t()} stable 1.0.0 Options :actor, :reason, :tenant. Arity 2 exists through a default. A second call for one feature writes nothing; moving a watermark goes through the recovery API.
AuroraMeter.Pro.Cutover.watermark/1 (atom()) :: DateTime.t() | nil stable 1.0.0 Read on the durable record path. Not cached: a lagging cache would hold nil while the row held a watermark, and a reader that believes there is no watermark accepts an event for a period the buffered reporter already reported.
AuroraMeter.Pro.Cutover.status/1 (atom()) :: map() stable 1.0.0 %{feature, watermark, buffered_periods_open, event_items, drained?}. drained? is the condition for deploying the :events source.
AuroraMeter.Pro.Cutover.list/0 () :: [struct()] stable 1.0.0 Every scheduled cutover, oldest watermark first.

1.10 Guarded recovery

What an operator may do to a financial record that is stuck. Every mutation takes the subject first and one keyword list second, carrying expected: (the state the operator believes they are acting on), reason: and evidence:. A mutation writes exactly one aurora_meter_recovery_actions row whether it applies or refuses. There is no force: option. Nothing here calls a provider. See Recovery.

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Recovery.list_uncertain/1 (keyword()) :: [map()] stable 1.0.0 uncertain, rejected and quarantined items, newest first. Options :state (one, a list, or :all), :tenant, :kind, :older_than (seconds against first_attempt_at), :limit (50, capped at 500) and :cursor. Writes nothing. Arity 0 exists through a default.
AuroraMeter.Pro.Recovery.inspect_item/1 (Ecto.UUID.t()) :: {:ok, map()} | {:error, :not_found} stable 1.0.0 The row, the payload, the exporter’s describe/0, whether the first attempt is inside the idempotency horizon, the staged usage_reports row, matching open reconciliation items, the eligibility the item would be re-checked against, and the recovery actions already recorded against it.
AuroraMeter.Pro.Recovery.actions/2 (String.t(), keyword()) :: [map()] stable 1.0.0 The audit trail for one subject, newest first. Option :limit (20). Arity 1 exists through a default.
AuroraMeter.Pro.Recovery.pending_payments/1 (keyword()) :: [map()] stable 1.0.0 Every credit account with a charge in flight, oldest first. Option :tenant. Arity 0 exists through a default.
AuroraMeter.Pro.Recovery.acknowledge_item/2 (Ecto.UUID.t(), keyword()) :: {:ok, summary()} | {:error, refusal()} stable 1.0.0 uncertain to accepted. expected: takes :state, :lease_token, :subject_ref and a non-empty :provider_ref. For a usage_window item it advances usage_reports.last_reported and clears the staged link in the same transaction. Never moves an item to confirmed.
AuroraMeter.Pro.Recovery.abandon_item/2 (Ecto.UUID.t(), keyword()) :: {:ok, summary()} | {:error, refusal()} stable 1.0.0 uncertain or quarantined to rejected. expected: takes :state, :lease_token and :subject_ref. Leaves last_reported where it is and clears the staged link, so the next reporter run stages the window again under a new identity.
AuroraMeter.Pro.Recovery.requeue_item/2 (Ecto.UUID.t(), keyword()) :: {:ok, summary()} | {:error, refusal()} stable 1.0.0 quarantined to pending. expected: takes :state, :lease_token, :subject_ref and :quarantine_reason. Refuses {:error, :mapping_changed} and {:error, {:still_ineligible, check}}.
AuroraMeter.Pro.Recovery.attach_payment_intent/2 (tenant, keyword()) :: {:ok, map()} | {:skip, atom()} | {:error, refusal() | term()} stable 1.0.0 Records a pi_... an operator identified and resumes the payment through the GET-only path. expected: takes :pending_idempotency_key; intent_id: is required; resume: defaults to true. Creates no charge and grants nothing by itself.
AuroraMeter.Pro.Recovery.abandon_payment/2 (tenant, keyword()) :: {:ok, map()} | {:error, refusal()} stable 1.0.0 Clears the four pending payment columns and nothing else. expected: takes :pending_idempotency_key and :pending_payment_intent_id, which must be nil. Refuses {:error, :intent_known} when an intent is known.
AuroraMeter.Pro.Recovery.reschedule_cutover/2 (atom(), keyword()) :: {:ok, map()} | {:error, refusal()} stable 1.0.0 Moves a watermark AuroraMeter.Pro.Cutover.schedule/3 refuses to move. expected: takes :effective_period_start; to: is required; :tenant optional. Refuses {:error, {:already_effective, counts}} once anything has been billed at or after the earlier of the two watermarks.

1.11 Periods and migrations

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Period.containing/2 (tenant, DateTime.t()) :: AuroraMeter.Period.t() stable 1.0.0 The subscription window when the instant falls inside it, and the calendar month with source: :calendar_fallback otherwise. The optional AuroraMeter.Period callback.
AuroraMeter.Pro.Migration.latest_version/0 () :: pos_integer() stable 0.3.0 9 in this release.
AuroraMeter.Pro.Migration.up/1 (keyword()) :: :ok stable 0.3.0 Options :version, :from, :to. Arity 0 exists through defaults. Every version is idempotent.
AuroraMeter.Pro.Migration.down/1 (keyword()) :: :ok stable 0.3.0 Options :version, :from, :to. Arity 0 exists through defaults.

AuroraMeter.Pro.Period implements the whole AuroraMeter.Period behaviour. Configure it with config :aurora_meter, period_source: AuroraMeter.Pro.Period; c:AuroraMeter.Period.current/2 is a callback and is not called directly.

1.12 Telemetry

The Pro event catalogue as data, and the Telemetry.Metrics presets over it. The tag rules themselves are core’s: see AuroraMeter.Telemetry.tag_allow_list/0 and Telemetry.

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Telemetry.events/0 () :: [AuroraMeter.Pro.Telemetry.event_doc()] stable 1.0.0 Every Pro event, with its real measurement and metadata keys, the tags a preset may use, the emitter and the version it arrived in. Checked against lib/, docs/api.md and docs/telemetry.md on every run.
AuroraMeter.Pro.Telemetry.event_names/0 () :: [[atom()]] stable 1.0.0 Every concrete Pro event name.
AuroraMeter.Pro.Outbox.gauge/0 () :: :ok stable 1.0.0 Emits one [:aurora_meter, :pro, :outbox, :gauge] sample. The deliverer calls it at the end of every run; it is public so a host with a paused queue or another scheduler can still chart the backlog. Raises and emits nothing when the aggregate query fails, because a zero would read as an empty backlog.
AuroraMeter.Pro.Telemetry.provider_span/2 (atom(), (-> result)) :: result stable 1.0.0 Wraps one outbound provider call in a [:aurora_meter, :pro, :provider] span, at the seam where Pro calls the configured client, so one span is one HTTP attempt and never a retry loop. The result is returned untouched. Raises ArgumentError on an operation outside provider_operations/0.
AuroraMeter.Pro.Telemetry.provider_operations/0 () :: [atom()] stable 1.0.0 The closed set of operation values the provider span can carry, one per client callback. It is a list rather than a derivation so a reader can see every value the metadata can take.

1.13 AuroraMeter.Pro.Telemetry.Metrics (optional dependency)

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Telemetry.Metrics.metrics/1 (keyword()) :: [Telemetry.Metrics.t()] optional-dep 1.0.0 Needs telemetry_metrics (~> 0.6 or ~> 1.0). Options :feature_label and :include. Arity 0 exists through defaults. A host wanting both writes AuroraMeter.Telemetry.Metrics.metrics() ++ AuroraMeter.Pro.Telemetry.Metrics.metrics().
AuroraMeter.Pro.Telemetry.Metrics.groups/0 () :: [atom()] optional-dep 1.0.0 Needs telemetry_metrics. The groups :include accepts.

Without telemetry_metrics installed the module is not defined at all. Every Pro event is still emitted and AuroraMeter.Pro.Telemetry still works.

1.14 AuroraMeter.Pro.LiveDashboard.Page (optional dependency)

A Phoenix.LiveDashboard page for Pro’s commercial operations: the export backlog, uncertain and quarantined items, leases, open reconciliation differences, pending payments, the recovery audit trail and the provider mapping.

:authorized_by is required and there is no default. This page refuses authorized_by: :host_route, which AuroraMeter.LiveDashboard.Page accepts: every section here renders tenant keys, subject references and payment state, and “the route is authenticated” is not a basis for showing one customer’s payment state to whoever reached the dashboard. The accepted forms are in AuroraMeter.LiveDashboard.Auth.

The page is read-only. It renders the recovery audit trail and the exact AuroraMeter.Pro.Recovery call to paste, and ships no button that performs one: those mutations require an expected: map and an evidence: string that a one-click button cannot supply honestly.

Entry Signature and return Class Since Notes
AuroraMeter.Pro.LiveDashboard.Page.init/1 (keyword()) :: {:ok, map()} optional-dep 1.0.0 Needs phoenix_live_dashboard (>= 0.8.0 and < 0.10.0). Raises ArgumentError when :authorized_by is absent or unrecognised, and with a distinct message for :host_route.
AuroraMeter.Pro.LiveDashboard.Page.menu_link/2 (map(), map()) :: {:ok, String.t()} | {:disabled, String.t()} optional-dep 1.0.0 Needs phoenix_live_dashboard. Disabled with “Aurora Meter Pro: not configured” when AuroraMeter.Pro.validate!/0 raises.
AuroraMeter.Pro.LiveDashboard.Page.mount/3 (map(), map(), Phoenix.LiveView.Socket.t()) :: {:ok, Phoenix.LiveView.Socket.t()} optional-dep 1.0.0 Needs phoenix_live_dashboard. Evaluates the configured check before reading anything.
AuroraMeter.Pro.LiveDashboard.Page.handle_refresh/1 (Phoenix.LiveView.Socket.t()) :: {:noreply, Phoenix.LiveView.Socket.t()} optional-dep 1.0.0 Needs phoenix_live_dashboard. Re-evaluates the check on every refresh.
AuroraMeter.Pro.LiveDashboard.Page.render/1 HEEx optional-dep 1.0.0 Needs phoenix_live_dashboard. No form, no button, no phx-click.

2. Behaviours and their callbacks

Entry Callbacks Class Since Notes
AuroraMeter.Pro.Credits.StripeClient create_checkout_session/1, create_payment_intent/2, create_portal_session/1, create_product/1, search_products/1, update_customer/2, retrieve_customer/1, retrieve_payment_intent/1, retrieve_payment_method/1, retrieve_charge/1, list_charge_disputes/1, create_tax_calculation/1 stable 0.3.0 12 callbacks; create_tax_calculation/1 (new in 1.1.0) is optional and called only with credits_tax: :exclusive. The slice of Stripe the top-ups use. A custom client must implement retrieve_charge/1 and list_charge_disputes/1, because refund reconciliation reads the charge’s current state rather than trusting an event’s snapshot, and retrieve_customer/1, because a payment may not credit a tenant on a customer this installation’s Stripe account does not have. retrieve_customer/1 is new since 0.3.0.
Entry Signature and return Class Since Notes
AuroraMeter.Pro.Credits.StripeClient.impl/0 () :: module() stable 0.3.0 The configured implementation.

Pro implements two core behaviours:

Entry Implements Class Since Notes
AuroraMeter.Pro.Stripe AuroraMeter.Billing.Provider stable 0.1.0 config :aurora_meter, provider: AuroraMeter.Pro.Stripe.
AuroraMeter.Pro.Period AuroraMeter.Period stable 0.1.0 config :aurora_meter, period_source: AuroraMeter.Pro.Period.
AuroraMeter.Pro.Credits.StripeClient.Live AuroraMeter.Pro.Credits.StripeClient stable 0.3.0 The default, backed by stripity_stripe.

3. Structs and public types

Entry Shape Class Since Notes
AuroraMeter.Pro.Schema.UsageReport aurora_meter_usage_reports row stable 0.1.0 The usage reporting ledger: one row per reported window, carrying what was sent, the identifier it was sent under, and what came back.
AuroraMeter.Pro.Schema.Rollup aurora_meter_rollups row stable 0.1.0
AuroraMeter.Pro.Schema.Alert aurora_meter_alerts row stable 0.1.0 The dedup record, one per tenant, feature, period and threshold.
AuroraMeter.Pro.Schema.CreditAccount aurora_meter_credit_accounts row stable 0.3.0 The Stripe customer, the saved card and the auto top-up settings. Never the balance: that is the core ledger’s.
AuroraMeter.Pro.Schema.AuditEvent aurora_meter_audit_events row stable 0.3.0
Entry Signature and return Class Since Notes
AuroraMeter.Pro.Schema.CreditAccount.changeset/2 (t(), map()) :: Ecto.Changeset.t() stable 0.3.0
AuroraMeter.Pro.Schema.CreditAccount.auto_top_up_changeset/2 (t(), map()) :: Ecto.Changeset.t() stable 0.3.0
AuroraMeter.Pro.Schema.AuditEvent.changeset/1 (map()) :: Ecto.Changeset.t() stable 0.3.0

Named types a host will meet in a spec: t:AuroraMeter.Pro.AuditLog.event/0, t:AuroraMeter.Pro.AuditLog.page/0, t:AuroraMeter.Pro.AuditLog.stats/0 and t:AuroraMeter.Pro.AuditLog.status_class/0, t:AuroraMeter.Pro.Credits.AutoTopUpWorker.skip/0, and t:AuroraMeter.Pro.Subscriptions.result/0.

4. Return values and error tuples

Pro returns {:ok, value} | {:error, reason} almost everywhere, and the two places it does not are worth knowing.

  • AuroraMeter.Pro.Credits.AutoTopUpWorker.attempt/2 has a third outcome, {:skip, reason}: the guards said no (no account, disabled, no saved payment method, still inside the cooldown, balance already above the threshold). A skip is not a failure and does not count against :auto_top_up_max_failures.
  • AuroraMeter.Pro.Reconcile.run/1 returns %{local_drift: [drift], items_open: integer}. There is no :ok wrapper, because a map with two keys is the answer. It returned a bare list before 1.0.0.
  • AuroraMeter.Pro.Recovery‘s mutations return {:error, {:expected_state_mismatch, current}} where current holds the present values of exactly the keys the caller claimed, so the call can be re-issued from the refusal itself. The other refusals are {:missing_evidence, :reason | :evidence | :provider_ref}, :not_found, :intent_known, :not_a_payment_intent, :mapping_changed, {:still_ineligible, check}, :staged_link_changed, :not_scheduled, :in_the_past, :not_a_period_start and {:already_effective, counts}. A missing expected:, reason: or evidence: raises: it is a call that never reached the API’s semantics, and it is the one failure that writes no audit row.

Money crosses the provider boundary in minor units (amount_cents), and lives in the core ledger in micro-dollars. Every Pro entry that names an amount says which. AuroraMeter.Credits.Money converts, and nothing rounds inside a transaction.

Idempotency keys: Pro keys a credit grant on the Stripe PaymentIntent id and passes it to the core ledger as reference:. A charge carries a Stripe idempotency key of its own, stored on the account row, so a retried charge is one charge at Stripe as well as one grant locally.

A webhook handler that returns {:error, reason} makes the plug answer 500, so Stripe retries the event. That is deliberate: a top-up whose grant failed on a transient database error must not be dropped.

5. Configuration keys

Read from the :aurora_meter_pro application environment. {:system, "VAR"} is accepted wherever the notes say so, and is resolved at read time.

Key Type and default Class Since Notes
:stripe_prices map, %{} compat 0.1.0 %{{plan_id, version} => price_id | [price_id]}. Flat prices, attached with quantity 1. A bare plan_id key means version "1", so every 0.x mapping keeps working unchanged. One price id may belong to exactly one {plan_id, version}, and boot refuses a mapping where two claim the same one.
:stripe_metered_prices map, %{} compat 0.2.0 %{{plan_id, version} => [price_id]}. Attached without a quantity. Keyed exactly as :stripe_prices, and checked for price-id uniqueness against it.
:proration_behavior :none | :create_prorations | :always_invoice, :none additive 1.0.0 What Stripe is asked to do about the unused part of the period when a plan change is sent. Aurora Meter computes no proration of its own; the other two values are Stripe’s own, passed through, and what they produce is Stripe’s arithmetic.
:stripe_subscription_client module, Stripe.Subscription internal 1.0.0 The module retrieve/1 and update/3 are called on for a provider-ordered plan change.
:stripe_meters map, %{} stable 0.1.0 %{feature => meter_event_name}. Keyed by feature, not by plan.
:webhook_secret string, list of strings, {:system, var} or nil, nil stable 0.1.0 A list supports a secret rotation.
:stripe_portal_configuration string, {:system, var} or nil, nil stable 0.2.0 Stripe’s default portal often has plan switching and cancellation disabled.
:alert_thresholds list of integers, [80, 100] stable 0.1.0 Percentages.
:alert_handler 1-arity function or nil, nil stable 0.1.0 A handler that raises rolls the dedup record back.
:credits_stripe_client module, AuroraMeter.Pro.Credits.StripeClient.Live stable 0.3.0
:credits_product_id string, {:system, var} or nil, nil stable 0.3.0 Set it to skip the product lookup at boot.
:credits_product_name string, "Prepaid credits" stable 0.3.0
:credits_currency string, the core’s :credits_currency stable 0.3.0
:credits_presets_cents list of integers, [1_000, 2_500, 5_000, 10_000] stable 0.3.0
:credits_min_cents integer, 500 stable 0.3.0
:credits_max_cents integer, 100_000 stable 0.3.0
:credits_tax :none or :exclusive, :none stable 1.1.0 :exclusive adds tax on top through Stripe Tax and credits the pre-tax amount. See docs/top-ups.md.
:credits_handler 1-arity function or nil, nil stable 0.3.0 Receives {:granted, txn}, {:low_balance, event}, {:auto_top_up_failed, key, reason, count} and {:auto_top_up_disabled, key, reason}.
:auto_top_up_cooldown_seconds integer, 600 stable 0.3.0
:auto_top_up_max_failures integer, 3 stable 0.3.0
:audit_log_retention_days integer, 30 stable 0.3.0
:audit_log_writer :async | :sync, :async stable 0.3.0 :async runs the insert under a Task.Supervisor the host registers as AuroraMeter.Pro.TaskSupervisor (that name is a registered process, not a module this package defines). Right in production, useless in a test, where the assertion runs before the write: use :sync there.
:stripe_account_id string, {:system, var} or nil, nil stable 1.0.0 The acct_... every outbox item is addressed to. Part of the item’s identity, so two environments pointed at one database cannot settle each other’s usage. Pro schema version 10 refuses to migrate staged reports without it.
:stripe_mode :test | :live, inferred from the API key stable 1.0.0 Part of the outbox identity. An item staged in one mode is quarantined rather than sent in another.
:mapping_version integer, 1 stable 1.0.0 The host’s mapping generation. Bump it when a change to :stripe_meters changes what a feature means; items staged before and after are then different identities.
:exporter module, AuroraMeter.Pro.Exporter.StripeMeterEvents stable 1.0.0 The AuroraMeter.Exporter the outbox delivers through.
:outbox_lease_seconds integer, 120 stable 1.0.0 How long a claim holds an item before another worker may take it. A liveness setting: what stops two workers acknowledging one item is the row’s fencing token, not this number.
:outbox_max_attempts integer, 20 stable 1.0.0 Attempts before an item escalates to uncertain. Never to rejected.
:outbox_batch_size integer, 100 stable 1.0.0 Items claimed per deliverer run, chunked to the exporter’s max_batch.
:outbox_backoff_base_seconds integer, 5 stable 1.0.0 First retry delay; it doubles per attempt.
:outbox_backoff_cap_seconds integer, 900 stable 1.0.0 Largest computed retry delay.
:outbox_rate_limit_delay_seconds integer, 30 stable 1.0.0 Delay after a rate limit, instead of the exponential backoff. Stripe’s per-endpoint limit is 25 requests per second, so backing off by five seconds is not an answer to being over it.
:uncertainty_horizon_seconds integer, 82_800 stable 1.0.0 How long after its first attempt an item may still be resent. Past it the item becomes uncertain and waits for reconciliation. Stripe documents “at least 24 hours” for both the meter event identifier and the idempotency key, so the default keeps an hour of margin.
:reporter_batch_size integer, 200 stable 1.0.0 Subscriptions per keyset page in one reporter run.
:stripe_meter_client module, Stripe.Billing.MeterEvent internal 1.0.0 The module the meter event call goes through, so a test can substitute a double visible across processes. Not a supported production seam: write an AuroraMeter.Exporter instead.
:stripe_account_client module, Stripe.Account internal 1.0.0 The module retrieve/2 is called on for the startup account assertion. It exists so that assertion can be exercised without a network.
:stripe_account_check :skip | :best_effort | :require, :best_effort stable 1.0.0 Whether boot confirms :stripe_account_id against the account the API key reaches. :best_effort warns and continues on a network failure, so a Stripe outage cannot stop a deploy; :require refuses to boot; :skip makes no call, which is what a test configuration wants.
:api_version string, "2025-11-17.clover" stable 1.0.0 The Stripe-Version Pro sends on every request, written into config :stripity_stripe, :api_version at validation. The default is the version this release was tested against, so an SDK upgrade that changes its own default no longer changes the wire contract silently.
:webhook_api_version :pinned | :any | string, :pinned stable 1.0.0 The version received webhook events are expected to be serialised at. Stripe serialises an event at the endpoint’s version, or the account’s default when the endpoint names none, which is not the version above. A disagreement is recorded on the event row, carried in telemetry and logged once per distinct version; it is never refused, because the event is a real fact about money. :any switches the observation off.
:outbox_retention_days integer, 90 stable 1.0.0 Days a confirmed outbox item is kept before AuroraMeter.Pro.Retention may delete it. An item in any other state is never deleted. Floor 1 day.
:webhook_event_retention_days integer, 30 additive 1.0.0 Days a recorded provider webhook event is kept. Floor 1 day.
:recovery_action_retention_days integer, 365 additive 1.0.0 Days a recorded recovery action is kept. Floor 1 day.
:reconciliation_item_retention_days integer, 365 additive 1.0.0 Days a resolved reconciliation item is kept. An open one is never deleted. Floor 1 day.
:stripe_meter_ids map, %{} stable 1.0.0 %{feature => "mtr_..."}. Not the same value as :stripe_meters: sending a meter event takes the meter’s event name, reading a meter event summary takes its id in the path. A feature with no id here is exported and never reconciled, which the reconciler logs rather than passing over.
:adjustment_window_seconds integer, 82_800 stable 1.0.0 How long after Stripe received a meter event it can still be cancelled. Stripe’s cancel.identifier documentation says “You can only cancel events within 24 hours of Stripe receiving them”; the default keeps an hour of margin. Measured from the original item’s accepted_at, never from when the usage occurred.
:confirmation_delay_seconds integer, 300 stable 1.0.0 How long an accepted item is left alone before the reconciler looks for a summary accounting for it. Stripe documents that meter events aggregate asynchronously but states no bound, so this is a choice, not a documented number.
:confirmation_grace_seconds integer, 86_400 stable 1.0.0 How long an item may stay accepted with nothing accounting for it before an unconfirmed_item finding is opened. It is never auto-confirmed and never resent.
:reconciler_max_requests integer, 200 stable 1.0.0 Provider requests one reconciler run may make.
:reconciler_max_groups integer, 50 stable 1.0.0 Groups one reconciler run may examine.
:reconciler_time_budget_ms integer, 60_000 stable 1.0.0 Elapsed-time budget for one run, measured with AuroraMeter.Clock.monotonic_ms/0.
:reconciler_check_invoices boolean, false stable 1.0.0 Whether a run also reads invoices, at one request per customer. Off by default; the four provider states are reported as they are observed and nothing is inferred from an invoice nobody read.
:reconciler_error_report_batch integer, 50 stable 1.0.0 How many recorded meter error reports one run processes.
:recovery_actor string or nil, nil stable 1.0.0 Who an AuroraMeter.Pro.Recovery mutation is recorded as when the call passes no :actor. Unset means the node name, which is the honest default: the package cannot know who is at the console. A host that fronts recovery with its own admin screen should pass :actor per call, because one name for every operator is the same as no name.
:stripe_adjustment_client module, Stripe.Billing.MeterEventAdjustment internal 1.0.0 The module the cancellation call goes through. Separate from :stripe_meter_client because a correction is two requests against two endpoints and a test needs to fail one without failing the other.
:stripe_summary_client module, Stripe.Billing.MeterEventSummary internal 1.0.0 The module list/3 is called on to read a meter event summary.
:stripe_invoice_client module, Stripe.Invoice internal 1.0.0 The module list/2 is called on when :reconciler_check_invoices is true.

Every key above is declared in a schema and validated once, by AuroraMeter.Pro.validate!/0, which AuroraMeter.Pro runs from the host’s supervision tree. {:system, "VAR"} is resolved at validation, not at read time: a variable unset after boot no longer changes what a running node does. An unknown key logs a warning in this release and stops the boot in 1.0.

A host that does not add AuroraMeter.Pro to its tree keeps working: the first accessor validates lazily and logs one warning naming the module. If that lazy validation fails it is logged and the raw value is used, rather than raised: a configuration problem belongs at boot, not on a metering call with money in flight.

6. Telemetry events

The Matched in lib/ column holds the exact source text the inventory test greps for, so a renamed event fails the build.

Event Measurements Metadata Class Since Matched in lib/
[:aurora_meter, :alert] threshold, usage, percent tenant_key, feature, kind stable 0.1.0 [:aurora_meter, :alert]
[:aurora_meter, :usage_report] delta tenant_key, feature, period_start stable 0.1.0 [:aurora_meter, :usage_report]
[:aurora_meter, :reconcile] drift tenant_key, feature stable 0.1.0 [:aurora_meter, :reconcile]
[:aurora_meter, :pro, :auto_top_up] amount_cents tenant_key, result, reason stable 0.3.0 [:aurora_meter, :pro, :auto_top_up]
[:aurora_meter, :pro, :outbox, :deliver] duration_ms state, outcome, subject_kind, attempts, reason stable 1.0.0 [:aurora_meter, :pro, :outbox, :deliver]
[:aurora_meter, :pro, :provider] duration, monotonic_time, system_time operation, result, kind, reason, stacktrace stable 1.0.0 [:aurora_meter, :pro, :provider]
[:aurora_meter, :pro, :credits, :gauge] armed, below_threshold, enqueued, reconciliation_required operation stable 1.0.0 [:aurora_meter, :pro, :credits, :gauge]
[:aurora_meter, :pro, :credits, :wallet_wide_fallback] count tenant_key, payment_intent_id, operation stable 0.6.0 [:aurora_meter, :pro, :credits, :wallet_wide_fallback]
[:aurora_meter, :pro, :outbox, :gauge] pending, leased, accepted, confirmed, uncertain, rejected, quarantined, oldest_pending_age_seconds, legacy_pending none stable 1.0.0 [:aurora_meter, :pro, :outbox, :gauge]
[:aurora_meter, :pro, :outbox, :stale_worker] count item_id, lease_token, transition stable 1.0.0 [:aurora_meter, :pro, :outbox, :stale_worker]
[:aurora_meter, :pro, :webhook] duration_ms type, outcome, duplicate, api_version stable 1.0.0 [:aurora_meter, :pro, :webhook]
[:aurora_meter, :pro, :cutover] none feature, watermark, action stable 1.0.0 [:aurora_meter, :pro, :cutover]
[:aurora_meter, :pro, :correction] count outcome, subject_ref, item_id, window, net_value, original_age_seconds stable 1.0.0 [:aurora_meter, :pro, :correction]
[:aurora_meter, :pro, :reconciliation, :difference] expected, observed kind, tenant_key, feature stable 1.0.0 [:aurora_meter, :pro, :reconciliation, :difference]
[:aurora_meter, :pro, :reconciliation, :run] duration_ms, requests, groups, confirmed, items_opened stopped stable 1.0.0 [:aurora_meter, :pro, :reconciliation, :run]
[:aurora_meter, :pro, :transition] count tenant_key, ref, to_plan_id, to_version, result stable 1.0.0 [:aurora_meter, :pro, :transition]
[:aurora_meter, :pro, :usage_report, :plan_fallback] count tenant_key, feature, period_start, plan_id, plan_version stable 1.0.0 [:aurora_meter, :pro, :usage_report, :plan_fallback]
[:aurora_meter, :pro, :recovery, :action] count subject, action, outcome, tenant_key stable 1.0.0 [:aurora_meter, :pro, :recovery, :action]
[:aurora_meter, :pro, :retention, :prune] deleted, duration table, blocked stable 1.0.0 [:aurora_meter, :pro, :retention, :prune]

Three of the four sit in the core’s [:aurora_meter, ...] namespace without being core events, and the core’s telemetry guide does not list them, because the core does not know Pro exists. This page is where a host attaching handlers reads them. New Pro events use the [:aurora_meter, :pro, ...] prefix; the three historical names are kept, because renaming them would silently detach every handler already attached.

tenant_key is metadata, never a metric tag: the cardinality is unbounded. The closed set of names a metric may tag on is core’s AuroraMeter.Telemetry.tag_allow_list/0, stated once there rather than twice; AuroraMeter.Pro.Telemetry.events/0 names the tags each event offers, and Telemetry gives the reason for each.

[:aurora_meter, :pro, :retention, :prune] is listed here since 1.0.0, the release that first emitted it. It is emitted through a module attribute, and the guard that checks this page against lib/ matched only a literal event name, so the event could not be found and could not be documented without failing that guard. The guard now reads the parsed source.

7. PubSub messages

Aurora Meter Pro broadcasts nothing. There is no Pro PubSub message and no Pro topic. Live usage and credit balance updates come from the core (AuroraMeter.Broadcaster.topic/1 and AuroraMeter.Credits.topic/1), which is what AuroraMeter.Pro.Live.Dashboard subscribes to.

8. Mix tasks

Entry Command Class Since Notes
Mix.Tasks.AuroraMeterPro.Gen.Migration mix aurora_meter_pro.gen.migration stable 0.3.0 Options -r, --from, --upgrade. The core’s migration is generated separately: both are required.
Mix.Tasks.AuroraMeterPro.Cutover mix aurora_meter_pro.cutover stable 1.0.0 Options --list, --feature, --at, --status, --reason, --actor, --tenant. With --feature and no --at it refuses and prints the next period start rather than guessing. It never changes :feature_sources: that is the host’s deploy.
Mix.Tasks.AuroraMeterPro.Recovery mix aurora_meter_pro.recovery stable 1.0.0 Subcommands list, inspect, payments, actions, acknowledge, abandon, requeue, attach-intent, abandon-payment. Read-only by default. A mutating subcommand exits non-zero without --reason and --evidence, and without --yes it prints the planned change and writes nothing. --format json for a run pasted into an incident record.

9. Migration entry points

Section 1.9 lists them. The schema-version contract is the core’s, restated: versions are additive during 1.x, every version is idempotent, and a host calls them from its own Ecto migration. Pro schema version 11 pairs with core schema version 10 in this release, and the two migrations must both run.

10. Test helpers

Supported, and shipped in the Hex tarball, so a host test suite may depend on them. They are governed by the test-helper heading of the support policy rather than by SemVer on every name, and nothing in production should call them.

Entry Signature and return Class Since Notes
AuroraMeter.Pro.Stripe.Fake.reset/0 () :: :ok stable 0.1.0
AuroraMeter.Pro.Stripe.Fake.reported/0 () :: [map()] stable 0.1.0 Every usage entry the fake accepted.
AuroraMeter.Pro.Stripe.Fake.report_attempts/0 () :: non_neg_integer() stable 0.3.0 Attempts, not acceptances: what a test asserts on when it needs to know a retry sent once rather than twice.
AuroraMeter.Pro.Stripe.Fake.fail_reports/1 (term()) :: :ok stable 0.1.0 Arity 0 exists and defaults to :stripe_unavailable.
AuroraMeter.Pro.Stripe.Fake.fail_after_accept/1 (term()) :: :ok stable 0.3.0 Accept at the provider, then fail locally: the uncertain-outcome case.
AuroraMeter.Pro.Stripe.Fake.clear_failure/0 () :: :ok stable 0.1.0
AuroraMeter.Pro.Stripe.Fake.put_subscription/1 (map()) :: :ok stable 0.1.0
AuroraMeter.Pro.Stripe.Fake.share_globally!/0 () :: :ok stable 0.3.0 Lets a process other than the test own the fake’s state, for an async-unsafe case.
AuroraMeter.Pro.Stripe.Fake.global_used?/0 () :: boolean() stable 0.3.0 Whether the shared state was actually read, so a test cannot claim isolation it did not have.
AuroraMeter.Pro.Credits.StripeClient.Fake.reset/0 () :: :ok stable 0.3.0
AuroraMeter.Pro.Credits.StripeClient.Fake.calls/0 () :: [term()] stable 0.3.0 Every call the fake received, in order.
AuroraMeter.Pro.Credits.StripeClient.Fake.fail_payment_intents/1 (term()) :: :ok stable 0.3.0 Arity 0 exists and defaults to :card_declined.
AuroraMeter.Pro.Credits.StripeClient.Fake.hold_payment_intents/1 (String.t()) :: :ok stable 0.3.0 Holds intents at a chosen status, for the delayed-notification path.
AuroraMeter.Pro.Credits.StripeClient.Fake.clear_failure/0 () :: :ok stable 0.3.0
AuroraMeter.Pro.Credits.StripeClient.Fake.put_payment_intent/1 (map()) :: :ok stable 0.3.0
AuroraMeter.Pro.Credits.StripeClient.Fake.put_customer/2 (String.t(), term()) :: :ok stable 1.0.0 What retrieve_customer/1 will answer for one id. Every customer exists until one says otherwise.
AuroraMeter.Pro.Credits.StripeClient.Fake.no_such_customer/1 (String.t()) :: {:error, Stripe.Error.t()} stable 1.0.0 Stripe’s own 404 answer in the shape stripity_stripe produces it (code: :invalid_request_error, extra.card_code: :resource_missing), so a test refuses for the reason Stripe would.
AuroraMeter.Pro.Credits.StripeClient.Fake.put_charge/2 (String.t(), term()) :: :ok stable 0.3.0 What retrieve_charge/1 will answer, which is what refund reconciliation reads.
AuroraMeter.Pro.Credits.StripeClient.Fake.put_charge_disputes/2 (String.t(), term()) :: :ok stable 0.3.0
AuroraMeter.Pro.Credits.StripeClient.Fake.put_tax_rate/1 (non_neg_integer()) :: :ok stable 1.1.0 Basis points of tax create_tax_calculation/1 adds; zero until set.
AuroraMeter.Pro.Credits.StripeClient.Fake.fail_tax_calculations/1 (term()) :: :ok stable 1.1.0 nil clears it.
AuroraMeter.Pro.Credits.StripeClient.Fake.put_product/1 (String.t()) :: :ok stable 0.3.0
AuroraMeter.Pro.Credits.StripeClient.Fake.share_globally!/0 () :: :ok stable 0.3.0
AuroraMeter.Pro.Credits.StripeClient.Fake.global_used?/0 () :: boolean() stable 0.3.0

11. Internal modules

Not part of the supported surface. Each carries a stability banner at the top of its module docs where it has module docs at all, and each renders under the “Internal” group in the generated documentation.

The inventory test holds this list as a module attribute and fails when a module on it appears anywhere in the tables above, and when this list and the groups_for_modules “Internal” group in mix.exs disagree.

Entry Why it is internal
AuroraMeter.Pro.LiveDashboard.Sections The readers behind the Pro operator page. They answer {:ok, data} or {:unavailable, class} and never a zero in place of a figure they could not read.
AuroraMeter.Pro.LiveDashboard.View The HEEx the Pro operator page renders. It reads nothing.
AuroraMeter.Pro.Install.Templates The source snippets mix aurora_meter_pro.install writes into a host. A host reads the generated file, never this module.
AuroraMeter.Pro.Config.Schema The NimbleOptions schema and the whole-environment validator. AuroraMeter.Pro.validate!/0 and the AuroraMeter.Pro.Config accessors are the interface; the schema itself is where a key’s type and default are written, and both are documented in section 5.
AuroraMeter.Pro.Credits.StripeClient.Fake.State The agent behind the credit client fake. The fake’s own functions are the interface.
AuroraMeter.Pro.Migration.V1 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V2 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V3 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V4 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V5 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V6 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V7 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V8 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V9 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V10 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Migration.V11 One schema version. Call AuroraMeter.Pro.Migration.up/1.
AuroraMeter.Pro.Outbox.Store Every read and write of the outbox table. Operators query through AuroraMeter.Pro.Recovery.
AuroraMeter.Pro.Reconcile.Items Every read and write of the reconciliation items table. AuroraMeter.Pro.Reconcile.list_items/1 and resolve_item/3 are the interface.
AuroraMeter.Pro.Recovery.Action The expected-state comparison every recovery mutation runs first, and the one writer of aurora_meter_recovery_actions. AuroraMeter.Pro.Recovery is the interface.
AuroraMeter.Pro.Schema.OutboxItem The outbox row. There is deliberately no update changeset; every transition is a conditional statement in the store.
AuroraMeter.Pro.Schema.WebhookEvent The inbound provider event dedupe record.
AuroraMeter.Pro.Schema.SourceCutover The per-feature watermark between buffered and event reporting.
AuroraMeter.Pro.Schema.ReconciliationItem An open difference between what Pro sent and what the provider shows.
AuroraMeter.Pro.Schema.RecoveryAction The record of what an operator did to a stuck financial record. Append only but for outcome, which an attach rewrites once when its resume answers. Read it through AuroraMeter.Pro.Recovery.actions/2.
AuroraMeter.Pro.Stripe.Fake.State The agent behind the billing provider fake. The fake’s own functions are the interface.

A function carrying @doc false inside any module is internal for the same reason, whether or not its module is on this list. That includes every Oban.Worker callback (perform/1, new/2, backoff/1, timeout/1), every Plug callback (init/1, call/2), every Phoenix.LiveView callback, and every AuroraMeter.Billing.Provider and AuroraMeter.Pro.Credits.StripeClient callback implementation. Call the named entry point instead: report_all/0 rather than perform/1.

12. Core dependency

Pro consumes the free core through its public API only. It never copies a core schema definition, and the core never references Pro.

Package Requirement Notes
:aurora_meter >= 1.0.0-rc.1 and < 2.0.0 The requirement in mix.exs. Pro 1.0 requires core 1.0 and nothing older: the previous requirement, ~> 0.4 or ~> 0.5, admitted every 0.x, Hex resolved the newest published core (0.4.0), and this package does not compile against it. Spelled out rather than ~> 1.0 because a ~> requirement never admits a pre-release. The inventory test compares this cell with Mix.Project.config()[:deps], so the two cannot drift.

The core entries Pro relies on, all of them stable in the core’s own inventory: the facade (usage/2, usage_all/1, history/3, period/1, plan/1, quota/2, check/2, entitled?/2, feature_value/3); AuroraMeter.Storage.load_counter/3, get_subscription/1, put_subscription/1, load_history_range/4 and stream_counters/1; everything in AuroraMeter.Credits and AuroraMeter.Credits.Money; AuroraMeter.Plans.get/1 and AuroraMeter.Plan; AuroraMeter.Subscriptions.get/1 and invalidate/1; AuroraMeter.Period.current!/2; AuroraMeter.Clock.now/0 and db_now/0; AuroraMeter.Flusher.flush/0; AuroraMeter.Test; and the behaviours AuroraMeter.Billing.Provider and AuroraMeter.Period.

12.1 Direct core-table reads that remain

Two places still build an Ecto query against a core schema module rather than going through a core function. They are recorded here because an undocumented coupling is worse than a documented one, and recording them is not endorsing them: each is internal and each is scheduled for removal. Until then, a core schema change can break Pro in a way the core’s own inventory does not warn about.

The alerts sweep’s is gone as of 1.0.0: it walks AuroraMeter.Storage.list_subscriptions/2 in pages instead, which also stops it loading every subscription in the installation into one list. Pro’s lib/ now builds no query against AuroraMeter.Schema.Subscription at all.

The usage reporter’s two are gone as of 1.0.0: subscriptions come from AuroraMeter.Storage.list_subscriptions/2 and counters from AuroraMeter.Storage.load_counter/3. The file still names AuroraMeter.Schema.Subscription, and that is not coupling: it calls entitled?/1 and entitled_statuses/0, which are pure functions over a struct the core hands back. See the note at the end of this section.

The inventory test asserts each of these is still there, by matching the query text rather than a line number, so the list cannot quietly rot before the work lands.

The “Replaced by” column is plain text rather than code, because the core functions it names do not exist yet. A code span would make mix docs warn on every build, which is how a real broken reference gets missed.

File Core schema Replaced by Matched in lib/
lib/aurora_meter/pro/rollup.ex AuroraMeter.Schema.Counter AuroraMeter.Storage.stream_counters/2 from(c in Counter,
lib/aurora_meter/pro/rollup.ex AuroraMeter.Schema.History AuroraMeter.Storage.stream_history/2 from(h in History,

Reading a core struct is not on this list and is not coupling: the schema modules are public structs in the core’s inventory. What is recorded here is building a query against one.