billing

package
v1.800.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: Apache-2.0, MIT Imports: 72 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddAccountMember

func AddAccountMember(c *gin.Context)

AddAccountMember is a stub. Member management is done via IAM.

POST /v1/billing/accounts/:id/members

func AddInvoiceLineItem

func AddInvoiceLineItem(c *gin.Context)

AddInvoiceLineItem appends a line item to a draft invoice and recalculates the subtotal.

POST /v1/billing/invoices/:id/line-items

func AdjustCustomerBalance

func AdjustCustomerBalance(c *gin.Context)

AdjustCustomerBalance manually adjusts a customer's balance.

POST /v1/billing/customer-balance/adjustments

func ApplyInvoiceDiscount

func ApplyInvoiceDiscount(c *gin.Context)

ApplyInvoiceDiscount applies a discount to a draft invoice and recalculates the amount due.

POST /v1/billing/invoices/:id/apply-discount

func AuthorizeSpendCap

func AuthorizeSpendCap(c *gin.Context)

AuthorizeSpendCap is the per-request cap verdict for a (project,service) scope and a proposed amount, over the org's spend-alert rows. It evaluates EVERY covering row (most-restrictive-wins) and DENIES when any HARD-enforceable ENFORCE=true row is exceeded, reporting the tightest one. Soft rows — and a project-scoped enforce row whose project axis is NOT validated (pv=0) — never block; they only raise the warn utilization.

FAIL CLOSED, not open: if a HARD-enforceable enforce row's spend sum cannot be computed, the verdict DENIES (spend_cap) — an attacker must not disable a cap by inducing a compute error. Per-scope sums are memoized so covering rows sharing a scope cost one query. The row scan is bounded (loadOrgScopes).

GET /v1/billing/spend-alerts/authorize?user=&project=&service=&amount=&pv=

func BindAccountProject

func BindAccountProject(c *gin.Context)

BindAccountProject binds a project to this account (upsert — a project funds from exactly one account, so this moves it off any prior account).

PUT /v1/billing/accounts/:id/projects/:project

func BurnCredits

func BurnCredits(db *datastore.Datastore, userId string, amount int64, meterId string) (int64, error)

BurnCredits applies the credit burn-down algorithm: deducts amount from active grants in priority order. Returns the remaining amount (overage) and the grants that were modified.

func BurnCreditsPreview

func BurnCreditsPreview(db *datastore.Datastore, userId string, amount int64) (int64, error)

BurnCreditsPreview calculates credit burn without actually deducting. Returns the remaining amount after credits would be applied.

func CalculateInvoiceTax

func CalculateInvoiceTax(c *gin.Context)

CalculateInvoiceTax computes tax for an invoice based on a customer address and updates the invoice with the resulting tax lines.

POST /v1/billing/invoices/:id/calculate-tax?country=...&state=...

func CancelBillingSubscription

func CancelBillingSubscription(c *gin.Context)

CancelBillingSubscription cancels a subscription.

POST /v1/billing/subscriptions/:id/cancel

func CancelPaymentIntent

func CancelPaymentIntent(c *gin.Context)

CancelPaymentIntent cancels a payment intent.

POST /v1/billing/payment-intents/:id/cancel

func CancelPayout

func CancelPayout(c *gin.Context)

CancelPayout cancels a pending payout.

POST /v1/billing/payouts/:id/cancel

func CancelSetupIntent

func CancelSetupIntent(c *gin.Context)

CancelSetupIntent cancels a setup intent.

POST /v1/billing/setup-intents/:id/cancel

func CancelSubscriptionSchedule

func CancelSubscriptionSchedule(c *gin.Context)

CancelSubscriptionSchedule cancels a subscription schedule.

POST /v1/billing/subscription-schedules/:id/cancel

func CapturePaymentIntent

func CapturePaymentIntent(c *gin.Context)

CapturePaymentIntent captures a previously authorized payment intent.

POST /v1/billing/payment-intents/:id/capture

func ChargeGPU

func ChargeGPU(c *gin.Context)

ChargeGPU debits a GPU charge from PREPAID real money only. It is the ONLY commerce write that records a "gpu"-tagged withdrawal, and it is fail-closed:

	POST /v1/billing/gpu-charge  { user, amountCents, currency?, requestId?, tag? }

  - 402 {code: card_required}         — no chargeable card on file.
  - 402 {code: insufficient_prepaid}  — prepaid real money can't cover it
    (credits are NEVER consulted or consumed).
  - 201 {transactionId, prepaidBalance, ...} on success.

Admin/service token (mounted on the admin group) — called by the cloud GPU launch/meter path, never the browser.

func CloseDispute

func CloseDispute(c *gin.Context)

CloseDispute closes a dispute.

POST /v1/billing/disputes/:id/close

func ConfirmPaymentIntent

func ConfirmPaymentIntent(c *gin.Context)

ConfirmPaymentIntent confirms a payment intent.

POST /v1/billing/payment-intents/:id/confirm

func ConfirmSetupIntent

func ConfirmSetupIntent(c *gin.Context)

ConfirmSetupIntent confirms a setup intent, saving the payment method.

POST /v1/billing/setup-intents/:id/confirm

func CreateBankTransferInstruction

func CreateBankTransferInstruction(c *gin.Context)

CreateBankTransferInstruction creates bank transfer details for a customer.

POST /v1/billing/bank-transfer-instructions

func CreateBillingAccount

func CreateBillingAccount(c *gin.Context)

CreateBillingAccount provisions a real billing account for the org. The org's FIRST account becomes its Default (unbound projects + legacy untagged spend draw there) unless one already exists; a request may also explicitly claim default, which demotes the prior one — exactly one account is ever Default.

POST /v1/billing/accounts

func CreateBillingSubscription

func CreateBillingSubscription(c *gin.Context)

CreateBillingSubscription creates a new subscription and starts the billing lifecycle.

POST /v1/billing/subscriptions

func CreateCreditGrant

func CreateCreditGrant(c *gin.Context)

CreateCreditGrant creates a new credit grant for a user.

POST /v1/billing/credit-grants

func CreateCreditNote

func CreateCreditNote(c *gin.Context)

CreateCreditNote creates a credit note against an invoice.

POST /v1/billing/credit-notes

func CreateInvoice

func CreateInvoice(c *gin.Context)

CreateInvoice creates a new draft billing invoice.

POST /v1/billing/invoices

func CreateMeter

func CreateMeter(c *gin.Context)

CreateMeter creates a new usage meter definition.

POST /v1/billing/meters

func CreatePaymentIntent

func CreatePaymentIntent(c *gin.Context)

CreatePaymentIntent creates a new payment intent.

POST /v1/billing/payment-intents

func CreatePaymentMethod

func CreatePaymentMethod(c *gin.Context)

CreatePaymentMethod creates and attaches a payment method to a customer.

POST /v1/billing/payment-methods

func CreatePayout

func CreatePayout(c *gin.Context)

CreatePayout creates a new outbound payout.

POST /v1/billing/payouts

func CreatePricingRule

func CreatePricingRule(c *gin.Context)

CreatePricingRule creates a new pricing rule for a meter.

POST /v1/billing/pricing-rules

func CreateRefund

func CreateRefund(c *gin.Context)

CreateRefund creates a full or partial refund.

POST /v1/billing/refunds

func CreateSetupIntent

func CreateSetupIntent(c *gin.Context)

CreateSetupIntent creates a new setup intent for saving a payment method.

POST /v1/billing/setup-intents

func CreateSpendAlert

func CreateSpendAlert(c *gin.Context)

CreateSpendAlert creates a spend alert / cap. UserId is optional (an org-wide or project/service scope cap has none). At least one limit must be meaningful: a Threshold>0 (spend cap) or a RateLimitRpm>0 (rate limit).

POST /v1/billing/spend-alerts

func CreateSubscriptionItem

func CreateSubscriptionItem(c *gin.Context)

CreateSubscriptionItem adds an item to a subscription.

POST /v1/billing/subscription-items

func CreateSubscriptionSchedule

func CreateSubscriptionSchedule(c *gin.Context)

CreateSubscriptionSchedule creates a new subscription schedule.

POST /v1/billing/subscription-schedules

func CreateWebhookEndpoint

func CreateWebhookEndpoint(c *gin.Context)

CreateWebhookEndpoint registers a new webhook endpoint.

POST /v1/billing/webhook-endpoints

func DeleteBillingAccount

func DeleteBillingAccount(c *gin.Context)

DeleteBillingAccount removes an account and the bindings that point at it (their projects fall back to the org default). The default account cannot be deleted — promote another to default first. Past debits keep their AccountId: the ledger is immutable history, so an account's spend stays auditable after deletion.

DELETE /v1/billing/accounts/:id

func DeletePricingRule

func DeletePricingRule(c *gin.Context)

DeletePricingRule removes a pricing rule by ID.

DELETE /v1/billing/pricing-rules/:id

func DeleteSpendAlert

func DeleteSpendAlert(c *gin.Context)

DeleteSpendAlert deletes a spend alert by ID.

DELETE /v1/billing/spend-alerts/:id

func DeleteSubscriptionItem

func DeleteSubscriptionItem(c *gin.Context)

DeleteSubscriptionItem removes an item from a subscription.

DELETE /v1/billing/subscription-items/:id

func DeleteWebhookEndpoint

func DeleteWebhookEndpoint(c *gin.Context)

DeleteWebhookEndpoint removes a webhook endpoint.

DELETE /v1/billing/webhook-endpoints/:id

func Deposit

func Deposit(c *gin.Context)

Deposit creates a deposit (credit) transaction for an IAM user.

POST /v1/billing/deposit

Used by internal services to add funds to a user's account (payment processor settlement, manual credit, promotional grants, etc.).

func DetachPaymentMethod

func DetachPaymentMethod(c *gin.Context)

DetachPaymentMethod detaches (soft-deletes) a payment method.

DELETE /v1/billing/payment-methods/:id

func DownloadInvoicePDF

func DownloadInvoicePDF(c *gin.Context)

DownloadInvoicePDF renders and serves an invoice as a PDF.

GET /v1/billing/invoices/:id/pdf

Tenant isolation: the invoice is loaded from the caller's OWN org namespace (datastore.New(org.Namespaced(c))). GetById scopes the lookup to that namespace at the storage layer, so an org can only ever fetch its own invoice — a foreign id resolves to nothing and returns 404. It is mounted on the user group so a normal authenticated org member can download their own invoice.

func FinalizeInvoice

func FinalizeInvoice(c *gin.Context)

