Cosmoner Docs
API Reference

Billing API

Manage subscriptions, invoices, payment methods, and setup intents.

Project Billing

Get Subscription Breakdown

GET /v1/projects/:projectId/billing

Returns the subscription breakdown and upcoming invoice preview. Maps subscription items to resources (servers, apps, storage, registries).

The response also includes the project's org-level credit balance (creditBalance, in minor units), which is automatically applied to upcoming invoices. This can be non-zero even when there is no active subscription.

Auth: Required (member)

Response (200):

{
  "success": true,
  "data": {
    "items": [
      {
        "product": "App — Professional-1",
        "quantity": 1,
        "unitAmount": 2400,
        "currency": "usd",
        "metered": false
      }
    ],
    "upcomingInvoice": {
      "amountDue": 2400,
      "currency": "usd",
      "periodEnd": "2025-02-25T00:00:00Z"
    },
    "creditBalance": 0
  }
}

List Invoices

GET /v1/projects/:projectId/billing/invoices

Returns the project's last 24 invoices, newest first.

Auth: Required (member)

Response:

{
  "success": true,
  "data": [
    {
      "id": "in_1234",
      "number": "DB-0001",
      "created": "2026-02-01T09:15:00.000Z",
      "amountDue": 4900,
      "currency": "USD",
      "status": "paid",
      "hostedInvoiceUrl": "https://invoice.stripe.com/i/...",
      "project": null
    }
  ]
}

This list is read from Stripe, so it covers every stage — draft, open, paid, void, uncollectible. number and hostedInvoiceUrl are null while an invoice is still a draft. project is always null here, since the route already scopes the list to one project; only the account-wide list below populates it.

List Your Invoices

GET /v1/account/invoices

Returns the last 24 invoices you have paid, newest first, with each attributed to the project it was billed for via project: { id, name }. The project name is the one it had when the invoice was paid.

This is a payment history, so it is recorded per invoice at the moment that invoice settles rather than derived from who bills for a project today:

  • Invoices stay on your list after you leave a project or hand billing to someone else.
  • Taking over billing for a project does not move that project's earlier invoices to you.
  • Only paid invoices appear. Upcoming, open, and draft invoices are on the project's own invoice list.

Auth: Required

Billing History

GET /v1/projects/:projectId/billing/history?limit=50

Returns a unified timeline of charges, proration credits, and refunds. Useful for showing users exactly what they were charged, what credits they received when removing resources, and any refunds issued.

Auth: Required (member)

Query Parameters:

ParameterTypeDefaultDescription
limitnumber50Max entries to return (capped at 100)

Response (200):

{
  "success": true,
  "data": [
    {
      "id": "il_...",
      "type": "charge",
      "description": "App — Professional-1",
      "amount": 2400,
      "currency": "USD",
      "date": "2026-05-25T00:00:00.000Z"
    },
    {
      "id": "il_...",
      "type": "credit",
      "description": "Unused time on App — Professional-1 after 10 Jun 2026",
      "amount": 1200,
      "currency": "USD",
      "date": "2026-06-10T00:00:00.000Z"
    },
    {
      "id": "re_...",
      "type": "refund",
      "description": "Credit balance refund requested by biller",
      "amount": 1176,
      "currency": "USD",
      "date": "2026-06-15T00:00:00.000Z"
    }
  ]
}

Each entry has a type field:

  • charge — a subscription charge or prorated first payment
  • credit — a proration credit from removing a resource mid-cycle
  • refund — a refund of the project's credit balance to the payment method, requested by the biller (see Refund Credit Balance); the amount is net of non-recoverable payment-processing fees

Refund Credit Balance

POST /v1/projects/:projectId/billing/credit/refund

Refunds the project's Stripe credit balance (creditBalance from the subscription-breakdown response) back to the original payment method(s) that funded it, spreading the refund across recent charges if needed. This is the general way for a biller to cash out the project's credit balance — for example after a resource removal generates a credit the biller would rather receive back than leave applied to future invoices, or before transferring billing responsibility to another member.

Cosmoner never issues this refund automatically; it only happens when a biller explicitly calls this endpoint. Our payment processor does not return its processing (transaction) fees on refunded charges — since those fees are a non-recoverable cost to us, they are deducted from the refund. amount is the amount actually refunded (credit consumed minus fees) and feeWithheld is the fee amount deducted, both in minor units. The amount refunded to the payment method is therefore less than the credit balance consumed, except where no fees apply.

If there is no credit to refund, this is a no-op and still returns 200 with refunded: false.

Auth: Required (biller)

Response (200):

{
  "success": true,
  "data": {
    "refunded": true,
    "amount": 776,
    "feeWithheld": 24,
    "currency": "USD"
  }
}

Notify the Biller

POST /v1/projects/:projectId/billing/notify-biller

Notifies the project's biller (email + in-app) that a payment method is needed. Used when a non-biller tries to deploy a resource into a project that has no card yet.

Auth: Required (member). Rate-limited to one notification per member per project per 6 hours; a repeat within the window returns 429 RATE_LIMITED. Returns 400 if the caller is the biller.


Project Payment Methods

The project's card is managed only by its biller (the pending biller of an in-flight transfer may also add a card while accepting). All resource billing charges this card.

Create Setup Intent

POST /v1/projects/:projectId/billing/setup-intent

Creates a setup intent bound to the project's Stripe customer. Confirm it in the browser to tokenise the card, then register it with the endpoint below.

Auth: Required (biller or pending biller)

Response (200): { "success": true, "data": { "clientSecret": "seti_..._secret_..." } }

List Payment Methods

GET /v1/projects/:projectId/billing/payment-methods

Returns the project's card(s) and the default payment method ID.

Auth: Required (biller)

Add / Replace Payment Method

POST /v1/projects/:projectId/billing/payment-methods

Registers a card confirmed via the setup intent. The card always becomes the project's default (so this doubles as "replace"), and its billing address is copied onto the customer for automatic tax.

Auth: Required (biller or pending biller)

Request Body: { "paymentMethodId": "pm_..." }

Set Default Payment Method

PATCH /v1/projects/:projectId/billing/payment-methods

Auth: Required (biller)

Request Body: { "paymentMethodId": "pm_..." }

Remove Payment Method

DELETE /v1/projects/:projectId/billing/payment-methods

Detaches a card. Removing the default card while a subscription is active is rejected with 409 ORG_PAYMENT_METHOD_IN_USE — add a replacement first.

Auth: Required (biller)

Request Body: { "paymentMethodId": "pm_..." }


Deploy Payment Errors

Resource-create endpoints (servers, apps, databases, storage, etc.) bill the project card off-session and return { "success": true, "data": { "deployed": true } } on success. When payment can't proceed they return 402 with a machine-readable code:

CodeMeaning
ORG_PAYMENT_METHOD_REQUIREDThe project has no card and the caller is the biller — add one and retry.
BILLER_PAYMENT_METHOD_REQUIREDThe project has no card and the caller is not the biller. error.details carries { billerUserId, billerName, billerEmail }.
ORG_BILLING_ADDRESS_REQUIREDAutomatic tax could not resolve the billing address — re-add the card with a full address.
PAYMENT_REQUIREDThe card was declined, or the subscription is past due.

Deprecated: Account-level Payment Methods

The following user-level endpoints are deprecated now that billing runs on the project card, and cards are no longer collected at signup. They remain for one release for historical access; new integrations should use the project payment-method endpoints above.

  • GET /v1/stripe/payment-methods, POST/PATCH/DELETE /v1/stripe/payment-methods
  • POST /v1/stripe/setup-intent (now requires authentication; the pre-signup, unauthenticated path was removed)
  • GET /v1/stripe/invoices — lists invoices on the user-level Stripe customer. Nothing has been billed to that customer since billing moved to the project, so this returns an empty list for accounts created after the move. Use GET /v1/account/invoices instead.

Auth: Required

On this page