<!-- x-generated: Generated by the Hyperscale artifact pipeline; do not edit by hand -->

# Policy

> Carrier-backed protection over one declared-value subject.

A policy quotes protection over one subject, binds after a carrier decision, activates at its declared start, and expires at term. Premium remains refundable while bound but not active; activation pays the insurer and opens the policy to claims.

- Instrument id: `policy`
- Initial state: `quoted`
- Terminal states: `canceled`, `expired`
- Composed by: [asset_backed_membership](../programs/asset_backed_membership.md), [dream_trip_packages](../programs/dream_trip_packages.md), [embedded_asset_protection](../programs/embedded_asset_protection.md), [insured_travel_marketplace](../programs/insured_travel_marketplace.md), [luxury_goods_consignment_escrow](../programs/luxury_goods_consignment_escrow.md), [parametric_travel_insurance](../programs/parametric_travel_insurance.md)

## Lifecycle

The diagram draws only the transitions a composing Product exposes as an action. A cell reading "no step any Product exposes" means no drawn edge enters or leaves that state, so the move belongs to a lifecycle step none of the composing Products exposes. Terminal states read "none" under Left by, because stopping there is the declared design rather than a missing step. Where an unexposed step carries a price it is listed under Steps no Product exposes, below.

```mermaid
stateDiagram-v2
    [*] --> quoted: create
    quoted --> bound: bind
    canceled --> [*]
    expired --> [*]
```

| State | Kind | Entered by | Left by |
| --- | --- | --- | --- |
| `quoted` | initial | create | bind |
| `bound` | intermediate | bind | no step any Product exposes |
| `active` | intermediate | no step any Product exposes | no step any Product exposes |
| `cancel_quoted` | intermediate | no step any Product exposes | no step any Product exposes |
| `canceled` | terminal | no step any Product exposes | none |
| `expired` | terminal | no step any Product exposes | none |

## Fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `premiumAmount` | money<SAR> (minor_unit_integer_string) | yes | Positive minor-unit integer amount serialized as a string (at most 18 digits) |
| `coverageLimit` | money<SAR> (minor_unit_integer_string) | yes | Positive minor-unit integer amount serialized as a string (at most 18 digits) |
| `currency` | text | yes | ISO 4217 currency code |
| `startsAt` | datetime | yes |  |
| `expiresAt` | datetime | yes |  |
| `perilSchedule` | array<object{peril, limitAmount, deductibleBps, waitingPeriodDays}> | yes |  |
| `termsSummary` | text | no |  |

## References

- `policyholderAccountId`: `account`, required
- `insurerAccountId`: `account`, required
- `renewalOfPolicyId`: `policy`, optional

## Actions

### bind

Asks the carrier to accept the risk, then moves the premium into its dedicated reserve until cover starts.

- From: `quoted`
- To: `bound`
- Hints: readOnly=false, destructive=false, idempotent=true, moneyMovement=true
- Handle key: `policyId`

Exposed as:

| Program | Public action | Route |
| --- | --- | --- |
| [asset_backed_membership](../programs/asset_backed_membership.md) | `bindAssetProtection` | `POST /v1/operations/policy.bindAssetProtection`, scopes policy:write, transfer:write, idempotency required, receipt yes |
| [dream_trip_packages](../programs/dream_trip_packages.md) | `bindTripProtection` | `POST /v1/operations/policy.bindTripProtection`, scopes policy:write, transfer:write, idempotency required, receipt yes |
| [embedded_asset_protection](../programs/embedded_asset_protection.md) | `attachAssetCoverage` | `POST /v1/operations/policy.attachAssetCoverage`, scopes policy:write, transfer:write, idempotency required, receipt yes |
| [insured_travel_marketplace](../programs/insured_travel_marketplace.md) | `bindTripProtection` | `POST /v1/operations/policy.bindTripProtection`, scopes policy:write, transfer:write, idempotency required, receipt yes |
| [luxury_goods_consignment_escrow](../programs/luxury_goods_consignment_escrow.md) | `bindSaleProtection` | `POST /v1/operations/policy.bindSaleProtection`, scopes policy:write, transfer:write, idempotency required, receipt yes |
| [parametric_travel_insurance](../programs/parametric_travel_insurance.md) | `bindTravelPolicy` | `POST /v1/operations/policy.bindTravelPolicy`, scopes policy:write, transfer:write, idempotency required, receipt yes |

Input:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `policyId` | ref<policy> | yes | Policy instance ID |

Effects:

- decides:
  - `decides.insurance_carrier` from `decision`
- moves:
  - `moves.transfer.internal` from `moves[0]`

Errors beyond the 53 shared with every action on this instrument:

| Code | HTTP | Cause | Action | Remediation | Retryable | Idempotency safe |
| --- | --- | --- | --- | --- | --- | --- |
| `account_frozen` | 409 | The account is frozen. Debits always refuse while frozen; some freezes also refuse credits. The error message carries the only reason wording Hyperscale exposes. | Use a different account for this transfer leg, or have the freeze lifted before retrying. | Unfreeze the account through its lifecycle surface if you imposed the freeze; a freeze you cannot lift was imposed by the platform and clears only when the platform lifts it. | no | yes |
| `destination_account_status_forbidden` | 400 | The destination (credit) account is not open. It is frozen or closed, so Hyperscale will not credit it. | Use a destination account whose status is `open`, or unfreeze the intended account, before retrying. | Read the account status, unfreeze it (or select an open account in the same currency and product), then resend the transfer. | no | yes |
| `instrument_decision_declined` | 409 | The request contradicts the resource the platform has already durably recorded (`instrument decision declined`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `instrument_decision_timeout` | 409 | The request contradicts the resource the platform has already durably recorded (`instrument decision timeout`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `instrument_instance_not_found` | 404 | No Instrument instance matches the `instrumentInstanceId` this request referenced (`instrument instance not found`). | List Instrument instances in the same tenant, product, and environment, then retry with the `instrumentInstanceId` that read returns. | Create or select the Instrument instance in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `invalid_instrument_transition` | 409 | The request contradicts the resource the platform has already durably recorded (`invalid instrument transition`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `source_account_status_forbidden` | 400 | The source (debit) account is not open. It is frozen or closed, so Hyperscale will not debit it. | Use a source account whose status is `open`, or unfreeze the intended account, before retrying. | Read the account status, unfreeze it (or select an open account in the same currency and product), then resend the transfer. | no | yes |
| `source_operation_not_found` | 404 | No resource matches the `id` this request referenced (`source operation not found`). | List the collection this request referenced in the same tenant, product, and environment, then retry with an `id` that listing returns. | Create or select the resource in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `transfer_destination_role_forbidden` | 400 | The submitted value is not one this resource accepts (`transfer destination role forbidden`). | Replace the rejected value with one this resource allows, as listed in the API reference or set by product policy. | Rebuild the request from the generated SDK types for this resource, which carry the allowed values as unions rather than free strings. | no | yes |
| `transfer_lineage_conflict` | 409 | The request contradicts the resource the platform has already durably recorded (`transfer lineage conflict`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `transfer_not_found` | 404 | No resource matches the `id` this request referenced (`transfer not found`). | List the collection this request referenced in the same tenant, product, and environment, then retry with an `id` that listing returns. | Create or select the resource in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `transfer_role_pair_forbidden` | 400 | The submitted value is not one this resource accepts (`transfer role pair forbidden`). | Replace the rejected value with one this resource allows, as listed in the API reference or set by product policy. | Rebuild the request from the generated SDK types for this resource, which carry the allowed values as unions rather than free strings. | no | yes |
| `transfer_source_role_forbidden` | 400 | The submitted value is not one this resource accepts (`transfer source role forbidden`). | Replace the rejected value with one this resource allows, as listed in the API reference or set by product policy. | Rebuild the request from the generated SDK types for this resource, which carry the allowed values as unions rather than free strings. | no | yes |
| `transfer_status_forbidden` | 409 | The transfer is not in the state this operation requires (for example, posting needs a reserved transfer; returning or reversing needs a posted one). The current and required states are described in the error message. | Read the transfer's current status and call the operation that is valid for that status. | Follow the transfer lifecycle (reserve → post, then return/reverse) and issue the operation matching the transfer's current state instead of the rejected one. | no | yes |

### create

Creates a quote against one declared-value risk and provisions the premium reserve. No premium moves until the carrier binds.

- From: none
- To: no state change
- Hints: readOnly=false, destructive=false, idempotent=true, moneyMovement=false

Exposed as:

| Program | Public action | Route |
| --- | --- | --- |
| [asset_backed_membership](../programs/asset_backed_membership.md) | `quoteAssetProtection` | `POST /v1/operations/policy.quoteAssetProtection`, scopes policy:write, idempotency required, receipt yes |
| [dream_trip_packages](../programs/dream_trip_packages.md) | `quoteTripProtection` | `POST /v1/operations/policy.quoteTripProtection`, scopes policy:write, idempotency required, receipt yes |
| [embedded_asset_protection](../programs/embedded_asset_protection.md) | `quoteAssetCoverage` | `POST /v1/operations/policy.quoteAssetCoverage`, scopes policy:write, idempotency required, receipt yes |
| [insured_travel_marketplace](../programs/insured_travel_marketplace.md) | `quoteTripProtection` | `POST /v1/operations/policy.quoteTripProtection`, scopes policy:write, idempotency required, receipt yes |
| [luxury_goods_consignment_escrow](../programs/luxury_goods_consignment_escrow.md) | `quoteSaleProtection` | `POST /v1/operations/policy.quoteSaleProtection`, scopes policy:write, idempotency required, receipt yes |
| [parametric_travel_insurance](../programs/parametric_travel_insurance.md) | `quoteTravelPolicy` | `POST /v1/operations/policy.quoteTravelPolicy`, scopes policy:write, idempotency required, receipt yes |

Input:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `policyholderAccountId` | ref<account> | yes | Hyperscale account ID |
| `insurerAccountId` | ref<account> | yes | Hyperscale account ID |
| `premiumAmount` | money<SAR> (minor_unit_integer_string) | yes | Positive minor-unit integer amount serialized as a string (at most 18 digits) |
| `coverageLimit` | money<SAR> (minor_unit_integer_string) | yes | Positive minor-unit integer amount serialized as a string (at most 18 digits) |
| `currency` | text | yes | ISO 4217 currency code |
| `startsAt` | datetime | yes |  |
| `expiresAt` | datetime | yes |  |
| `perilSchedule` | array<object{peril, limitAmount, deductibleBps, waitingPeriodDays}> | yes |  |
| `renewalOfPolicyId` | ref<policy> | no | Prior policy this quote renews; the prior term must be active or already expired |
| `termsSummary` | text | no |  |
| `subject` | text | yes | ID of an existing subject created with Product operation; its registered kind must be one of: policy_risk, flight_itinerary, lodging_stay, vehicle, merchandise, pet, traveler_party, employee_census. Discover registered kinds and their attribute schemas with Product operation. |

Effects:

- reads:
  - `reads.requires_refs` from `requiresRefs`

Errors beyond the 53 shared with every action on this instrument:

| Code | HTTP | Cause | Action | Remediation | Retryable | Idempotency safe |
| --- | --- | --- | --- | --- | --- | --- |
| `financial_address_write_failed` | 500 | The platform could not durably complete the `financial address write failed` step, so the Financial address may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the Financial address was written. | Treat the Financial address's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `instrument_reference_not_found` | 404 | No resource matches the `id` this request referenced (`instrument reference not found`). | List the collection this request referenced in the same tenant, product, and environment, then retry with an `id` that listing returns. | Create or select the resource in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `instrument_reference_required` | 409 | The request contradicts the resource the platform has already durably recorded (`instrument reference required`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `instrument_reference_status_forbidden` | 409 | The resource's current lifecycle state does not allow this transition (`instrument reference status forbidden`). | Read the resource this request referenced and pick the lifecycle operation its current status allows. | Apply a transition the resource's current status permits. The reference itself is still valid, so no new resource is needed. | no | yes |
| `instrument_retired` | 409 | The request contradicts the resource the platform has already durably recorded (`instrument retired`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `instrument_subject_kind_forbidden` | 409 | The request contradicts the resource the platform has already durably recorded (`instrument subject kind forbidden`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `instrument_subject_not_found` | 409 | No resource matches the `id` this request referenced (`instrument subject not found`). | List the collection this request referenced in the same tenant, product, and environment, then retry with an `id` that listing returns. | Create or select the resource in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `kyc_tier_insufficient` | 403 | Opening an account of this role requires the owning customer's entity to have ATTAINED a KYC tier it has not reached: either required fields are missing or the profile is not verified. | Complete and verify the entity's KYC profile to the tier this account role requires, then retry. The error details name the required tier and the entity's attained tier. | Submit the missing fields (`entity.kyc.submit`), run verification (`entity.kyc.verification.start`), and once the outcome is verified at the required tier the account open succeeds unchanged. `entity.kyc.retrieve` shows exactly which fields stand between the entity and the required tier. | no | yes |

## Steps no Product exposes

The cost table prices 5 lifecycle steps that no Product in this catalog exposes as an action, so none of them is callable through a Product API. They run inside the instrument. The IR carries only their price, so price is all this page can state about them.

### activate

| Action | Effect | Meter | Rate | Table version |
| --- | --- | --- | --- | --- |
| `activate` | `moves.transfer.internal` | `transfer.internal.volume_sar` | 75+11bps | 2026-09-02.1 |
| `activate` | `schedules.due` | `instrument.event.count` | 0 | 2026-09-02.1 |

### cancel

| Action | Effect | Meter | Rate | Table version |
| --- | --- | --- | --- | --- |
| `cancel` | `moves.transfer.internal` | `transfer.internal.volume_sar` | 75+11bps | 2026-09-02.1 |

### endorse

| Action | Effect | Meter | Rate | Table version |
| --- | --- | --- | --- | --- |
| `endorse` | `decides.insurance_carrier` | `instrument.event.count` | 0 | 2026-09-02.1 |

### expire

| Action | Effect | Meter | Rate | Table version |
| --- | --- | --- | --- | --- |
| `expire` | `schedules.due` | `instrument.event.count` | 0 | 2026-09-02.1 |

### preview

| Action | Effect | Meter | Rate | Table version |
| --- | --- | --- | --- | --- |
| `preview` | `holds.quote` | `instrument.event.count` | 0 | 2026-09-02.1 |
| `preview` | `schedules.expiry` | `instrument.event.count` | 0 | 2026-09-02.1 |

## Reads

- `policy.list` as `policy_list`: List policies
  - Route: `GET /v1/policies`, scopes policy:read, idempotency not_required, receipt yes
  - Output: items, nextCursor, statusCounts
- `policy.retrieve` as `policy_retrieve`: Retrieve a policy
  - Route: `GET /v1/policies/{policyId}`, scopes policy:read, idempotency not_required, receipt yes
  - Output: policyId, tenantId, productId, instrumentId, status, fields, refs, createdAt, updatedAt

## Cost

| Action | Effect | Meter | Rate | Table version |
| --- | --- | --- | --- | --- |
| `activate` | `moves.transfer.internal` | `transfer.internal.volume_sar` | 75+11bps | 2026-09-02.1 |
| `activate` | `schedules.due` | `instrument.event.count` | 0 | 2026-09-02.1 |
| `bind` | `decides.insurance_carrier` | `instrument.event.count` | 0 | 2026-09-02.1 |
| `bind` | `moves.transfer.internal` | `transfer.internal.volume_sar` | 75+11bps | 2026-09-02.1 |
| `cancel` | `moves.transfer.internal` | `transfer.internal.volume_sar` | 75+11bps | 2026-09-02.1 |
| `create` | `reads.requires_refs` | `instrument.event.count` | 0 | 2026-09-02.1 |
| `endorse` | `decides.insurance_carrier` | `instrument.event.count` | 0 | 2026-09-02.1 |
| `expire` | `schedules.due` | `instrument.event.count` | 0 | 2026-09-02.1 |
| `preview` | `holds.quote` | `instrument.event.count` | 0 | 2026-09-02.1 |
| `preview` | `schedules.expiry` | `instrument.event.count` | 0 | 2026-09-02.1 |

## Errors on every action

The 53 errors every action on this instrument declares. An action's own section lists only what it adds beyond these.

| Code | HTTP | Cause | Action | Remediation | Retryable | Idempotency safe |
| --- | --- | --- | --- | --- | --- | --- |
| `account_ledger_mapping_conflict` | 409 | The request contradicts the Account the platform has already durably recorded (`account ledger mapping conflict`). | Re-read the Account with `account.retrieve` and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the Account as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `account_not_found` | 404 | No Account matches the `accountId` this request referenced (`account not found`). | List Accounts in the same tenant, product, and environment, then retry with the `accountId` that read returns. | Create or select the Account in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `cross_tenant_transfer_forbidden` | 409 | The request contradicts the resource the platform has already durably recorded (`cross tenant transfer forbidden`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `currency_invalid` | 500 | The platform could not durably complete the `currency invalid` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `currency_mismatch` | 400 | The currency on the request does not match the settlement currency of the account or transfer it targets. Hyperscale never converts between currencies, so the two must be identical. | Read the target account's currency (for example with `account.balance.retrieve`) and resend with that same currency and a minor-unit amount denominated in it. | This is deterministic. Retrying with the same currency fails identically. Correct the request's currency field, or move the money through an account already denominated in the required currency, then retry. | no | yes |
| `customer_access_compliance_forbidden` | 403 | The request contradicts the Customer access the platform has already durably recorded (`customer access compliance forbidden`). | Re-read the Customer access with `customer_access.retrieve` and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the Customer access as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `customer_access_required` | 403 | The operation cannot run against this Customer access until the `customer access required` prerequisite exists. | Supply the field, capability, evidence, or configuration the error details name for this Customer access, then call the operation again. | Complete the prerequisite through the surface that owns it -- the operation reference for this Customer access names it -- and the same call then succeeds unchanged. | no | yes |
| `customer_not_found` | 404 | No Customer matches the `customerId` this request referenced (`customer not found`). | List Customers in the same tenant, product, and environment, then retry with the `customerId` that read returns. | Create or select the Customer in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `customer_status_forbidden` | 403 | The Customer's current lifecycle state does not allow this transition (`customer status forbidden`). | Read the Customer with `customer.retrieve` and pick the lifecycle operation its current status allows. | Apply a transition the Customer's current status permits. The reference itself is still valid, so no new Customer is needed. | no | yes |
| `entity_not_found` | 404 | No Entity matches the `entityId` this request referenced (`entity not found`). | List Entities in the same tenant, product, and environment, then retry with the `entityId` that read returns. | Create or select the Entity in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `entity_status_forbidden` | 403 | The Entity's current lifecycle state does not allow this transition (`entity status forbidden`). | Read the Entity with `entity.retrieve` and pick the lifecycle operation its current status allows. | Apply a transition the Entity's current status permits. The reference itself is still valid, so no new Entity is needed. | no | yes |
| `insufficient_balance` | 409 | The source (debit) account's available balance is below the transfer amount, so the ledger refused the transfer. No money moved. The transfer was not created and its charge/transfer rows are recorded as failed. | Fund the source (debit) account so its available balance in minor units covers the full amount, or lower the amount, then retry. Confirm the shortfall first with `account.balance.retrieve`. | This is a definitive refusal, not a transient failure: replaying the exact request with the same Idempotency-Key safely returns this same refusal and never double-charges, so rotating to a fresh key is not the fix. Funding is. Top up the source account (or reduce the amount), then submit the transfer as a new request. | no | yes |
| `invalid_credentials` | 401 | Hyperscale could not accept the account or credential request. Signup, login, and bearer authentication use one 401 for every case they reject, so the response exposes no credential-specific reason or registered-email verdict. The single exception is a key that is real but homed in the other environment: because the presented secret already matched a stored key, the message names the mismatch instead of leaving a working credential looking unknown. | For signup or login, re-check the submitted account details. For API calls, re-check the `Authorization: Bearer <key>` API key and whether it matches the target environment (sandbox vs live). | For signup, verify the submitted details or use login or password reset for an existing account. For login, re-enter the credentials or reset the password. For API or MCP calls, use an active key for the target environment, set HYPERSCALE_API_KEY, and retry. When the message reports an environment mismatch, `details.keyEnvironment` names where the key does work: send that environment's key, or set `X-Hyperscale-Environment` to it. | no | yes |
| `ledger_account_rejected` | 500 | The platform could not durably complete the `ledger account rejected` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_account_result_missing` | 500 | The platform could not durably complete the `ledger account result missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_address_missing` | 500 | The platform could not durably complete the `ledger address missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_amount_invalid` | 500 | The platform could not durably complete the `ledger amount invalid` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_cluster_id_invalid` | 500 | The platform could not durably complete the `ledger cluster id invalid` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_cluster_id_missing` | 500 | The platform could not durably complete the `ledger cluster id missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_confirmation_mismatch` | 500 | The platform could not durably complete the `ledger confirmation mismatch` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_effect_missing` | 500 | The platform could not durably complete the `ledger effect missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_effect_not_declared` | 500 | The platform could not durably complete the `ledger effect not declared` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_evidence_missing` | 500 | The platform could not durably complete the `ledger evidence missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_linked_transfer_chain_open` | 500 | The platform could not durably complete the `ledger linked transfer chain open` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_lookup_confirmation_mismatch` | 500 | The platform could not durably complete the `ledger lookup confirmation mismatch` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_mapping_missing` | 500 | The platform could not durably complete the `ledger mapping missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_pending_transfer_id_missing` | 500 | The platform could not durably complete the `ledger pending transfer id missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_timeout_invalid` | 500 | The platform could not durably complete the `ledger timeout invalid` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_timeout_phase_invalid` | 500 | The platform could not durably complete the `ledger timeout phase invalid` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_transfer_lookup_conflict` | 500 | The platform could not durably complete the `ledger transfer lookup conflict` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_transfer_lookup_request_missing` | 500 | The platform could not durably complete the `ledger transfer lookup request missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_transfer_rejected` | 409 | The request contradicts the resource the platform has already durably recorded (`ledger transfer rejected`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `ledger_transfer_result_count_mismatch` | 500 | The platform could not durably complete the `ledger transfer result count mismatch` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_transfer_result_missing` | 500 | The platform could not durably complete the `ledger transfer result missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `ledger_unavailable` | 503 | The platform could not durably complete the `ledger unavailable` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | yes | no |
| `local_evidence_output_key_missing` | 500 | The platform could not durably complete the `local evidence output key missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `local_evidence_reference_missing` | 500 | The platform could not durably complete the `local evidence reference missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `local_evidence_resource_missing` | 500 | The platform could not durably complete the `local evidence resource missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `mfa_verification_required` | 403 | This tenant surface requires a session that completed TOTP at login. Tenant operations demand it while the organization's require-MFA policy (tenant.security.configure) is on; user.mfa.totp.disable demands it unconditionally, because removing a factor is the act that factor exists to guard. | Enroll and confirm a TOTP factor (user.mfa.totp.enrollment.begin, then user.mfa.totp.enrollment.confirm), then log in again and complete user.login.mfa.verify before retrying. | MFA verification is a mint-time session fact, so enrolling a factor mid-session never upgrades the current session. After the factor is active, a fresh login returns an MFA challenge; completing it mints the verified session this surface demands. Identity self-operations (logout, TOTP enrollment) stay open to a password-only session, so a factorless member is never locked out of enrolling. Disabling a factor is the exception: sign in again and complete the challenge first. | no | yes |
| `operation_insert_failed` | 500 | The platform could not durably complete the `operation insert failed` step, so the Operation may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the Operation was written. | Treat the Operation's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `operation_not_finalized` | 409 | The request contradicts the Operation the platform has already durably recorded (`operation not finalized`). | Re-read the Operation with `operation.retrieve` and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the Operation as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `product_not_found` | 404 | No Product matches the `productId` this request referenced (`product not found`). | List Products in the same tenant, product, and environment, then retry with the `productId` that read returns. | Create or select the Product in the environment the call runs against; ids never carry across tenants, or across sandbox and live. | no | yes |
| `session_expired` | 401 | The operation refused the request on its `session expired` contract condition. | Read the error details, then the operation reference for this resource, before retrying. | Correct the request against the generated SDK models and a fresh read of the resource; if the shape is already right, the product may be missing the capability this operation needs. | no | yes |
| `session_required` | 401 | The operation cannot run against this resource until the `session required` prerequisite exists. | Supply the field, capability, evidence, or configuration the error details name for this resource, then call the operation again. | Complete the prerequisite through the surface that owns it -- the operation reference for this resource names it -- and the same call then succeeds unchanged. | no | yes |
| `session_revoked` | 401 | The operation refused the request on its `session revoked` contract condition. | Read the error details, then the operation reference for this resource, before retrying. | Correct the request against the generated SDK models and a fresh read of the resource; if the shape is already right, the product may be missing the capability this operation needs. | no | yes |
| `tenant_code_invalid` | 500 | The platform could not durably complete the `tenant code invalid` step, so the Company may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the Company was written. | Treat the Company's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `tenant_code_missing` | 500 | The platform could not durably complete the `tenant code missing` step, so the Company may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the Company was written. | Treat the Company's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `usage_amount_missing` | 500 | The platform could not durably complete the `usage amount missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `usage_currency_mismatch` | 500 | The platform could not durably complete the `usage currency mismatch` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `usage_meter_missing` | 500 | The platform could not durably complete the `usage meter missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `usage_source_conflict` | 409 | The request contradicts the resource the platform has already durably recorded (`usage source conflict`). | Re-read the resource this request referenced and compare the submitted ids, currency, product, tenant, and expected state against what comes back. | Rebuild the request from the resource as it now stands, then retry under a NEW idempotency key -- reuse the original key only when you are deliberately replaying the original mutation. | no | yes |
| `usage_tenant_missing` | 500 | The platform could not durably complete the `usage tenant missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
| `usage_transfer_missing` | 500 | The platform could not durably complete the `usage transfer missing` step, so the resource may or may not have been written. | Capture the request id and the receipt or operation id before retrying or escalating; do not re-send under a fresh key until you know whether the resource was written. | Treat the resource's side effects as unknown unless a terminal receipt says otherwise; retry only operations documented as retryable, and replay them with the SAME idempotency key. | no | no |