FinalizeInvoice transitions an invoice from draft to open.

POST /v1/billing/invoices/:id/finalize

func GPUChargeEligibility

func GPUChargeEligibility(c *gin.Context)

GPUChargeEligibility is the read-only launch gate: may a GPU of this size be launched/charged from prepaid right now?

GET /v1/billing/gpu-eligibility?user=<subj>&amountCents=<n>&minPrepaidCents=<m>

Returns 200 with {eligible,reason,...} in ALL cases (the caller decides how to render) — it never 402s, so the launch UI can show the exact remedy (add a card / add prepaid). amountCents is the immediate charge; minPrepaidCents is the 24h-minimum prepaid the GPU policy requires before launch (the gate needs prepaidAvailable >= max(amountCents, minPrepaidCents)).

func GetAutoRecharge

func GetAutoRecharge(c *gin.Context)

GetAutoRecharge returns the org's auto-recharge config (or disabled defaults).

GET /v1/billing/auto-recharge

func GetBalance

func GetBalance(c *gin.Context)

GetBalance returns the current balance for an IAM user.

GET /v1/billing/balance?user=hanzo/alice&currency=usd

All amounts in cents. available = balance - holds.

func GetBalanceAll

func GetBalanceAll(c *gin.Context)

GetBalanceAll returns balances across all currencies for an IAM user.

GET /v1/billing/balance/all?user=hanzo/alice

func GetBankTransferInstruction

func GetBankTransferInstruction(c *gin.Context)

GetBankTransferInstruction returns a single bank transfer instruction by ID.

GET /v1/billing/bank-transfer-instructions/:id

func GetBillingAccount

func GetBillingAccount(c *gin.Context)

GetBillingAccount returns one account the caller owns.

GET /v1/billing/accounts/:id

func GetBillingEvent

func GetBillingEvent(c *gin.Context)

GetBillingEvent retrieves a single billing event.

GET /v1/billing/events/:id

func GetBillingStatus

func GetBillingStatus(c *gin.Context)

GetBillingStatus returns a unified billing status for a user. Used by the bot gateway billing-gate to decide whether to allow LLM requests.

GET /v1/billing/status?user=<userId>

Response:

{
  "user": "alice",
  "hasPaymentMethod": true,
  "creditBalance": 500,   // cents
  "tier": "developer"
}

func GetBillingSubscription

func GetBillingSubscription(c *gin.Context)

GetBillingSubscription returns a single subscription.

GET /v1/billing/subscriptions/:id

func GetCapabilities

func GetCapabilities(c *gin.Context)

GetCapabilities returns the billing platform's supported features, payment methods, and currencies.

GET /v1/billing/capabilities

func GetCreditBalance

func GetCreditBalance(c *gin.Context)

GetCreditBalance returns the total available credit balance for a user.

GET /v1/billing/credit-balance?userId=...

func GetCreditBalanceBreakdown

func GetCreditBalanceBreakdown(c *gin.Context)

GetCreditBalanceBreakdown returns the credit balance grouped by tag. Used by Chat to distinguish trial vs paid credits.

GET /v1/billing/credit-balance/breakdown?userId=...

func GetCreditNote

func GetCreditNote(c *gin.Context)

GetCreditNote retrieves a credit note by ID.

GET /v1/billing/credit-notes/:id

func GetCustomerBalance

func GetCustomerBalance(c *gin.Context)

GetCustomerBalance retrieves the customer balance for a customer+currency.

GET /v1/billing/customer-balance?customerId=...&currency=...

func GetDNSUsageSummary

func GetDNSUsageSummary(c *gin.Context)

GetDNSUsageSummary returns a usage summary for DNS queries, zones, and records.

GET /v1/dns/usage/summary?user={owner/name}&period=day|month

func GetDispute

func GetDispute(c *gin.Context)

GetDispute retrieves a dispute by ID.

GET /v1/billing/disputes/:id

func GetInvoice

func GetInvoice(c *gin.Context)

GetInvoice returns a single billing invoice by ID.

GET /v1/billing/invoices/:id

func GetMeter

func GetMeter(c *gin.Context)

GetMeter returns a single meter by ID.

GET /v1/billing/meters/:id

func GetMeterEventsSummary

func GetMeterEventsSummary(c *gin.Context)

GetMeterEventsSummary returns aggregated usage for a meter+user+period.

GET /v1/billing/meter-events/summary?meterId=...&userId=...&periodStart=...&periodEnd=...

func GetMyBalance

func GetMyBalance(c *gin.Context)

GetMyBalance returns the calling user's balance for a given currency. Identity comes from the gateway-injected X-Org-Id / X-User-Id headers; no admin token required.

GET /v1/billing/me/balance?currency=usd

func GetOSSPayoutSummary

func GetOSSPayoutSummary(c *gin.Context)

GetOSSPayoutSummary rolls up accruals per package: the running total Hanzo owes each OSS package and where it would be paid. This is the payout-ready view — the disbursement job consumes it.

GET /v1/billing/oss-payout/summary?org=

func GetPaymentConfig

func GetPaymentConfig(c *gin.Context)

GetPaymentConfig returns the PUBLIC Square config (application id, location id, environment) the browser's Web Payments SDK must use to tokenize a card for THIS org. It resolves sandbox-vs-production through the SAME single authority as the charge path (org.TestMode / SQUARE_ENVIRONMENT) and the same KMS-then-env fallback, so the app id the browser tokenizes with always matches the env + access token commerce will vault/charge with. All values are public (safe to expose to the client).

GET /v1/billing/payment-config

func GetPaymentIntent

func GetPaymentIntent(c *gin.Context)

GetPaymentIntent retrieves a payment intent by ID.

GET /v1/billing/payment-intents/:id

func GetPaymentMethod

func GetPaymentMethod(c *gin.Context)

GetPaymentMethod retrieves a payment method by ID.

GET /v1/billing/payment-methods/:id

func GetPayout

func GetPayout(c *gin.Context)

GetPayout retrieves a payout by ID.

GET /v1/billing/payouts/:id

func GetPlan

func GetPlan(c *gin.Context)

GetPlan returns a single plan by slug.

GET /v1/billing/plans/:id

func GetRefund

func GetRefund(c *gin.Context)

GetRefund retrieves a refund by ID.

GET /v1/billing/refunds/:id

func GetSetupIntent

func GetSetupIntent(c *gin.Context)

GetSetupIntent retrieves a setup intent by ID.

GET /v1/billing/setup-intents/:id

func GetSubscriptionItem

func GetSubscriptionItem(c *gin.Context)

GetSubscriptionItem retrieves a subscription item by ID.

GET /v1/billing/subscription-items/:id

func GetSubscriptionSchedule

func GetSubscriptionSchedule(c *gin.Context)

GetSubscriptionSchedule retrieves a subscription schedule by ID.

GET /v1/billing/subscription-schedules/:id

func GetTier

func GetTier(c *gin.Context)

GetTier returns the billing tier, limits, and effective balance for a user.

For IAM-authenticated requests the tier is read from the JWT claim. For service-to-service calls the tier may be passed as a query parameter.

GET /v1/billing/tier?user=hanzo/alice

Response includes the tier config plus the effective available balance. There is no free tier: a zero-balance account has effectiveAvailable == 0 and is gated. The daily-credit term is 0 for every tier (see billing/tier); onboarding funds an account once via the starter-credit grant, and once that is spent the account is gated until it is topped up.

func GetUsage

func GetUsage(c *gin.Context)

GetUsage returns usage transactions for an IAM user, filtered by tag "api-usage".

GET /v1/billing/usage?user=hanzo/alice&currency=usd

func GetUsageRollup

func GetUsageRollup(c *gin.Context)

GetUsageRollup returns the unified plan + included-usage + consumed + overage + balance view for a user, for the current UTC month. This is the single read surface the console billing UI renders. All figures are derived from the same transactions the gateway's balance gate reads — no separate store.

GET /v1/billing/usage-rollup?user=hanzo/alice&plan=pro

`plan` is optional; when omitted it is resolved from the user's subscription.

func GetWebhookEndpoint

func GetWebhookEndpoint(c *gin.Context)

GetWebhookEndpoint retrieves a webhook endpoint.

GET /v1/billing/webhook-endpoints/:id

func GrantAllotment

func GrantAllotment(c *gin.Context)

GrantAllotment grants the calling/target user's plan-included monthly usage credit for the current UTC month, idempotently.

POST /v1/billing/allotment/grant   { "user": "hanzo/alice", "plan": "pro" }

The credit lands as an expiring balance deposit, so the gateway prepaid balance gate (available > 0) passes while the tenant is within allotment and fails closed once both the included credit and any purchased balance are exhausted. Admin token required.

func GrantStarter

func GrantStarter(c *gin.Context)

GrantStarter ensures an explicit subject has received the one-time $100 starter credit, idempotently. It is the on-signup welcome grant invoked by trusted services (chat, cloud-api) with the commerce service token — the service-to-service twin of POST /billing/credit (GrantStarterCredit, the admin/UI path). Neither requires a payment method, so a brand-new user "just works" on first chat without a card (a card gates top-up BEYOND the credit).

The subject is explicit and caller-supplied: "owner/name" for per-user (personal-org) billing, or the org slug for org-pooled billing — it MUST match the subject the cloud gateway debits and reads (object.BillingSubject in hanzoai/ai). The grant is scoped to the X-Org-Id namespace.

Idempotent + race-safe: credit.GrantIfEligibleNow dedupes on the starter-credit tag inside a datastore transaction, so duplicate/concurrent calls (e.g. the same user opening several chats at once) never double-grant — no bleed.

POST /v1/billing/grant-starter   {"user":"hanzo/alice","trigger":"chat_first_use"}

func GrantStarterCredit

func GrantStarterCredit(c *gin.Context)

GrantStarterCredit creates a $100 USD starter credit for a new org. The credit expires after 365 days if unused. Tagged "starter-credit" so it can be identified in transaction history.

No payment method is required — the starter credit is the on-signup grant that lets a new org evaluate the platform before adding a card. A verified payment method is required only to top up BEYOND the starter credit. Idempotent: deduped by the starter-credit tag.

POST /v1/billing/credit

func HandleProviderWebhook

func HandleProviderWebhook(c *gin.Context)

HandleProviderWebhook is the single ingress for payment-provider webhooks. It dispatches to the matching processor in payment/router, validates the signature, records the event in billing_events, and — for subscription lifecycle events — updates the local subscription row keyed by ProviderId.

POST /v1/billing/webhooks/:provider

The :provider path segment is informational; signature verification picks the right processor regardless. We pass the path segment as a lightweight filter so webhook endpoints are URL-scoped per-provider (easier in Stripe dashboard configuration).

func IncludedMonthlyCents

func IncludedMonthlyCents(slug string) int64

IncludedMonthlyCents returns the recurring monthly included-usage allotment for a plan slug, in cents. Returns 0 when the plan is unknown or declares no included allotment. This is the single catalog-derived input to the monthly allotment grant — the dollar value is the plan's declared cloud credit (@hanzo/plans limits.includedCloudCredits / includedCloudCreditsPerUser, i.e. the cloud.included_credits_usd entitlement).

func IngestSBOM

func IngestSBOM(c *gin.Context)

IngestSBOM stores the normalized SBOM for a built image.

POST /v1/billing/sbom

Called by the arcd build pipeline after `docker push`: it runs `syft <image> -o cyclonedx-json`, normalizes the component graph to {purl, name, ecosystem, version, scope}, and POSTs it here keyed by the immutable image digest. Idempotent on ImageDigest — re-ingesting the same image updates the record in place.

func InvoicePreview

func InvoicePreview(c *gin.Context)

InvoicePreview calculates an invoice preview: usage x pricing - credits.

POST /v1/billing/invoice-preview

func ListAccountMembers

func ListAccountMembers(c *gin.Context)

ListAccountMembers returns the members of a billing account (org). Currently the requesting IAM user is the sole member surfaced, since the full roster lives in IAM.

GET /v1/billing/accounts/:id/members

func ListAccountProjects

func ListAccountProjects(c *gin.Context)

ListAccountProjects lists the projects funded by an account (its bindings).

GET /v1/billing/accounts/:id/projects

func ListBalanceTransactions

func ListBalanceTransactions(c *gin.Context)

ListBalanceTransactions lists balance transactions for a customer.

GET /v1/billing/balance-transactions?customerId=...

func ListBankTransferInstructions

func ListBankTransferInstructions(c *gin.Context)

ListBankTransferInstructions lists bank transfer instructions, optionally filtered by customerId.

GET /v1/billing/bank-transfer-instructions?customerId=...

func ListBillingAccounts

func ListBillingAccounts(c *gin.Context)

ListBillingAccounts returns the org's billing accounts (with derived period spend). An org that has provisioned none still presents ONE synthetic account — itself, the org-wide default pool — so existing callers that expect >=1 account keep working and it mirrors the pre-account "org == billing account" behavior.

GET /v1/billing/accounts

func ListBillingEvents

func ListBillingEvents(c *gin.Context)

ListBillingEvents lists billing events, optionally filtered by type or objectId.

GET /v1/billing/events?type=...&objectId=...

func ListBillingSubscriptions

func ListBillingSubscriptions(c *gin.Context)

ListBillingSubscriptions lists subscriptions for a user.

GET /v1/billing/subscriptions?userId=...

func ListCreditGrants

func ListCreditGrants(c *gin.Context)

ListCreditGrants lists credit grants for a user.

GET /v1/billing/credit-grants?userId=...

func ListCreditNotes

func ListCreditNotes(c *gin.Context)

ListCreditNotes lists credit notes, optionally filtered by invoiceId or customerId.

GET /v1/billing/credit-notes?invoiceId=...&customerId=...

func ListDNSPlans

func ListDNSPlans(c *gin.Context)

ListDNSPlans returns the available DNS plans.

GET /v1/dns/plans

func ListDisputes

func ListDisputes(c *gin.Context)

ListDisputes lists disputes.

GET /v1/billing/disputes?paymentIntentId=...

func ListInvoices

func ListInvoices(c *gin.Context)

ListInvoices lists billing invoices, optionally filtered by userId and status.

GET /v1/billing/invoices?userId=...&status=...

func ListMeters

func ListMeters(c *gin.Context)

ListMeters returns all meters for the organization.

GET /v1/billing/meters

func ListOSSAccruals

func ListOSSAccruals(c *gin.Context)

ListOSSAccruals returns accrual ledger lines, optionally filtered by package PURL or spending org.

GET /v1/billing/oss-accruals?purl=&org=

func ListPaymentIntents

func ListPaymentIntents(c *gin.Context)

ListPaymentIntents lists payment intents, optionally filtered by customerId.

GET /v1/billing/payment-intents?customerId=...

func ListPaymentMethods

func ListPaymentMethods(c *gin.Context)

ListPaymentMethods lists payment methods for a customer.

GET /v1/billing/payment-methods?customerId=...&type=...

func ListPayouts

func ListPayouts(c *gin.Context)

ListPayouts lists payouts.

GET /v1/billing/payouts

func ListPlans

func ListPlans(c *gin.Context)

ListPlans returns the list of available plans, optionally filtered by category. Data is loaded at startup from embedded JSON plan definitions.

GET /v1/billing/plans
GET /v1/billing/plans?category=dns

func ListPricingRules

func ListPricingRules(c *gin.Context)

ListPricingRules lists pricing rules, optionally filtered by meter or plan.

GET /v1/billing/pricing-rules?meterId=...&planId=...

func ListRefunds

func ListRefunds(c *gin.Context)

ListRefunds lists refunds, optionally filtered by paymentIntentId or invoiceId.

GET /v1/billing/refunds?paymentIntentId=...&invoiceId=...

func ListSBOMs

func ListSBOMs(c *gin.Context)

ListSBOMs returns the stored SBOM records (metadata only, not components).

GET /v1/billing/sbom

func ListSpendAlerts

func ListSpendAlerts(c *gin.Context)

ListSpendAlerts returns the ORG's spend alerts (budgets/caps) plus derived period spend. It is the console Budgets read AND the source ScopeRules uses for the rate-limit config, so it MUST key on the same org the writer stored under.

GET /v1/billing/spend-alerts

func ListSubscriptionItems

func ListSubscriptionItems(c *gin.Context)

ListSubscriptionItems lists items for a subscription.

GET /v1/billing/subscription-items?subscriptionId=...

func ListSubscriptionSchedules

func ListSubscriptionSchedules(c *gin.Context)

ListSubscriptionSchedules lists subscription schedules.

GET /v1/billing/subscription-schedules?customerId=...&status=...

func ListTransactions

func ListTransactions(c *gin.Context)

ListTransactions returns transactions for an IAM user, newest first.

GET /v1/billing/transactions?user=hanzo/alice&limit=100&offset=0&currency=usd

Response: { "transactions": [...], "count": N, "user": "hanzo/alice" }

func ListWebhookEndpoints

func ListWebhookEndpoints(c *gin.Context)

ListWebhookEndpoints lists all webhook endpoints.

GET /v1/billing/webhook-endpoints

func MigrateHUSD

func MigrateHUSD(c *gin.Context)

MigrateHUSD moves every org's existing DB-ledger balance onto chain with zero drift (one-time). Dry-run by default (reports the snapshot + reconcile without minting); pass ?execute=true to mint. Platform-only.

POST /v1/billing/husd/migrate?execute=true

func PayInvoice

func PayInvoice(c *gin.Context)

PayInvoice attempts to collect payment on an open invoice.

POST /v1/billing/invoices/:id/pay

func PortalInvoices

func PortalInvoices(c *gin.Context)

PortalInvoices returns the customer's invoice list.

GET /v1/billing/portal/invoices?customerId=...

func PortalOverview

func PortalOverview(c *gin.Context)

PortalOverview returns a billing summary for the authenticated customer.

GET /v1/billing/portal/overview?customerId=...

func PortalPaymentMethods

func PortalPaymentMethods(c *gin.Context)

PortalPaymentMethods returns the customer's payment methods.

GET /v1/billing/portal/payment-methods?customerId=...

func PortalSubscriptions

func PortalSubscriptions(c *gin.Context)

PortalSubscriptions returns the customer's subscriptions.

GET /v1/billing/portal/subscriptions?customerId=...

func PostMyWelcome

func PostMyWelcome(c *gin.Context)

PostMyWelcome grants the welcome credit (idempotent, tag-deduped) to the calling user. Unlike POST /billing/credit — which requires an admin token and an explicit user — this endpoint is callable with just an IAM bearer token (user inferred from headers), designed to be invoked by the playground SPA on first successful login.

Idempotent: if the credit was already granted (or zapped), returns 200 with `granted: false` instead of failing.

POST /v1/billing/me/welcome

func ReactivateBillingSubscription

func ReactivateBillingSubscription(c *gin.Context)

ReactivateBillingSubscription reactivates a canceled subscription.

POST /v1/billing/subscriptions/:id/reactivate

func ReconcileInboundTransfer

func ReconcileInboundTransfer(c *gin.Context)

ReconcileInboundTransfer matches an incoming bank transfer by reference and creates a balance transaction for the customer.

POST /v1/billing/bank-transfer-instructions/reconciliation/match

func RecordDNSUsage

func RecordDNSUsage(c *gin.Context)

RecordDNSUsage records a batch of DNS query usage for a zone owner. The zone's owner is looked up via the user field. Usage is checked against the plan's daily query limit.

POST /v1/dns/usage

func RecordMeterEvents

func RecordMeterEvents(c *gin.Context)

RecordMeterEvents records one or more meter events (batch up to 100).

POST /v1/billing/meter-events

func RecordUsage

func RecordUsage(c *gin.Context)

RecordUsage records an API usage event as a Withdraw transaction.

POST /v1/billing/usage

Creates a withdraw transaction deducting the cost from the user's balance.

func Refund

func Refund(c *gin.Context)

Refund creates a deposit tagged "refund" to REVERSE a prior charge, correcting an overcharge. The metadata links back to the original transaction.

H1 (money-correctness). Previously this minted an arbitrary, uncapped credit against an UNVALIDATED originalTransactionId — a refund could exceed the original, name a non-existent or foreign transaction, refund a credit (doubling a deposit), or be replayed to double-refund. It is now fully validated and idempotent: the original MUST exist in THIS org's ledger, be a charge (Withdraw) for the SAME subject, and bound the amount (refund ≤ original); and there is AT MOST ONE refund per original transaction (keyed idempotency), so a retry replays and any second refund of the same charge is refused. Fail-closed throughout.

POST /v1/billing/refund

func ReleaseSubscriptionSchedule

func ReleaseSubscriptionSchedule(c *gin.Context)

ReleaseSubscriptionSchedule releases a subscription schedule.

POST /v1/billing/subscription-schedules/:id/release

func RemoveAccountMember

func RemoveAccountMember(c *gin.Context)

RemoveAccountMember is a stub. Member removal is done via IAM.

DELETE /v1/billing/accounts/:id/members/:memberId

func RemoveInvoiceLineItem

func RemoveInvoiceLineItem(c *gin.Context)

RemoveInvoiceLineItem removes a line item from a draft invoice by index or line item ID.

DELETE /v1/billing/invoices/:id/line-items/:itemId

func RenewBillingSubscription

func RenewBillingSubscription(c *gin.Context)

RenewBillingSubscription manually triggers a billing cycle renewal. Normally this would be automated by Temporal, but this endpoint allows manual triggering for testing and for deployments without Temporal.

POST /v1/billing/subscriptions/:id/renew

func Route

func Route(r router.Router, args ...gin.HandlerFunc)

Route registers billing endpoints for service-to-service calls. These are internal endpoints used by Cloud-API; require admin token.

func RunAllotments

func RunAllotments(c *gin.Context)

RunAllotments grants the monthly included allotment to every user with an active/trialing subscription in the request's organization, for the current UTC month. Idempotent per (user, period). Intended for the platform scheduler to invoke at period start (alongside the billing cycle).

POST /v1/billing/allotment/run

func RunAutoRechargeAllOrgs

func RunAutoRechargeAllOrgs(c *gin.Context)

RunAutoRechargeAllOrgs iterates every organization and, for those with auto-recharge enabled whose available balance is below the threshold, charges the default payment method and credits the balance. Intended to be invoked on a recurring schedule (CronJob) by the platform.

POST /v1/billing/auto-recharge/run-all

func RunBillingCycle

func RunBillingCycle(c *gin.Context)

RunBillingCycle processes all subscriptions whose current period has ended for the request's organization. It generates invoices and attempts collection for each due subscription.

POST /v1/billing/cycle/run

func RunBillingCycleAllOrgs

func RunBillingCycleAllOrgs(c *gin.Context)

RunBillingCycleAllOrgs iterates every organization and processes due subscriptions across all of them. This is intended for the platform scheduler to invoke on a recurring basis.

POST /v1/billing/cycle/run-all

func RunBillingCycleUser

func RunBillingCycleUser(c *gin.Context)

RunBillingCycleUser processes due subscriptions for a single user within the request's organization.

POST /v1/billing/cycle/run-user

func SetAutoRecharge

func SetAutoRecharge(c *gin.Context)

SetAutoRecharge upserts the org's auto-recharge config.

PUT /v1/billing/auto-recharge

Enabling requires a default payment method on file (the card that will be charged off-session when the balance runs low).

func SetDefaultPaymentMethod

func SetDefaultPaymentMethod(c *gin.Context)

SetDefaultPaymentMethod sets the default payment method for a customer.

POST /v1/billing/customers/:id/default-payment-method

func SetOrgTestMode

func SetOrgTestMode(c *gin.Context)

SetOrgTestMode toggles the org's live flag (org.Live) and its test-mode view. org.Live marks transactions Test=true and is the FALLBACK Square-environment signal: when the deployment does NOT set SQUARE_ENVIRONMENT, a test org uses Square sandbox and a live org uses production (via org.TestMode). When the deployment DOES set SQUARE_ENVIRONMENT (the per-env authority: mainnet=production, testnet/devnet=sandbox), that env governs which Square environment is charged regardless of this flag — on mainnet there is no sandbox charge. Admin-only — a user must not be able to move their own org to sandbox to dodge real charges.

POST /v1/billing/test-mode   { testMode: bool }

func SettleHUSD

func SettleHUSD(c *gin.Context)

SettleHUSD sweeps every org's on-chain drift back to the treasury (metered usage settled org→treasury). Platform-only, CronJob-driven. Idempotent (self-correcting drift). Returns the per-org settlement outcomes.

POST /v1/billing/husd/settle

func StatusHUSD

func StatusHUSD(c *gin.Context)

StatusHUSD reports the chain-ledger configuration + whether it is enabled — a read-only observability surface (no secrets: the treasury key is never exposed).

GET /v1/billing/husd/status

func SubmitDisputeEvidence

func SubmitDisputeEvidence(c *gin.Context)

SubmitDisputeEvidence submits evidence for a dispute.

PATCH /v1/billing/disputes/:id

func SyncHUSD

func SyncHUSD(c *gin.Context)

SyncHUSD runs one indexer pass — the backfill + reconcile safety net behind the synchronous mint-time projection. Driven by an external CronJob (mirrors the contributor-payout execute endpoint). Platform-only (touches the money ledger).

POST /v1/billing/husd/sync

func TierCheck

func TierCheck(c *gin.Context)

TierCheck is a lightweight endpoint for model-access gating. It returns the tier config and whether a specific model is allowed, without computing the full balance. Used by Chat and white-label services.

GET /v1/billing/tier-check?user=hanzo/alice&model=zen4-max

func TokenizeCard

func TokenizeCard(c *gin.Context)

TokenizeCard accepts raw card data server-side and returns a provider token. Raw PAN is never stored; it is forwarded directly to the configured payment provider and discarded.

Card tokenization should be done client-side using the Square Web Payments SDK. This endpoint returns 503 as server-side tokenization requires PCI DSS Level 1 compliance. Use the Square Web Payments SDK (SqPaymentForm) instead.

