Skip to content

Settle a lease

The leases.settle operation: POST /api/v1/leases/{id}/settle in the REST API and the leases_settle tool in the MCP server.

POST/api/v1/leases/{id}/settle

Charges what your service consumed from a lease since the previous settle (consumed), with a usageSummary: one line per meter (and attribute set) with the quantity used and its amount; the amounts add up to consumed. Each line is stored as a usage event and counted in the daily usage aggregates. The settle is charged at once (the lease's captured grows); the ledger books what a lease's settles charged as usage revenue per meter in one posting, when the lease closes, is renewed or expires. Wallet usage can't use a meter that a metered price bills in arrears (prepaid and arrears usage coexist on different meters).

Then the lease:

  • stays open (neither final nor renew): keep consuming its remaining;
  • closes (final: true): what it still holds goes back to the wallet;
  • is renewed (renew): it closes, and a new lease with a new ID, a fresh TTL and the same expiry terms is reserved, for renew.amount (default: the same amount) or as much of it as the wallet has. renewedLease is null when the wallet can't fund it.

A settle after expiresAt gets lease_expired, except within the late-settle window of a hold_for_late_settle lease: that settle charges consumed and closes the lease (late: true).

Ordering and retries: a resent settle (same Idempotency-Key and content) is answered with duplicate: true and changes nothing. Optionally number your settles with settleSeq (the lease's settleSeq plus one): a numbered settle is applied only after the one before it (lease_settle_out_of_order, retryable, otherwise), so a final settle can't overtake earlier usage, and a settle numbered at or below the lease's settleSeq is a duplicate. Every response has the lease's suggestedNextAmount.

At a glance

  • REST: POST /api/v1/leases/{id}/settle
  • MCP tool: leases_settle
  • Operation ID: leases.settle
  • Scope: Brand
  • Permission: wallets:write
  • Risk tier: write
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the wallets:write scope
  • Since: M6

Request

Path parameters

FieldTypeDescription
idlease_… IDThe lease (lease_…).

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
consumedobjectYesWhat was used since the previous settle of this lease, in its currency; at most what it still holds.
consumed.amountstringYesInteger micros as a string (5000000 = 5.00); finer than a cent is fine.
consumed.currencystringYesISO 4217 currency code: the wallet's currency.
usageSummaryarray of objectNoUp to 100 lines, one per meter (and attribute set), whose amounts add up to consumed. Each is stored as a usage event.
usageSummary[].meterstringYesThe meter this usage counts toward, e.g. api.calls. Not a meter a metered price bills in arrears.
usageSummary[].quantitystring or integer (at least 0)YesHow much of the meter was used, in its unit, as an integer string (e.g. "1200" calls).
usageSummary[].amountobjectYesWhat this usage cost, in the wallet's currency.
usageSummary[].amount.amountstringYesInteger micros as a string (5000000 = 5.00); finer than a cent is fine.
usageSummary[].amount.currencystringYesISO 4217 currency code: the wallet's currency.
usageSummary[].attributesobjectNoOptional dimensions of the event, e.g. { "model": "large" }; usage is aggregated per day and attribute set.
finalbooleanNotrue: close the lease; what it still holds goes back to the wallet.
renewobjectNoClose this lease and continue in a new one (new ID, fresh TTL, same expiry terms). Send {} to keep the amount and TTL.
renew.amountobjectNoThe new lease's amount (default: this lease's amount).
renew.amount.amountstringYesInteger micros as a string (5000000 = 5.00); finer than a cent is fine.
renew.amount.currencystringYesISO 4217 currency code: the wallet's currency.
renew.ttlSecondsinteger (1 to 900)NoThe new lease's TTL (default: this lease's TTL).
settleSeqinteger (at least 1)NoOptional: this settle's number, the lease's settleSeq plus one. Numbered settles are applied in order, and a resent one is answered as a duplicate.

Response

200 OK with a JSON object:

