Billing & FinOps

Preview — pending review

This reference is generated from the platform API contract and is still under review. Operations, fields, and descriptions can change before publication.

Pay an open invoice

POST
/scopes/{scopeId}/billing/invoices/{invoiceId}/actions/pay

Charges the amount due for an UNPAID or OVERDUE invoice ("Pay invoice" on the invoice detail page, confirmed through the pay dialog). The charge targets the supplied payment method, or the scope's default card when paymentMethodId is omitted (the UI confirms "Charge {amount} to {brand} •••• {last4}"). On settlement the invoice transitions to PAID, a PAID event is appended to its payment timeline, and the outstanding-balance roll-up of the scope decreases by the invoice total. Validation: invoiceId must reference an invoice visible in the active scope (otherwise 404 NOT_FOUND); the invoice status must permit pay — only UNPAID or OVERDUE invoices are payable; PAID or CANCELLED invoices are rejected with 409 CONFLICT; paymentMethodId, when supplied, must reference an existing, non-expired payment method in the scope (otherwise 422 VALIDATION_FAILED); the caller must be authorized for billing commands (otherwise 403 FORBIDDEN). Async & state: Asynchronous; returns 202 with the invoice resource in its transitional state while the charge settles. Terminal outcomes: status PAID (a resource.updated SSE frame with kind: invoice, patch: {status: PAID} is emitted and a PAID timeline event is appended) or the invoice remains UNPAID/OVERDUE with a FAILED timeline event when the charge is declined. Errors: 401 unauthenticated; 403 caller lacks billing command permission; 404 unknown invoiceId in the scope; 409 invoice already PAID or CANCELLED (state does not permit pay); 422 unknown or expired payment method; 500 on payment-pipeline failure. Idempotency/Concurrency: Idempotency-Key is optional (recommended); replaying the same key returns the original 202 response and never double-charges the payment method. Concurrent pay attempts on the same invoice serialize on the invoice; the loser observes 409 CONFLICT once the first charge settles.

Authorization

bearerToken
headerAuthorizationBearer <token>

An API token (pc_live_…) or a service-account key (sak_live_…), created in Identity & Access Management and sent as Authorization: Bearer <token>. Requests are rate limited per credential and per tenant: every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a refused request gets 429 RATE_LIMITED with Retry-After.

Path Parameters

scopeId*string

Opaque ownership+authorization scope resolving to tenant + subscription + project.

invoiceId*string

Identifier of the invoice to pay.

Header Parameters

Idempotency-Key?string

Optional; recommended for safe retries. When sent, the same key+body within 24h replays the original result and the same key with a different body is 409 CONFLICT; keys are unique per tenant. When an API token or service-account (bearer) caller omits it, the request is applied once with no replay protection (a retry may apply it again). A console session gets one from the edge.

Formatuuid

Request Body

application/json
  1. body

Payment instruction for paying an invoice; the invoice is settled OFFLINE (bank transfer).

paymentMethodId?|Deprecated

Deprecated: the platform stores no cards and runs no PSP — invoice pay settles offline. This field is IGNORED and will be removed once the Payment methods UI is retired.

Response Body

Payment accepted; the invoice in its transitional state while the charge settles.

application/json
  1. response

An invoice issued for the scope, with amounts in ten-thousandths of the subscription currency's unit.

id*string
number*string
description*string
currency*CurrencyCode

ISO currency code supported by billing.

Value in"USD""EUR""TRY"
subtotal*integer

Subtotal in ten-thousandths of the currency unit.

tax*integer

Tax in ten-thousandths of the currency unit.

total*integer

Amount due in ten-thousandths of the currency unit: (subtotal − credits applied before VAT) + tax − credits applied after VAT (promotional credit comes off the net before VAT, credit from cash-funded grants settles the gross after it).

prepaid?integer

Gross (net + VAT) already paid that this invoice RECORDS -- a commitment upfront settled in its period (see InvoiceDetail.prepaidItems). It is NOT part of total (the amount due). 0 / absent when nothing was prepaid. Equals prepaidNet + prepaidTax.

prepaidNet?integer

The net of the prepaid block -- shown with the totals, never in total and never in tax (the period's usage tax excludes it).

Default0
prepaidTax?integer

The VAT already paid with the prepaid block (frozen at the charge's rate); excluded from tax and from total.

Default0
status*InvoiceStatus

Invoice settlement status.

Value in"PAID""UNPAID""OVERDUE""CANCELLED"
issuedAt*string
Formatdate-time
dueAt*string
Formatdate-time
period*string

Human-readable billing period label.

curl -X POST "https://example.com/scopes/string/billing/invoices/string/actions/pay" \  -H "Content-Type: application/json" \  -d '{}'
{  "id": "inv-2026-06",  "number": "STC-2026-1042",  "description": "Cloud services — June 2026 (current)",  "currency": "USD",  "subtotal": 0,  "tax": 0,  "total": 0,  "prepaid": 0,  "prepaidNet": 0,  "prepaidTax": 0,  "status": "PAID",  "issuedAt": "2019-08-24T14:15:22Z",  "dueAt": "2019-08-24T14:15:22Z",  "period": "June 2026 (current)"}