POST /v1/billing/card/tokenize

func Topup

func Topup(c *gin.Context)

Topup charges a saved payment method and credits the user's balance.

POST /v1/billing/topup

Body: { userId, paymentMethodId, amountCents, currency? } Returns: { transactionId, balanceCents, status }

func TopupWithToken

func TopupWithToken(c *gin.Context)

TopupWithToken charges a Square Web Payments SDK nonce and credits the org's canonical balance. Use this for one-time card top-ups without saving a payment method first — the cold-customer "add credits" path.

POST /v1/billing/topup/token

Body: { sourceId, amountCents, currency? } Header (optional): X-Idempotency-Key — a retry/double-submit with the same key (or, absent a key, the same single-use nonce) never double-charges or double-credits; it replays the first result. Returns: { transactionId, balanceCents, status }

func UnbindAccountProject

func UnbindAccountProject(c *gin.Context)

UnbindAccountProject removes a project's binding to this account (the project falls back to the org default account).

DELETE /v1/billing/accounts/:id/projects/:project

func UpcomingInvoice

func UpcomingInvoice(c *gin.Context)

UpcomingInvoice generates a preview of the next invoice for a subscription.

GET /v1/billing/invoices/upcoming?userId=...&subscriptionId=...

func UpdateBillingAccount

func UpdateBillingAccount(c *gin.Context)

UpdateBillingAccount patches an account (partial; absent fields preserved). It can PROMOTE this account to the org default (demoting the prior one) but cannot clear default — the org always has exactly one. Enabled/freeze is not settable here (platform control).

PATCH /v1/billing/accounts/:id

func UpdateBillingSubscription

func UpdateBillingSubscription(c *gin.Context)

UpdateBillingSubscription updates a subscription (plan change, quantity).

PATCH /v1/billing/subscriptions/:id

func UpdateMemberRole

func UpdateMemberRole(c *gin.Context)

UpdateMemberRole is a stub. Role updates are done via IAM.

PATCH /v1/billing/accounts/:id/members/:memberId

func UpdatePaymentMethod

func UpdatePaymentMethod(c *gin.Context)

UpdatePaymentMethod updates a payment method.

PATCH /v1/billing/payment-methods/:id

func UpdateSpendAlert

func UpdateSpendAlert(c *gin.Context)

UpdateSpendAlert patches an existing spend alert / cap. Only the fields present in the body change; the rest are preserved.

PATCH /v1/billing/spend-alerts/:id

func UpdateSubscriptionItem

func UpdateSubscriptionItem(c *gin.Context)

UpdateSubscriptionItem updates a subscription item (e.g. seat count).

PATCH /v1/billing/subscription-items/:id

func UpdateSubscriptionSchedule

func UpdateSubscriptionSchedule(c *gin.Context)

UpdateSubscriptionSchedule updates phases or end behavior.

PATCH /v1/billing/subscription-schedules/:id

func UpdateWebhookEndpoint

func UpdateWebhookEndpoint(c *gin.Context)

UpdateWebhookEndpoint updates a webhook endpoint configuration.

PATCH /v1/billing/webhook-endpoints/:id

func VoidCreditGrant

func VoidCreditGrant(c *gin.Context)

VoidCreditGrant voids a specific credit grant, making it unusable.

POST /v1/billing/credit-grants/:id/void

func VoidCreditNote

func VoidCreditNote(c *gin.Context)

VoidCreditNote voids a credit note.

POST /v1/billing/credit-notes/:id/void

func VoidInvoice

func VoidInvoice(c *gin.Context)

VoidInvoice voids a draft or open invoice.

POST /v1/billing/invoices/:id/void

func Withdraw

func Withdraw(c *gin.Context)

Withdraw creates a withdrawal transaction for an IAM user.

POST /v1/billing/withdraw

Used when a user explicitly moves funds out of their Commerce balance (e.g. funding a bot wallet, manual withdrawal). Non-admin callers may only withdraw from their own account; admin callers may withdraw on behalf of any user.

Fails with 402 if the user has insufficient available balance.

func ZapDispatch

func ZapDispatch(c *gin.Context)

ZapDispatch is the single ZAP-over-HTTP endpoint for billing.

Types

type Plan

type Plan struct {
	Slug        string
	Name        string
	Description string
	Category    string
	PriceMonth  int64
	PriceYear   int64
	Currency    string
}

Plan is the exported snapshot used by external seeders (e.g. the Stripe parity seed in commerce.go). It mirrors the subset of fields the seed populates onto seed.Plan, with field names that match the caller's expectations (PriceMonth / PriceYear are cent-denominated monthly + annual prices). Internal callers stick with staticPlan; this type exists so the public surface doesn't leak the unexported shape and so we can evolve them independently.

func LookupStaticPlan

func LookupStaticPlan(slug string) *Plan

LookupStaticPlan resolves a single plan by slug from the embedded catalog and returns it in the exported Plan shape. Returns nil when the slug is unknown. It is the single-plan analogue of StaticPlans and shares the same staticPlan -> Plan projection, so external seeders (e.g. cmd/grant) never touch the unexported wire type.

func StaticPlans

func StaticPlans() []Plan

StaticPlans returns a snapshot of the embedded plan catalog as the exported Plan shape. The slice is freshly allocated so callers may mutate freely without bleeding into the canonical hanzoPlans var.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL