Skip to content
Select themeSelect language

`GET /api/marketplace/purchases/{id}/invoices` — #1111 FUND 3: the billing history of one subscription licence, newest first.

GET
/api/marketplace/purchases/{id}/invoices
curl --request GET \
--url https://example.com/api/marketplace/purchases/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/invoices \
--cookie supacloud_session=<supacloud_session>

Workspace-scoped like the cancellation, and for the same reason: the entitlement belongs to the workspace that paid, so its billing record does too.

id
required
string format: uuid
Media typeapplication/json
Array<object>

#1111 — one row per Stripe invoice OUTCOME on a subscription purchase.

Two jobs in one row: it is the webhook idempotency key (UNIQUE (provider_invoice_id, outcome) — a replayed invoice.paid inserts nothing, so nothing is booked twice) and the per-period audit trail, linking the paid period to the seller ledger row it produced.

object
amount_minor
required
integer format: int32
created_at
required
string format: date-time
currency
required
string
id
required
string format: uuid
ledger_entry_id

The seller-earnings row this period booked. None for a failed invoice and for a platform-as-seller sale (#928 writes no payout row).

string | null format: uuid
outcome
required

paid | payment_failed.

string
period_end
string | null format: date-time
period_start
string | null format: date-time
provider_invoice_id
required
string
purchase_id
required
string format: uuid
refund_ledger_entry_id

The negative ledger row the reversal booked, if any.

string | null format: uuid
refunded_at

#1125 — set once this period was refunded. Also the idempotency guard: the reversal is applied by a CAS on refunded_at IS NULL, so Stripe’s repeated charge.refunded deliveries cannot reverse a period twice.

string | null format: date-time
refunded_minor
required

The CUMULATIVE amount Stripe last reported as refunded for this period. Stripe grows this figure across partial refunds, so the stored value is what lets a LARGER later refund extend the reversal instead of being dropped as a replay.

integer format: int32
Examplegenerated
[
{
"amount_minor": 1,
"created_at": "2026-04-15T12:00:00Z",
"currency": "example",
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"ledger_entry_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"outcome": "example",
"period_end": "2026-04-15T12:00:00Z",
"period_start": "2026-04-15T12:00:00Z",
"provider_invoice_id": "example",
"purchase_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"refund_ledger_entry_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"refunded_at": "2026-04-15T12:00:00Z",
"refunded_minor": 1
}
]

Authentication required

Media typeapplication/json

The canonical JSON body of every error response — the single source of truth the frontend binds to. Every AppError serializes as this exact shape, and the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is what the frontend error schema is generated from, so there is no hand-written error schema on either end.

object
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden license_required license_expired bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited too_many_requests quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}

Purchase belongs to another workspace

Media typeapplication/json

The canonical JSON body of every error response — the single source of truth the frontend binds to. Every AppError serializes as this exact shape, and the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is what the frontend error schema is generated from, so there is no hand-written error schema on either end.

object
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden license_required license_expired bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited too_many_requests quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}

Purchase not found

Media typeapplication/json

The canonical JSON body of every error response — the single source of truth the frontend binds to. Every AppError serializes as this exact shape, and the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is what the frontend error schema is generated from, so there is no hand-written error schema on either end.

object
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden license_required license_expired bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited too_many_requests quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}

Structured server error

Media typeapplication/json

The canonical JSON body of every error response — the single source of truth the frontend binds to. Every AppError serializes as this exact shape, and the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is what the frontend error schema is generated from, so there is no hand-written error schema on either end.

object
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden license_required license_expired bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited too_many_requests quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}