FieldTypeDescription
object"lease_settlement"
settleSeqinteger (at least 1)This settle's number on the lease.
duplicatebooleantrue: this settle had been applied before (resent, or numbered at or below the lease's settleSeq); nothing changed now, and lease is the lease as it is now.
latebooleanSettled after expiresAt, inside the late-settle window; it closed the lease.
consumedmoneyWhat this settle captured.
leaseobjectThe settled lease.
lease.idlease_… ID
lease.object"lease"
lease.brandIdbrd_… ID
lease.livemodeboolean
lease.walletIdwal_… ID
lease.statusone of active, expired_pending, captured, released, expiredactive: settle against it. expired_pending: past its TTL, held for a late settle until lateSettleUntil. captured: closed by a settle (final or a renewal). expired: closed by its expiry policy.
lease.amountmoneyHow much was leased.
lease.capturedmoneyHow much the settles (and an expiry capture) have charged so far. The ledger books it as usage revenue when the lease closes, is renewed or expires.
lease.remainingmoneyWhat can still be consumed: amount − captured while the lease is open, 0 once it is closed.
lease.ttlSecondsinteger (1 to 900)
lease.expiresAtdate-timeSettle before this instant; then the expiry policy applies.
lease.expiryPolicyone of release, capture, hold_for_late_settle
lease.lateSettleWindowSecondsinteger or nullhold_for_late_settle only.
lease.lateSettleFallbackone of release, capture or nullhold_for_late_settle only.
lease.lateSettleUntildate-time or nullhold_for_late_settle only: a settle is accepted until this instant (expiresAt + window).
lease.settleSeqinteger (at least 0)How many settles the lease has had.
lease.renewedFromlease_… ID or nullThe lease this one renewed.
lease.renewedTolease_… ID or nullThe lease a renewing settle replaced this one with.
lease.suggestedNextAmountmoneySizing guidance for the next lease (or renewal) of this TTL, from the recent consumption rate with 25% headroom.
lease.metadataobject
lease.createdAtdate-time
lease.closedAtdate-time or null
renewedLeaseobject or nullThe new lease of a renewal. null without renew, after a late settle, or when the wallet couldn't fund it (frozen, or no spendable credits); its amount may be less than asked when the wallet had less.
usageEventIdsarray of uev_… IDThe usage events, one per usage summary line.

Examples

Settle usage of two meters and keep the lease

HTTP
POST /api/v1/leases/lease_01m4v0d9k2j7r5t3w8x6y4z2b0/settle
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "consumed": {
    "amount": "1250000",
    "currency": "EUR"
  },
  "usageSummary": [
    {
      "meter": "api.calls",
      "quantity": "1000",
      "amount": {
        "amount": "1000000",
        "currency": "EUR"
      },
      "attributes": {
        "model": "large"
      }
    },
    {
      "meter": "tokens.out",
      "quantity": "25000",
      "amount": {
        "amount": "250000",
        "currency": "EUR"
      }
    }
  ],
  "settleSeq": 1
}

Response (200):

JSON
{
  "object": "lease_settlement",
  "settleSeq": 1,
  "duplicate": false,
  "late": false,
  "consumed": {
    "amount": "1250000",
    "currency": "EUR"
  },
  "lease": {
    "id": "lease_01m4v0d9k2j7r5t3w8x6y4z2b0",
    "object": "lease",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "livemode": false,
    "walletId": "wal_01m4ty3c2b5qx7mhd9k8w6s0b1",
    "status": "active",
    "amount": {
      "amount": "5000000",
      "currency": "EUR"
    },
    "captured": {
      "amount": "1250000",
      "currency": "EUR"
    },
    "remaining": {
      "amount": "3750000",
      "currency": "EUR"
    },
    "ttlSeconds": 300,
    "expiresAt": "2026-10-13T12:05:00.000Z",
    "expiryPolicy": "release",
    "lateSettleWindowSeconds": null,
    "lateSettleFallback": null,
    "lateSettleUntil": null,
    "settleSeq": 1,
    "renewedFrom": null,
    "renewedTo": null,
    "suggestedNextAmount": {
      "amount": "7812500",
      "currency": "EUR"
    },
    "metadata": {
      "worker": "api-eu-1"
    },
    "createdAt": "2026-10-13T12:00:00.000Z",
    "closedAt": null
  },
  "renewedLease": null,
  "usageEventIds": ["uev_01m4v0d9k2j7r5t3w8x6y4z2b2", "uev_01m4v0d9k2j7r5t3w8x6y4z2b3"]
}

Settle and renew before the TTL

The lease closes and a new 5.00 lease continues with a fresh TTL.

HTTP
POST /api/v1/leases/lease_01m4v0d9k2j7r5t3w8x6y4z2b0/settle
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "consumed": {
    "amount": "3500000",
    "currency": "EUR"
  },
  "usageSummary": [
    {
      "meter": "api.calls",
      "quantity": "3500",
      "amount": {
        "amount": "3500000",
        "currency": "EUR"
      }
    }
  ],
  "renew": {},
  "settleSeq": 2
}

Response (200):

JSON
{
  "object": "lease_settlement",
  "settleSeq": 2,
  "duplicate": false,
  "late": false,
  "consumed": {
    "amount": "3500000",
    "currency": "EUR"
  },
  "lease": {
    "id": "lease_01m4v0d9k2j7r5t3w8x6y4z2b0",
    "object": "lease",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "livemode": false,
    "walletId": "wal_01m4ty3c2b5qx7mhd9k8w6s0b1",
    "status": "captured",
    "amount": {
      "amount": "5000000",
      "currency": "EUR"
    },
    "captured": {
      "amount": "4750000",
      "currency": "EUR"
    },
    "remaining": {
      "amount": "0",
      "currency": "EUR"
    },
    "ttlSeconds": 300,
    "expiresAt": "2026-10-13T12:05:00.000Z",
    "expiryPolicy": "release",
    "lateSettleWindowSeconds": null,
    "lateSettleFallback": null,
    "lateSettleUntil": null,
    "settleSeq": 2,
    "renewedFrom": null,
    "renewedTo": "lease_01m4v0d9k2j7r5t3w8x6y4z2b1",
    "suggestedNextAmount": {
      "amount": "7421875",
      "currency": "EUR"
    },
    "metadata": {
      "worker": "api-eu-1"
    },
    "createdAt": "2026-10-13T12:00:00.000Z",
    "closedAt": "2026-10-13T12:04:00.000Z"
  },
  "renewedLease": {
    "id": "lease_01m4v0d9k2j7r5t3w8x6y4z2b1",
    "object": "lease",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "livemode": false,
    "walletId": "wal_01m4ty3c2b5qx7mhd9k8w6s0b1",
    "status": "active",
    "amount": {
      "amount": "5000000",
      "currency": "EUR"
    },
    "captured": {
      "amount": "0",
      "currency": "EUR"
    },
    "remaining": {
      "amount": "5000000",
      "currency": "EUR"
    },
    "ttlSeconds": 300,
    "expiresAt": "2026-10-13T12:09:00.000Z",
    "expiryPolicy": "release",
    "lateSettleWindowSeconds": null,
    "lateSettleFallback": null,
    "lateSettleUntil": null,
    "settleSeq": 0,
    "renewedFrom": "lease_01m4v0d9k2j7r5t3w8x6y4z2b0",
    "renewedTo": null,
    "suggestedNextAmount": {
      "amount": "7421875",
      "currency": "EUR"
    },
    "metadata": {
      "worker": "api-eu-1"
    },
    "createdAt": "2026-10-13T12:04:00.000Z",
    "closedAt": null
  },
  "usageEventIds": ["uev_01m4v0d9k2j7r5t3w8x6y4z2b2"]
}

Close the lease

HTTP
POST /api/v1/leases/lease_01m4v0d9k2j7r5t3w8x6y4z2b0/settle
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "consumed": {
    "amount": "0",
    "currency": "EUR"
  },
  "usageSummary": [],
  "final": true
}

Response (200):

JSON
{
  "object": "lease_settlement",
  "settleSeq": 1,
  "duplicate": false,
  "late": false,
  "consumed": {
    "amount": "0",
    "currency": "EUR"
  },
  "lease": {
    "id": "lease_01m4v0d9k2j7r5t3w8x6y4z2b0",
    "object": "lease",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "livemode": false,
    "walletId": "wal_01m4ty3c2b5qx7mhd9k8w6s0b1",
    "status": "captured",
    "amount": {
      "amount": "5000000",
      "currency": "EUR"
    },
    "captured": {
      "amount": "0",
      "currency": "EUR"
    },
    "remaining": {
      "amount": "0",
      "currency": "EUR"
    },
    "ttlSeconds": 300,
    "expiresAt": "2026-10-13T12:05:00.000Z",
    "expiryPolicy": "release",
    "lateSettleWindowSeconds": null,
    "lateSettleFallback": null,
    "lateSettleUntil": null,
    "settleSeq": 1,
    "renewedFrom": null,
    "renewedTo": null,
    "suggestedNextAmount": {
      "amount": "500000",
      "currency": "EUR"
    },
    "metadata": {
      "worker": "api-eu-1"
    },
    "createdAt": "2026-10-13T12:00:00.000Z",
    "closedAt": "2026-10-13T12:01:00.000Z"
  },
  "renewedLease": null,
  "usageEventIds": []
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400A field is malformed, or a settle asks for both final and renew.Fix the fields listed in details.issues and send the request again.
lease_usage_mismatch400The amounts of the usageSummary lines don't add up to consumed.Make the amounts of the usageSummary lines add up to consumed exactly (details.consumed, details.usageTotal, integer micros), in the lease's currency.
capture_exceeds_reservation400consumed is more than the lease still holds (remaining).Capture at most the reserved amount that is still open (details.outstanding, integer micros), or reserve more first.
wallet_currency_mismatch400consumed isn't in the lease's currency.Use the wallet for this currency. A customer has one wallet per currency (details.expected, details.actual).
usage_meter_billed_in_arrears400A line names a meter a metered price bills in arrears.Report prepaid (wallet) usage on a meter that no metered price names, e.g. api.calls.prepaid (details.meter).
resource_not_found404No lease with this ID in the brand and mode.Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
lease_expired409The lease is past expiresAt (and past lateSettleUntil for hold_for_late_settle).Create a new lease for further usage. To settle usage after a crash, make leases with the expiry policy hold_for_late_settle, which accepts a settle until lateSettleUntil.
lease_closed409A final settle or a renewal already closed the lease (details.renewedTo names its successor).Settle the lease it was renewed into (details.renewedTo), or create a new lease. A lease closes with a final settle or a renewal.
lease_settle_out_of_order409settleSeq skips a settle that hasn't arrived yet (retryable).Send the settles of a lease in order, one at a time: settleSeq must be the lease's settleSeq plus one (details.expected). Retry once the earlier settle has been applied.
lease_settle_seq_conflict409The lease's last settle has this settleSeq but other content.Give each settle of a lease the next number (details.settleSeq is the lease's current one) and resend a settle only unchanged.
idempotency_key_reused409The Idempotency-Key was already used for a different settle of this lease.Use a new Idempotency-Key for a different request, or resend the original request unchanged.
permission_denied403The credentials can't use this brand's wallets (wallets:write).Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, idempotency_key_required, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.