Skip to content

feat(billing): Add one-off invoice protos - #463

Draft
volokluev wants to merge 2 commits into
mainfrom
feat/billing-one-off-invoice-protos
Draft

volokluev wants to merge 2 commits into
mainfrom
feat/billing-one-off-invoice-protos

Conversation

@volokluev

@volokluev volokluev commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Adds the proto surface for one-off invoices: invoices the billing platform bills to an organization outside of any contract, charged immediately.

  • InvoiceKind and Invoice.kind. INVOICE_KIND_UNSPECIFIED covers invoices written before kinds existed, which are all contract invoices, so consumers only need to test for INVOICE_KIND_ONE_OFF.
  • Invoice.idempotency_key: caller-supplied key that makes one-off creation safe to retry. It is unique per organization and client_id.
  • Invoice.client_id: names the service that requested a one-off invoice. Each service picks its own idempotency keys, so a key only means something together with the client that chose it.
  • InvoiceLineItem.external_id: the caller's own identifier for a line. Kept separate from type so callers can bill for new products without platform enum changes, and so platform code that reads meaning into type prefixes never sees caller values.
  • OneOffInvoiceUpdated event (EventPayload field 8) with PAID / CLOSED_UNPAID / REFUNDED outcomes, invoice-level amounts only. It carries client_id and idempotency_key: a handler acts only on events with its own client_id and uses the key to find its own transaction.

All additions; no existing fields change.

Consumed by the getsentry stack below; those PRs can't pass CI until this is released and pinned in sentry.

Stack (each getsentry PR is based on the one above it; G1 is based on master):

PR Change
P1 (this PR) #463 Protos: InvoiceKind, Invoice.kind/idempotency_key, InvoiceLineItem.external_id, OneOffInvoiceUpdated
S1 not opened yet Bump sentry-protos in sentry once P1 is released
G1 getsentry/getsentry#22446 Migration: kind, idempotency_key, external_id columns
G2 getsentry/getsentry#22447 Migration (post-deploy): unique index on (organization_id, idempotency_key)
G3 getsentry/getsentry#22448 Contract plumbing: kind=CONTRACT, proto mapping, shared item builder
G4 getsentry/getsentry#22449 ContractService.create_one_off_invoice
G5 getsentry/getsentry#22450 OneOffInvoiceUpdated events
G6 getsentry/getsentry#22451 Invoicer: no account-status writes, metric kind tag, PDF disclaimer
G7 getsentry/getsentry#22452 InvoicerService.bill_one_off_invoice + option
G8 getsentry/getsentry#22453 Admin invoice comparison excludes one-offs

Add InvoiceKind, Invoice.kind, Invoice.idempotency_key and
InvoiceLineItem.external_id so the billing platform can bill an
organization outside of a contract, and a OneOffInvoiceUpdated event so
the requesting service learns when such an invoice is paid, closed
unpaid or refunded.
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow ci / buf-checks (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedOct 9, 2026, 10:51 PM

Identify the service that requested a one-off invoice on the Invoice and
on OneOffInvoiceUpdated, so a handler can recognize its own invoices and
map idempotency_key back to its records.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant