Project billing

These routes show how much a project consumed: the usage computed hour by hour (projects with hourly billing) and the billing entries associated with the project. To understand the payment models, see Payments and billing.

Authentication and permissions

The routes accept an organization API Key (x-api-key: znf_... or Authorization: Bearer znf_...) or a user token with x-organization-id. Both require project.billing.read on project:<project-id> (or project:*). project.metrics.read does not grant access to financial values. owner has full access.

RouteLimit
GET /v1/project/:id/billing/hourly-usage50 per minute
GET /v1/project/:id/billing/ledger50 per minute

Monetary values are numbers in BRL cents and can be fractional (up to 8 decimal places). Divide by 100 to display them in reais.

Query parameters

ParameterTypeDefaultDescription
fromISO 8601 string—Period start (inclusive)
toISO 8601 string—Period end (exclusive)
pageinteger1Page, starting at 1
limitinteger10Items per page, from 1 to 50
statusstring—Ledger only: pending or applied

Values outside these formats return 400. A project that does not exist in the organization returns 404 with Project not found.

Hourly usage

GET /v1/project/:id/billing/hourly-usage?from=2026-10-01T00:00:00Z&to=2026-10-08T00:00:00Z
{
  "status": "success",
  "message": "get project hourly usage with success",
  "data": {
    "hours": [
      {
        "id": "6702a1b2c3d4e5f6a7b8c9d0",
        "hour_start": "2026-10-07T23:00:00.000Z",
        "hour_end": "2026-10-08T00:00:00.000Z",
        "currency": "brl",
        "compute_amount": 12.5,
        "storage_amount": 0.4,
        "total_amount": 12.9,
        "compute_instance_hours": 1,
        "storage_gb_hours": 10,
        "status": "charged",
        "calculated_at": "2026-10-08T00:05:00.000Z",
        "charged_at": "2026-10-08T00:10:00.000Z"
      }
    ],
    "summary": {
      "currency": "brl",
      "compute_amount": 12.5,
      "storage_amount": 0.4,
      "total_amount": 12.9
    },
    "pagination": { "page": 1, "limit": 10, "total": 1, "total_pages": 1 }
  }
}
FieldDescription
hours[]One entry per computed hour, from newest to oldest. The period filter uses hour_start
compute_amount / storage_amount / total_amountCapacity, storage, and total amount for the hour
compute_instance_hoursInstance-hours considered for the hour
storage_gb_hoursStorage GB-hours considered for the hour
statuspending (computed, not charged yet) or charged
charged_atWhen the charge happened, if it already did
summarySum of the whole filtered period, not only the page

Projects with a monthly or yearly contract and scheduled Jobs (billed per minute) have no hourly usage: the route returns 200 with empty hours, 0 totals, and total: 0. The cost of Job runs is in Scheduled Jobs.

Billing entries

GET /v1/project/:id/billing/ledger?status=pending
{
  "status": "success",
  "message": "get project billing ledger with success",
  "data": {
    "entries": [
      {
        "id": "6702a1b2c3d4e5f6a7b8c9d1",
        "category": "usage",
        "description": "Uso computado",
        "amount": 12.5,
        "currency": "brl",
        "status": "pending",
        "occurred_at": "2026-10-08T00:05:00.000Z"
      }
    ],
    "summary": {
      "currency": "brl",
      "adjustment_amount": 0,
      "storage_amount": 0,
      "usage_amount": 12.5,
      "total_amount": 12.5
    },
    "summary_by_currency": [
      {
        "currency": "brl",
        "adjustment_amount": 0,
        "storage_amount": 0,
        "usage_amount": 12.5,
        "total_amount": 12.5
      }
    ],
    "pagination": { "page": 1, "limit": 10, "total": 1, "total_pages": 1 }
  }
}
FieldDescription
categoryusage (capacity or database usage), storage, or adjustment (balance adjustment)
descriptionDescriptive text for the entry, in Portuguese
statuspending (waiting to be applied) or applied (already applied to the balance)
occurred_atWhen the entry was recorded; the period filter uses this field
applied_atWhen the entry was applied, if it already was
summaryTotals by category for the whole filtered period. Absent when there is more than one currency; in that case, use summary_by_currency

Entries are sorted from newest to oldest.

Example

curl "https://api.zenifra.com/v1/project/6650f1a2b3c4d5e6f7a8b9c0/billing/hourly-usage?page=1&limit=24" \
  -H "x-api-key: znf_..."

Next steps

Last updated on

On this page