Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.lumina-org.com/llms.txt

Use this file to discover all available pages before exploring further.

When something goes wrong, the API returns a JSON envelope:
{ "error": "machine_code", "message": "human-readable explanation", "code": "machine_code" }
The SDK maps non-2xx HTTP responses into LuminaError with .status, .code, .message. Use the code field for branching; the message is for logs / UI surfacing.

HTTP envelope

CodeMeaningTypical action
400Invalid request shapeCheck the request body against the OpenAPI schema
401Missing / invalid API keyVerify x-api-key header is present and valid (lk_...)
403Forbidden — rate limit, sandbox cap, or 2FA requiredReduce request rate; check x-ratelimit-* headers
404Resource not foundVerify the productId / policyId / epochId exists
409Idempotency conflictUse a fresh Idempotency-Key for new requests
422Validation errorCheck coverageAmount is within product limits
429Rate limitHonour the Retry-After header
500Server errorRetry with exponential backoff
503Service unavailable (RPC down, oracle stale, sequencer down)Retry after 30s

Application-level codes

The code field on the JSON envelope is one of:
codeHTTPCauseResolution
invalid_product404productId not in catalogueUse GET /products to list valid IDs
product_inactive422productActive[pid] === false on PolicyManagerV2Wait for re-activation or choose another product
coverage_below_minimum422coverageAmount < 100e6 ($100)Minimum is 100000000 base units USDC
coverage_above_maximum422Coverage exceeds BondVault available capacityReduce coverage or wait for capacity
sandbox_disabled503SANDBOX_WALLET not configured on the API serverUse full onboarding path
sandbox_cap_exceeded403$100 sandbox cap exhausted for the caller IPWait for the hourly window to reset (10/h/IP) or onboard
rate_limit429Caller exceeded the per-key RPM allowanceSlow down; honour Retry-After
idempotency_conflict409Same Idempotency-Key with a different bodyGenerate a fresh UUIDv4 for genuinely new requests
health_contracts_incomplete500/health.contracts missing a required keyServer-side; retry or report
chain_not_found503RPC provider returned no resultTransient — retry with backoff
not_authorized_relayer403Caller is not in the relayer allowlistDirect callers should use purchasePolicy, not purchasePolicyFor

On-chain reverts (surfaced verbatim from the contracts)

These come back inside the message field when a transaction reverts. The SDK preserves the raw revert reason; below is the catalogue of strings you may see and what they mean.

CoverRouterV2

ReasonCauseResolution
ContractPausedCoverRouterV2.paused == true OR GlobalPauseRegistry.isPaused()Wait for unpause
SEQUENCER_DOWNBase L2 sequencer uptime feed reports down or within 1h grace periodWait for sequencer recovery + grace
ProductNotConfigured(productId)Product not registered in CoverRouterUse a productId from GET /products
ProductInactive(productId)products[pid].active == falseChoose a different product
InvalidCoverage(amount)coverageAmount < 100_000_000 (less than $100 in 6-dec USDC)Min cover is $100 base units
NotAuthorizedRelayer(addr)Caller is not in the relayer allowlistDirect path purchasePolicy doesn’t need allowlist

BaseFlashShield / FlashBTC/ETHShield

ReasonCauseResolution
NOT_ROUTERmsg.sender is not the FlashShieldAdapter wired into this shieldAlways go through the adapter (PolicyManagerV2 routes for you)
SEQUENCER_DOWNBase L2 sequencer down OR in grace periodWait + retry
ORACLE_INVALIDChainlink answer <= 0Transient oracle outage; retry
ORACLE_STALEChainlink block.timestamp - updatedAt > MAX_PRICE_STALENESS (1h)Wait for next oracle update
POLICY_EXISTSAdapter tried to create a policy with an already-used idBug — open an issue
INVALID_WINDOWexpiresAt <= startTimestampBug — open an issue
WINDOW_MISMATCHAdapter passed duration != shield._window()Bug — open an issue
POLICY_NOT_FOUNDverifyAndCalculate called for an id that doesn’t existBug or stale policyId
ALREADY_FINALIZEDTrigger was already evaluated for this policyA policy can only fire (or not) once
WINDOW_EXPIREDblock.timestamp > policy.expiresAt on trigger attemptPolicy expired without firing — premium stays burned

BondVault

ReasonCauseResolution
Exceeds capacitytotalCommittedUSD + payoutUSD > vault maxCapacity full; wait or scale down coverage
Only PolicyManagerCaller is not PolicyManagerV2Always go through PolicyManager
Zero payoutTrigger tried to issue a $0 bondBug — check coverage rounding
Not maturedredeemBond() called before maturity (730 days)Wait until block.timestamp >= maturityTimestamp
Insufficient bondsCaller doesn’t hold enough ERC-1155 of that epochCheck claimBond.balanceOf(caller, epochId)
Price too lowLUMINA price < MIN_REDEEM_PRICE ($0.001)Wait for price recovery — circuit breaker
Insufficient reserveVault LUMINA balance < computed payoutWait — should be transient
When a redemption would exceed the 1.08% per-epoch throttle, the bond is BURNED IMMEDIATELY and added to the FIFO queue for the next epoch (no revert). The user gets a BondQueued event back; LUMINA pays out when processQueue() is called against the target epoch. See BondVault throttle for the full queue lifecycle.

LuminaBondMarketplace

ReasonCauseResolution
InsufficientListingValueListing total below the anti-spam floor (audit fix M-3)Increase totalPriceUsdc or amount
NotMaturedListing duration outside allowed rangeAdjust the listing window
NotBondOwnerCaller doesn’t own the bond being listedVerify ownership via ClaimBond ERC-1155
ListingNotFoundBuying a listingId that’s already filled or cancelledRefresh the listing book

LuminaTokenV2

ReasonCauseResolution
ERC20InsufficientBalanceBuyer USDC balance < premiumTop up
ERC20InsufficientAllowanceApproval to CoverRouter < premiumApprove at least the quoted premium

Retry strategy

For transient errors (HTTP 5xx, ORACLE_STALE, SEQUENCER_DOWN, chain_not_found):
  • Initial retry after 1s
  • Exponential backoff: 1s, 2s, 4s, 8s, 16s, 32s
  • Max 6 retries (~63s total wall clock)
  • Honour Retry-After headers when present
For permanent errors (HTTP 4xx except 429, on-chain reverts other than ORACLE_STALE / SEQUENCER_DOWN):
  • Do not retry
  • Surface the code + message to your user with a clear next step

Webhook delivery

When the API can’t deliver a webhook (3xx / 4xx / 5xx / timeout):
  • Retry schedule: 1m, 5m, 30m, 2h, 12h, 24h (6 attempts)
  • After the 6 attempts, the webhook is marked undeliverable
  • Re-enable via POST /api/v1/webhooks/{id}/retry
  • Each delivery carries an HMAC signature in X-Lumina-Signature — reject any payload that fails verification