{"openapi":"3.1.0","info":{"title":"Luckotto API","version":"1","description":"LUCKOTTO-1 public and authenticated account API. The server validates every success body and every documented operation error before returning it."},"servers":[{"url":"https://luckotto.com/api","description":"Production (Bitcoin mainnet, real funds)"},{"url":"http://localhost:4000/api","description":"Local development"}],"tags":[{"name":"System"},{"name":"Rounds"},{"name":"Partners"},{"name":"Account"},{"name":"Deposit addresses"},{"name":"Deposits"},{"name":"Tickets"}],"paths":{"/chain-tip":{"get":{"operationId":"getChainTip","tags":["System"],"summary":"Get scanner chain tip","description":"Returns the latest Bitcoin block height processed by Luckotto's scanner. External workers can compare this height with deposit confirmed block heights from deposit events and apply their own confirmation threshold.","responses":{"200":{"description":"The latest scanner-processed chain tip, or nulls before the first scan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChainTip"}}}},"400":{"description":"`invalid_request` — The request path, query string, headers, or body are invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/constants":{"get":{"operationId":"getConstants","tags":["System"],"summary":"Get API constants","description":"Returns public project and runtime constants used by API clients and workers, including the deposit account xpub, fixed prize shortfall cap, draw-allocation scale, current fees, and round timing settings.","responses":{"200":{"description":"Public project and runtime constants.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Constants"}}}},"400":{"description":"`invalid_request` — The request path, query string, headers, or body are invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds":{"get":{"operationId":"listRounds","tags":["Rounds"],"summary":"List rounds","description":"Lists public Luckotto rounds with metadata and draw proof fields. Set sort to asc or desc, then pass nextCursor as cursor with the same sort. hasNext tells whether another page exists now.","parameters":[{"name":"sort","in":"query","required":false,"description":"Round-number order. Defaults to desc. Keep the same value when following nextCursor.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"cursor","in":"query","required":false,"description":"Exclusive page cursor from the previous response's nextCursor.","schema":{"type":"integer","minimum":0,"maximum":2147483648},"example":1},{"name":"limit","in":"query","required":false,"description":"Maximum items to return. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500},"example":100}],"responses":{"200":{"description":"A cursor page of public rounds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundList"}}}},"400":{"description":"`invalid_request` — sort is invalid, cursor is malformed, limit is outside 1-500, or an unsupported query parameter is present.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds/current":{"get":{"operationId":"getCurrentRound","tags":["Rounds"],"summary":"Get current round","description":"Returns the current round accepting new tickets without changing lifecycle state. Use expectedRoundNumber when a later purchase must remain in this round.","responses":{"200":{"description":"The public round currently accepting tickets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Round"}}}},"400":{"description":"`invalid_request` — The request path, query string, headers, or body are invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"503":{"description":"`service_unavailable` — No ticket-sale round is currently available; the lifecycle worker must restore the invariant.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["service_unavailable"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds/{roundNumber}":{"get":{"operationId":"getRound","tags":["Rounds"],"summary":"Get round","description":"Returns one public Luckotto round with metadata and draw proof fields.","parameters":[{"name":"roundNumber","in":"path","required":true,"description":"Round number.","schema":{"type":"integer","minimum":1,"maximum":2147483647},"example":3}],"responses":{"200":{"description":"The requested public round.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundDetail"}}}},"400":{"description":"`invalid_request` — roundNumber is not a positive integer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — The round does not exist.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds/{roundNumber}/manifest":{"get":{"operationId":"getRoundManifest","tags":["Rounds"],"summary":"Get committed round manifest","description":"Returns the exact canonical LUCKOTTO-1 manifest bytes committed by the round. The bytes become available when the round locks and never change.","parameters":[{"name":"roundNumber","in":"path","required":true,"description":"Round number.","schema":{"type":"integer","minimum":1,"maximum":2147483647},"example":3}],"responses":{"200":{"description":"The canonical committed round manifest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundManifest"}}},"headers":{"ETag":{"description":"Validator for the manifest bytes and secret-publication state.","schema":{"type":"string","minLength":1}},"X-Luckotto-Round-Manifest-SHA256":{"description":"Plain SHA-256 committed on chain.","schema":{"type":"string","pattern":"^[0-9a-f]{64}$"}},"X-Luckotto-Round":{"description":"Round represented by the manifest.","schema":{"type":"integer","minimum":1,"maximum":2147483647}},"X-Luckotto-Round-Manifest-Status":{"description":"Manifest byte finality marker.","schema":{"type":"string","const":"final"}},"X-Luckotto-Round-Secret-Hash":{"description":"Tagged SHA-256 of the round secret.","schema":{"type":"string","pattern":"^[0-9a-f]{64}$"}},"X-Luckotto-Round-Secret":{"description":"Round secret after its scheduled publication.","schema":{"type":"string","pattern":"^[0-9a-f]{64}$"}}}},"304":{"description":"The representation matches If-None-Match; the response is empty."},"400":{"description":"`invalid_request` — roundNumber is not a positive integer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — The round does not exist or has not sealed its manifest yet.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds/{roundNumber}/partners":{"get":{"operationId":"listRoundPartners","tags":["Rounds"],"summary":"List round partners","description":"Lists every partner that bought funded tickets in the round, with its aggregate contribution, ticket count, desired prize, and potential prize.","parameters":[{"name":"roundNumber","in":"path","required":true,"description":"Round number.","schema":{"type":"integer","minimum":1,"maximum":2147483647},"example":3}],"responses":{"200":{"description":"All participating partners in the requested round.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundPartnerList"}}}},"400":{"description":"`invalid_request` — roundNumber is not a positive integer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — The round does not exist.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds/{roundNumber}/partners/{partnerPayoutAddress}/manifest":{"get":{"operationId":"getRoundPartnerReceiptManifest","tags":["Rounds"],"summary":"Get partner receipt manifest","description":"Streams one partner's receipt manifest from immutable ticket data after the round seals. Its exact bytes are committed by the partner's round-manifest entry; its contents and availability are not LUCKOTTO-1 validity rules.","parameters":[{"name":"roundNumber","in":"path","required":true,"description":"Round number.","schema":{"type":"integer","minimum":1,"maximum":2147483647},"example":3},{"name":"partnerPayoutAddress","in":"path","required":true,"description":"Full participating-partner Luckotto payout address.","schema":{"type":"string","minLength":14,"maxLength":128},"example":"tb1pkpswdsh4gskkf397hrnnzy0gvxftkh2phzed8fcczufhawxfurts9782tk"}],"responses":{"200":{"description":"The generated partner receipt manifest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerReceiptManifest"}}},"headers":{"X-Luckotto-Round":{"description":"Round represented by the manifest.","schema":{"type":"integer","minimum":1,"maximum":2147483647}}}},"400":{"description":"`invalid_request` — roundNumber is not a positive integer.\n\n`invalid_request` — partnerPayoutAddress is not a valid Bitcoin address for this network.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — The round is not sealed, the partner did not participate, or the partner was deleted.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds/{roundNumber}/partners/{partnerPayoutAddress}":{"get":{"operationId":"getRoundPartner","tags":["Rounds"],"summary":"Get round partner","description":"Returns one participating partner's aggregate contribution, ticket count, desired prize, and potential prize in the round.","parameters":[{"name":"roundNumber","in":"path","required":true,"description":"Round number.","schema":{"type":"integer","minimum":1,"maximum":2147483647},"example":3},{"name":"partnerPayoutAddress","in":"path","required":true,"description":"Full participating-partner Luckotto payout address.","schema":{"type":"string","minLength":14,"maxLength":128},"example":"tb1pkpswdsh4gskkf397hrnnzy0gvxftkh2phzed8fcczufhawxfurts9782tk"}],"responses":{"200":{"description":"The requested partner's round participation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundPartner"}}}},"400":{"description":"`invalid_request` — roundNumber is not a positive integer.\n\n`invalid_request` — partnerPayoutAddress is not a valid Bitcoin address for this network.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — The round does not exist or the partner did not participate in it.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/rounds/{roundNumber}/vdf":{"get":{"operationId":"getRoundVdf","tags":["Rounds"],"summary":"Get the canonical VDF solution","description":"Returns the round manifest hash, current draw block, and verified one-shot VDF solution. Superseded solutions remain in the internal append-only database history but are not publicly exposed.","parameters":[{"name":"roundNumber","in":"path","required":true,"description":"Round number.","schema":{"type":"integer","minimum":1,"maximum":2147483647},"example":3}],"responses":{"200":{"description":"The round's current canonical VDF solution, if available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundVdfSolution"}}}},"400":{"description":"`invalid_request` — roundNumber is not a positive integer.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — The round does not exist.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}},"post":{"operationId":"submitRoundVdf","tags":["Rounds"],"summary":"Submit a VDF solution","description":"Publicly races one strictly verified solution for the round manifest hash, draw block, and manifest iteration count. Core verifies the LUCKOTTO-1 Chia proof, hashes the canonical output, and records its own acceptance time and solve duration. Public proof verification is serialized across the service, so concurrent attempts receive HTTP 429 instead of waiting; a valid partner Bearer key can use the trusted overflow rate bucket but is not required. Core's trusted evaluator uses the same verifier and append-only persistence rules directly without depending on this HTTP route.","parameters":[{"name":"roundNumber","in":"path","required":true,"description":"Round number.","schema":{"type":"integer","minimum":1,"maximum":2147483647},"example":3}],"requestBody":{"required":true,"description":"Exactly one VDF solution; the body is limited to 24 KiB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitVdfSolutionRequest"},"example":{"drawBlockHash":"0000000000000000000000000000000000000000000000000000000000000000","output":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","witnessType":0,"proof":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}}},"responses":{"200":{"description":"The accepted canonical solution and reveal state. New acceptance and idempotent replay both return 200; status distinguishes them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VdfSubmissionResult"}}}},"400":{"description":"`invalid_request` — The body is not a valid solution object or drawBlockHash is malformed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — The round does not exist.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"409":{"description":"`solution_not_ready` — The round has not sealed a manifest and iteration count yet.\n\n`stale_draw_block` — drawBlockHash is no longer the round's canonical draw block.\n\n`solution_conflict` — A different valid output is already stored for this draw block.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["solution_not_ready","stale_draw_block","solution_conflict"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"413":{"description":"`invalid_request` — The request body exceeds 24 KiB.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"415":{"description":"`invalid_request` — Content-Type is not application/json.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"422":{"description":"`invalid_solution` — The proof fails strict LUCKOTTO-1 verification.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_solution"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"429":{"description":"`rate_limited` — The per-round verification rate bucket is exhausted or another public proof is already being verified.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["rate_limited"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"503":{"description":"`service_unavailable` — The VDF verifier is temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["service_unavailable"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/partners":{"get":{"operationId":"listPublicPartners","tags":["Partners"],"summary":"List directory partners","description":"Returns the public partner directory: partners presented by display name. Partners outside the directory still exist and are presented by payout address on round and ticket surfaces.","responses":{"200":{"description":"Public directory partners.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPartnerList"}}}},"400":{"description":"`invalid_request` — The request path, query string, headers, or body are invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/partners/{partnerPayoutAddress}":{"get":{"operationId":"getPublicPartner","tags":["Partners"],"summary":"Get public partner","description":"Returns public directory details for one verified partner.","parameters":[{"name":"partnerPayoutAddress","in":"path","required":true,"description":"Full partner Luckotto payout address.","schema":{"type":"string","minLength":14,"maxLength":128},"example":"tb1pkpswdsh4gskkf397hrnnzy0gvxftkh2phzed8fcczufhawxfurts9782tk"}],"responses":{"200":{"description":"The public partner.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPartner"}}}},"400":{"description":"`invalid_request` — partnerPayoutAddress is not a valid Bitcoin address for this network.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — No verified public partner has this payout address.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/account":{"get":{"operationId":"getAccount","tags":["Account"],"summary":"Get account","description":"Returns the authenticated account's Luckotto payout address, creation time, desired prize, and available balance. The public deposit xpub is available from /api/constants.","security":[{"partnerApiKey":[]}],"responses":{"200":{"description":"The authenticated account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"400":{"description":"`invalid_request` — The request path, query string, headers, or body are invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/account/deposit-addresses":{"get":{"operationId":"listAccountDepositAddresses","tags":["Deposit addresses"],"summary":"List deposit addresses","description":"Lists deposit addresses for the authenticated account. Sort defaults to desc; pass nextCursor as cursor with the same sort. hasNext tells whether another page exists now.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"sort","in":"query","required":false,"description":"Allocation order. Defaults to desc. Keep the same value when following nextCursor.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"cursor","in":"query","required":false,"description":"Exclusive page cursor from the previous response's nextCursor.","schema":{"type":"integer","minimum":-1,"maximum":2147483648},"example":10},{"name":"limit","in":"query","required":false,"description":"Maximum items to return. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500},"example":100}],"responses":{"200":{"description":"A page of deposit addresses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepositAddressList"}}}},"400":{"description":"`invalid_request` — sort is invalid, cursor is malformed, limit is outside 1-500, or an unsupported query parameter is present.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/account/deposit-addresses/{id}":{"put":{"operationId":"putAccountDepositAddress","tags":["Deposit addresses"],"summary":"Create deposit address","description":"Creates a Bitcoin deposit address for the authenticated account at the UUIDv4 id in the path. Private address metadata is free-form; optional autoTicket metadata becomes public on generated tickets.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Deposit address UUIDv4 idempotency key.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"example":"018f58d2-2800-4000-8000-000000000456"}],"requestBody":{"required":true,"description":"Private metadata and optional auto-ticket configuration. Each metadata object has a 4096-byte canonical JSON limit; the complete JSON request body is limited to 16384 bytes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutDepositAddressRequest"},"example":{"metadata":{"customerId":"new-customer-456","source":"checkout"},"autoTicket":{"expression":"net_amount * 0.75","metadata":{"source":"automatic-deposit"}}}}}},"responses":{"200":{"description":"The created deposit address. Retrying an identical request with the same id returns the original address.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepositAddress"}}}},"400":{"description":"`invalid_request` — The path id is not a UUIDv4, the body is not valid JSON, metadata exceeds 4096 canonical JSON bytes, or autoTicket.expression is not a valid expression.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"409":{"description":"`idempotency_conflict` — id already exists with different metadata or autoTicket configuration. Retrying with the exact original fields returns the original address.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["idempotency_conflict"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"413":{"description":"`invalid_request` — The request body exceeds 16384 bytes.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"415":{"description":"`invalid_request` — Content-Type is not application/json.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"429":{"description":"`rate_limited` — The authenticated account's deposit-address creation rate bucket is exhausted.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["rate_limited"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}},"get":{"operationId":"getAccountDepositAddress","tags":["Deposit addresses"],"summary":"Get deposit address by idempotency key","description":"Returns one private deposit address for the authenticated account by UUIDv4 idempotency key. Use /api/account/deposits with its depositAddress filter for current per-outpoint state.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Deposit address UUIDv4 idempotency key.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"example":"018f58d2-2800-4000-8000-000000000456"}],"responses":{"200":{"description":"The private partner-owned deposit address.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepositAddress"}}}},"400":{"description":"`invalid_request` — id is not a UUIDv4.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — No deposit address with this id belongs to the partner.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/account/deposits":{"get":{"operationId":"listAccountDeposits","tags":["Deposits"],"summary":"List current deposits","description":"Lists the current reduced state of deposit outpoints owned by the authenticated account. Sort defaults to desc; pass nextCursor as cursor with the same sort. Filter by depositAddress for checkout or order status.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"sort","in":"query","required":false,"description":"Deposit id order. Defaults to desc. Keep the same value when following nextCursor.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"cursor","in":"query","required":false,"description":"Exclusive page cursor from the previous response's nextCursor.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"example":"018f58d2-2800-7000-8000-000000000120"},{"name":"limit","in":"query","required":false,"description":"Maximum items to return. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500},"example":100},{"name":"depositAddress","in":"query","required":false,"description":"Filter to one full deposit address.","schema":{"type":"string","minLength":14,"maxLength":128},"example":"tb1pafjzr7fs3tyal6l3l6ad5784fzmafvshrg7q4u535fjewhl9utvsn65th3"}],"responses":{"200":{"description":"A cursor page of current deposit states.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDepositList"}}}},"400":{"description":"`invalid_request` — sort is invalid, cursor is malformed, limit is outside 1-500, or an unsupported query parameter is present.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/account/deposit-events":{"get":{"operationId":"listAccountDepositEvents","tags":["Deposits"],"summary":"List deposit events","description":"Lists immutable deposit lifecycle and reversible deposit-only accounting events for the authenticated account. Sort defaults to asc; pass nextCursor as cursor with the same sort. hasNext tells whether another page exists now. Use credited events as Luckotto balance-credit events, watch uncredited/reorged_out events as reversals, and apply your own confirmation threshold with /api/chain-tip before treating a payment as final.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"sort","in":"query","required":false,"description":"Event id order. Defaults to asc. Keep the same value when following nextCursor.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"cursor","in":"query","required":false,"description":"Exclusive page cursor from the previous response's nextCursor.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"example":"018f58d2-2800-7000-8000-000000000120"},{"name":"limit","in":"query","required":false,"description":"Maximum items to return. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500},"example":100},{"name":"depositAddress","in":"query","required":false,"description":"Filter to one full deposit address.","schema":{"type":"string","minLength":14,"maxLength":128},"example":"tb1pt3sz9gp9s2gdewr36j8x22m0qqqqqqqqqqqqqqqqqqqqqqqqqpe6z4a"},{"name":"depositTxid","in":"query","required":false,"description":"Filter to one Bitcoin transaction id.","schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"example":"0000000000000000000000000000000000000000000000000000000000000000"},{"name":"depositVout","in":"query","required":false,"description":"Filter to one Bitcoin transaction output index.","schema":{"type":"integer","minimum":0,"maximum":9007199254740991},"example":0},{"name":"type","in":"query","required":false,"description":"Filter to one deposit lifecycle or accounting event type.","schema":{"type":"string","enum":["mempool_seen","mempool_dropped","confirmed","reorged_out","credited","uncredited"]},"example":"credited"}],"responses":{"200":{"description":"A cursor page of deposit events.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepositEventList"}}}},"400":{"description":"`invalid_request` — sort is invalid, or a cursor, limit, or filter parameter is malformed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/account/tickets":{"get":{"operationId":"listAccountTickets","tags":["Tickets"],"summary":"List tickets","description":"Lists tickets owned by the authenticated account. Ticket UUIDs and metadata are public; this view additionally includes createdAt and ticketFeeSats. Sort defaults to desc; pass nextCursor as cursor with the same sort.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"sort","in":"query","required":false,"description":"Direction for roundNumber:ticketId ordering. Defaults to desc. Keep the same value when following nextCursor.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"cursor","in":"query","required":false,"description":"Exclusive page cursor from the previous response's nextCursor.","schema":{"type":"string","pattern":"^[0-9]+:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"},"example":"3:018f58d2-2800-4000-8000-000000000123"},{"name":"limit","in":"query","required":false,"description":"Maximum items to return. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500},"example":100},{"name":"roundNumber","in":"query","required":false,"description":"Filter to one round number.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991},"example":3}],"responses":{"200":{"description":"A cursor page of partner-owned tickets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketList"}}}},"400":{"description":"`invalid_request` — sort is invalid, cursor is malformed, limit is outside 1-500, or an unsupported query parameter is present.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/account/tickets/{id}":{"get":{"operationId":"getAccountTicket","tags":["Tickets"],"summary":"Get ticket by ID","description":"Returns one ticket owned by the authenticated account by its public UUIDv4 identity. This response includes createdAt and ticketFeeSats.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Public canonical ticket UUIDv4.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"example":"018f58d2-2800-4000-8000-000000000123"}],"responses":{"200":{"description":"The partner-owned ticket.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ticket"}}}},"400":{"description":"`invalid_request` — id is not a UUIDv4.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — No ticket with this id belongs to the partner.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}},"put":{"operationId":"putAccountTicket","tags":["Tickets"],"summary":"Create ticket","description":"Creates one funded receipt for the authenticated account at the UUIDv4 id in the path. The debit is exactly contributedSats + ticketFeeSats; optional expectedRoundNumber and expectedTicketFeeSats preconditions prevent creating a new ticket in an unexpected round or at an unexpected fee. Core aggregates all account contributions into one draw interval governed by the desired prize snapshotted when the round locks.","security":[{"partnerApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Public canonical ticket UUIDv4.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"example":"018f58d2-2800-4000-8000-000000000123"}],"requestBody":{"required":true,"description":"Public metadata included in the generated partner receipt manifest after the round seals, contribution, and optional round and fee preconditions. The complete JSON request body is limited to 16384 bytes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutTicketRequest"},"example":{"metadata":{"displayReference":"ticket-123"},"contributedSats":1000,"expectedRoundNumber":3,"expectedTicketFeeSats":100}}}},"responses":{"200":{"description":"The created ticket. Retrying the same immutable ticket fields with the same id returns the original ticket with the same 200 status regardless of supplied round or fee expectations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ticket"}}}},"400":{"description":"`invalid_request` — The path id is not a UUIDv4, metadata is missing, contributedSats is not a positive safe integer, metadata exceeds 4096 canonical JSON bytes, an expected purchase value is outside its documented range, or the body is not valid JSON.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"401":{"description":"`unauthorized` — The Authorization header is missing or the Bearer API key is invalid.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["unauthorized"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"409":{"description":"`idempotency_conflict` — id already exists with a different account, contribution, or metadata. Retrying with the same immutable fields returns the original ticket.\n\n`insufficient_balance` — Available balance is less than contributedSats plus the current ticketFeeSats.\n\n`unexpected_round` — A new ticket's expectedRoundNumber is supplied and does not match the accepting round. Idempotent replays ignore this precondition.\n\n`unexpected_ticket_fee` — A new ticket's expectedTicketFeeSats is supplied and does not match the live fee. Idempotent replays ignore this precondition.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["idempotency_conflict","insufficient_balance","unexpected_round","unexpected_ticket_fee"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"413":{"description":"`invalid_request` — The request body exceeds 16384 bytes.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"415":{"description":"`invalid_request` — Content-Type is not application/json.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"429":{"description":"`rate_limited` — The authenticated account's ticket-purchase rate bucket is exhausted.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["rate_limited"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/tickets":{"get":{"operationId":"listPublicTickets","tags":["Tickets"],"summary":"List public tickets","description":"Lists public tickets across all partners. Ticket UUID and metadata are public; createdAt and ticketFeeSats remain partner-only. Set sort to asc or desc, then pass nextCursor as cursor with the same sort.","parameters":[{"name":"sort","in":"query","required":false,"description":"Direction for roundNumber:ticketId ordering. Defaults to desc. Keep the same value when following nextCursor.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"cursor","in":"query","required":false,"description":"Exclusive page cursor from the previous response's nextCursor.","schema":{"type":"string","pattern":"^[0-9]+:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"},"example":"3:018f58d2-2800-4000-8000-000000000123"},{"name":"limit","in":"query","required":false,"description":"Maximum items to return. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500},"example":100},{"name":"roundNumber","in":"query","required":false,"description":"Filter to one round number.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991},"example":3},{"name":"partnerPayoutAddress","in":"query","required":false,"description":"Filter to one full partner Luckotto payout address.","schema":{"type":"string","minLength":14,"maxLength":128},"example":"tb1pkpswdsh4gskkf397hrnnzy0gvxftkh2phzed8fcczufhawxfurts9782tk"}],"responses":{"200":{"description":"A cursor page of public tickets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketList"}}}},"400":{"description":"`invalid_request` — sort is invalid, cursor is malformed, limit is outside 1-500, or an unsupported query parameter is present.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}},"/tickets/{id}":{"get":{"operationId":"getPublicTicket","tags":["Tickets"],"summary":"Get public ticket by ID","description":"Returns one public ticket by its canonical UUIDv4 identity without requiring a partner API key. Missing tickets return 404. createdAt and ticketFeeSats remain partner-only.","parameters":[{"name":"id","in":"path","required":true,"description":"Public canonical ticket UUIDv4.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"example":"018f58d2-2800-4000-8000-000000000123"}],"responses":{"200":{"description":"The public funded ticket.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicket"}}}},"400":{"description":"`invalid_request` — id is not a UUIDv4.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["invalid_request"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"404":{"description":"`not_found` — No ticket with this id exists.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["not_found"],"description":"Stable machine-readable error code for this HTTP status."}}}}}},"500":{"description":"`internal_error` — Luckotto failed unexpectedly while handling the request.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","code"],"properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["internal_error"],"description":"Stable machine-readable error code for this HTTP status."}}}}}}}}}},"components":{"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","minLength":1,"description":"Human-readable error message."},"code":{"type":"string","enum":["idempotency_conflict","insufficient_balance","internal_error","service_unavailable","invalid_solution","invalid_request","not_found","rate_limited","solution_conflict","solution_not_ready","stale_draw_block","unexpected_round","unexpected_ticket_fee","unauthorized"],"description":"Stable machine-readable error code."}},"required":["error","code"],"additionalProperties":false,"description":"Stable API error envelope."},"JsonValue":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/components/schemas/JsonValue"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/JsonValue"}}],"description":"A JSON string, number, boolean, null, array, or object value."},"PrivateMetadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"description":"Private partner metadata, limited to 4096 UTF-8 bytes after canonical JSON encoding."},"PublicTicketMetadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"description":"Required public ticket display metadata, limited to 4096 UTF-8 bytes after canonical JSON encoding. After the round seals, the generated partner receipt manifest includes the complete metadata object. Metadata removal is not currently supported. Metadata does not affect the Core draw. Encrypt any private or sensitive values before storing them."},"Sats":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Whole satoshis encoded as a JSON safe integer."},"Count":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Non-negative count."},"ChainTip":{"type":"object","properties":{"processedTipHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Latest Bitcoin block height fully processed by Luckotto's scanner, or null before the first scan."},"processedTipHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Hash of the latest processed tip block, or null before the first scan."},"processedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"When Luckotto recorded this processed tip."}},"required":["processedTipHeight","processedTipHash","processedAt"],"additionalProperties":false,"description":"Latest Bitcoin block height processed by Luckotto's scanner."},"Constants":{"type":"object","properties":{"bitcoin":{"type":"object","properties":{"network":{"type":"string","minLength":1,"description":"Configured Bitcoin network."}},"required":["network"],"additionalProperties":false,"description":"Bitcoin network."},"wallets":{"type":"object","properties":{"deposit":{"type":"object","properties":{"xpub":{"type":"string","minLength":1,"description":"Raw depth-3 BIP86 account extended public key."}},"required":["xpub"],"additionalProperties":false,"description":"Public account xpub used for partner deposit addresses."},"commitment":{"type":"object","properties":{"xpub":{"type":"string","minLength":1,"description":"Raw depth-3 BIP86 commitment account extended public key."}},"required":["xpub"],"additionalProperties":false,"description":"Public account xpub used for round commitments."}},"required":["deposit","commitment"],"additionalProperties":false,"description":"Public wallet metadata used for deposit and round verification."},"fees":{"type":"object","properties":{"depositFeeSats":{"description":"Fee charged when a confirmed deposit credits balance.","$ref":"#/components/schemas/Sats"},"ticketFeeSats":{"description":"Fee charged when creating a ticket.","$ref":"#/components/schemas/Sats"}},"required":["depositFeeSats","ticketFeeSats"],"additionalProperties":false,"description":"Current server-side fee settings."},"lottery":{"type":"object","properties":{"drawAllocationScale":{"type":"integer","minimum":4294967296,"maximum":4294967296,"description":"Compiled LUCKOTTO-1 application-layer draw-allocation scale, fixed at 2^32."},"maxPrizeShortfallFactor":{"type":"number","minimum":0.5,"maximum":0.5,"description":"Project-wide prize shortfall cap factor. Every prize shortfall is capped at floor(prizeBankrollSats * maxPrizeShortfallFactor). This is a compiled protocol constant."}},"required":["drawAllocationScale","maxPrizeShortfallFactor"],"additionalProperties":false,"description":"Luckotto draw-allocation constants."},"rounds":{"type":"object","properties":{"drawDelayBlocks":{"type":"integer","minimum":3,"maximum":3,"description":"Fixed LUCKOTTO-1 protocol delay: exactly 3 blocks after commitment confirmation."},"sufficientConfirmationBlocks":{"description":"Confirmations Luckotto requires before crediting ordinary deposits.","$ref":"#/components/schemas/Count"},"autoTicketConfirmationBlocks":{"description":"Confirmations required before an auto-ticket deposit irrevocably creates its ticket and credits its balance remainder.","$ref":"#/components/schemas/Count"},"minPayoutConfirmations":{"description":"Internal unattended-settlement threshold; it does not change which Bitcoin chain is authoritative.","$ref":"#/components/schemas/Count"}},"required":["drawDelayBlocks","sufficientConfirmationBlocks","autoTicketConfirmationBlocks","minPayoutConfirmations"],"additionalProperties":false,"description":"Runtime round timing constants."},"draw":{"type":"object","properties":{"minimumIterations":{"type":"integer","minimum":1,"maximum":1},"construction":{"type":"string","enum":["class-group-repeated-squaring"]},"proof":{"type":"string","enum":["nested-wesolowski"]},"discriminantBits":{"type":"integer","minimum":1024,"maximum":1024},"revealDelaySeconds":{"type":"integer","minimum":1800,"maximum":1800},"startingElement":{"type":"string","enum":["08"]},"seedEncoding":{"type":"string","enum":["LUCKOTTO-VDF-SEED-1"]},"proofEncoding":{"type":"string","enum":["LUCKOTTO-CHIAVDF-NWESO-1"]},"outputExtractor":{"type":"string","enum":["tagged-SHA-256"]},"sampleExpansion":{"type":"string","enum":["SHA-256"]}},"required":["minimumIterations","construction","proof","discriminantBits","revealDelaySeconds","startingElement","seedEncoding","proofEncoding","outputExtractor","sampleExpansion"],"additionalProperties":false,"description":"The fixed VDF construction and minimum iteration count."}},"required":["bitcoin","wallets","fees","lottery","rounds","draw"],"additionalProperties":false,"description":"Public project and runtime constants used by API clients and workers."},"PutDepositAddressRequest":{"type":"object","properties":{"metadata":{"description":"Private free-form metadata attached to the new deposit address.","$ref":"#/components/schemas/PrivateMetadata"},"autoTicket":{"anyOf":[{"type":"object","properties":{"expression":{"type":"string","minLength":1,"maxLength":500,"description":"Expression whose floating-point result is floored and clamped to the net deposit. The resulting ticket budget includes the ticket fee. See /docs/auto-ticket-expressions."},"metadata":{"description":"Public metadata copied to every ticket created by this address.","$ref":"#/components/schemas/PublicTicketMetadata"}},"required":["expression","metadata"],"additionalProperties":false,"description":"Immutable auto-ticket configuration for a deposit address."},{"type":"null"}],"description":"Optional auto-ticket configuration. Omit it or send null for an ordinary deposit address. Its metadata is public ticket metadata, unlike the address metadata field."}},"additionalProperties":false,"description":"Request body for creating one account deposit address."},"Account":{"type":"object","properties":{"payoutAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Fixed public Bitcoin payout address for this partner's prize wins."},"desiredPrizeSats":{"description":"Live desired prize configured by this partner. Core synchronizes it to every participation whose ticket sales remain open; the atomic ticket-sales close freezes the round value.","$ref":"#/components/schemas/Sats"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Time the partner account was created."},"balanceSats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Available partner balance for new tickets. It may be negative after an auto-ticket funding deposit is reorged out."}},"required":["payoutAddress","desiredPrizeSats","createdAt","balanceSats"],"additionalProperties":false,"description":"Authenticated partner account."},"PublicPartner":{"type":"object","properties":{"payoutAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Fixed public Bitcoin payout address for this partner's prize wins."},"desiredPrizeSats":{"description":"Desired prize for this representation. Partner resources show the live value; round and ticket resources show the effective participation value, which becomes immutable when the round seals.","$ref":"#/components/schemas/Sats"},"displayName":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"description":"Public partner display name, or null when the partner is presented by its Luckotto payout address alone."},"website":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"description":"Public partner website, or null when the partner has none or is presented by address alone."}},"required":["payoutAddress","desiredPrizeSats","displayName","website"],"additionalProperties":false,"description":"Public partner details."},"PublicPartnerList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicPartner"},"description":"Directory partners, sorted by display name and Luckotto payout address."}},"required":["items"],"additionalProperties":false,"description":"Public partner directory."},"DepositAddress":{"type":"object","properties":{"id":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid","description":"Deposit address UUID. Partner-supplied when id was provided."},"depositAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Bitcoin deposit address. Send funds to this value."},"bip32Path":{"type":"string","pattern":"^(?:\\/[0-9]+){5}$","description":"Five-segment xpub-relative BIP32 path produced by Hash Tweak V1."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Time the deposit address was allocated."},"metadata":{"description":"Private partner metadata attached to this address.","$ref":"#/components/schemas/PrivateMetadata"},"autoTicket":{"anyOf":[{"type":"object","properties":{"expression":{"type":"string","minLength":1,"maxLength":500,"description":"Expression whose floating-point result is floored and clamped to the net deposit. The resulting ticket budget includes the ticket fee. See /docs/auto-ticket-expressions."},"metadata":{"description":"Public metadata copied to every ticket created by this address.","$ref":"#/components/schemas/PublicTicketMetadata"}},"required":["expression","metadata"],"additionalProperties":false,"description":"Immutable auto-ticket configuration for a deposit address."},{"type":"null"}],"description":"Auto-ticket configuration, or null for an ordinary deposit address."},"status":{"type":"string","enum":["pending","unconfirmed","dropped","funded"],"description":"Address funding state derived from confirmed and mempool deposits."},"depositCount":{"description":"Number of deposits observed for this address.","$ref":"#/components/schemas/Count"},"pendingSats":{"description":"Uncredited sats currently observed for this address.","$ref":"#/components/schemas/Sats"},"creditedSats":{"description":"Sats credited to the partner balance from this address.","$ref":"#/components/schemas/Sats"}},"required":["id","depositAddress","bip32Path","createdAt","metadata","autoTicket","status","depositCount","pendingSats","creditedSats"],"additionalProperties":false,"description":"A partner-owned Bitcoin deposit address."},"DepositAddressList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DepositAddress"},"description":"Items on this page."},"nextCursor":{"type":"string","minLength":1,"description":"Cursor to pass as the next request's cursor query parameter. It remains useful when hasNext is false so clients can poll later."},"hasNext":{"type":"boolean","description":"Whether another page is available right now."}},"required":["items","nextCursor","hasNext"],"additionalProperties":false,"description":"Deposit addresses owned by the authenticated partner."},"AddressDeposit":{"type":"object","properties":{"depositId":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid","description":"UUIDv7 id of the observed deposit output."},"txid":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Bitcoin transaction id containing the deposit output."},"vout":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Transaction output index."},"amountSats":{"description":"Gross deposit output amount.","$ref":"#/components/schemas/Sats"},"chainStatus":{"type":"string","enum":["mempool","confirmed","dropped","reorged_out"],"description":"Latest chain lifecycle state for this outpoint."},"creditStatus":{"type":"string","enum":["not_credited","credited","uncredited"],"description":"Latest balance accounting state. credited means the deposit added available partner balance; uncredited means a previous credit was reversed."},"depositFeeSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Deposit fee charged at credit time; null before crediting."},"creditedSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Sats credited to the partner balance; null unless credited."},"blockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Confirmation block height; null while unconfirmed."},"blockHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Confirmation block hash; null while unconfirmed."},"blockTime":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Confirmation block timestamp; null while unconfirmed."},"txIndex":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"Confirmation transaction index; null while unconfirmed."},"confirmationCount":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Confirmations at the processed chain tip; null unless confirmed. Compare with requiredConfirmationCount before treating a deposit as final."},"requiredConfirmationCount":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Confirmations required for this address type before processing the deposit."},"autoTicketResult":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["pending","created","skipped_too_small","skipped_invalid_result"],"description":"Pending or terminal auto-ticket processing state."},"allocatedSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Calculated ticket budget, or null while processing is pending or the expression produced an invalid result."},"balanceRemainderSats":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"A signed JSON safe integer."},{"type":"null"}],"description":"Signed cumulative available-balance effect after the ticket budget debit. It is null while pending and can be negative when a created ticket survives a deposit reorg."},"ticketId":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},{"type":"null"}],"description":"Created ticket UUID, or null when pending or skipped."}},"required":["status","allocatedSats","balanceRemainderSats","ticketId"],"additionalProperties":false,"description":"Auto-ticket processing result for one deposit output."},{"type":"null"}],"description":"Auto-ticket result, or null for an ordinary deposit address."},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Time of the latest lifecycle or accounting event."}},"required":["depositId","txid","vout","amountSats","chainStatus","creditStatus","depositFeeSats","creditedSats","blockHeight","blockHash","blockTime","txIndex","confirmationCount","requiredConfirmationCount","autoTicketResult","updatedAt"],"additionalProperties":false,"description":"Current reduced state of one deposit outpoint observed on a deposit address. This is the latest lifecycle and credit state per outpoint; the deposit-events endpoint remains the append-only audit source."},"AccountDeposit":{"type":"object","properties":{"depositId":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid","description":"UUIDv7 id of the observed deposit output."},"txid":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Bitcoin transaction id containing the deposit output."},"vout":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Transaction output index."},"amountSats":{"description":"Gross deposit output amount.","$ref":"#/components/schemas/Sats"},"chainStatus":{"type":"string","enum":["mempool","confirmed","dropped","reorged_out"],"description":"Latest chain lifecycle state for this outpoint."},"creditStatus":{"type":"string","enum":["not_credited","credited","uncredited"],"description":"Latest balance accounting state. credited means the deposit added available partner balance; uncredited means a previous credit was reversed."},"depositFeeSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Deposit fee charged at credit time; null before crediting."},"creditedSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Sats credited to the partner balance; null unless credited."},"blockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Confirmation block height; null while unconfirmed."},"blockHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Confirmation block hash; null while unconfirmed."},"blockTime":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Confirmation block timestamp; null while unconfirmed."},"txIndex":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"Confirmation transaction index; null while unconfirmed."},"confirmationCount":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Confirmations at the processed chain tip; null unless confirmed. Compare with requiredConfirmationCount before treating a deposit as final."},"requiredConfirmationCount":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Confirmations required for this address type before processing the deposit."},"autoTicketResult":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["pending","created","skipped_too_small","skipped_invalid_result"],"description":"Pending or terminal auto-ticket processing state."},"allocatedSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Calculated ticket budget, or null while processing is pending or the expression produced an invalid result."},"balanceRemainderSats":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"A signed JSON safe integer."},{"type":"null"}],"description":"Signed cumulative available-balance effect after the ticket budget debit. It is null while pending and can be negative when a created ticket survives a deposit reorg."},"ticketId":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},{"type":"null"}],"description":"Created ticket UUID, or null when pending or skipped."}},"required":["status","allocatedSats","balanceRemainderSats","ticketId"],"additionalProperties":false,"description":"Auto-ticket processing result for one deposit output."},{"type":"null"}],"description":"Auto-ticket result, or null for an ordinary deposit address."},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Time of the latest lifecycle or accounting event."},"depositAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Deposit address that received this output."},"bip32Path":{"type":"string","pattern":"^(?:\\/[0-9]+){5}$","description":"Xpub-relative BIP32 path of the receiving deposit address."},"metadata":{"description":"Private metadata from the receiving deposit address.","$ref":"#/components/schemas/PrivateMetadata"}},"required":["depositId","txid","vout","amountSats","chainStatus","creditStatus","depositFeeSats","creditedSats","blockHeight","blockHash","blockTime","txIndex","confirmationCount","requiredConfirmationCount","autoTicketResult","updatedAt","depositAddress","bip32Path","metadata"],"additionalProperties":false,"description":"Current reduced state of one deposit outpoint owned by the authenticated account."},"AccountDepositList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AccountDeposit"},"description":"Items on this page."},"nextCursor":{"type":"string","minLength":1,"description":"Cursor to pass as the next request's cursor query parameter. It remains useful when hasNext is false so clients can poll later."},"hasNext":{"type":"boolean","description":"Whether another page is available right now."}},"required":["items","nextCursor","hasNext"],"additionalProperties":false,"description":"Current per-outpoint deposit states owned by the authenticated account."},"DepositEvent":{"type":"object","properties":{"id":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid","description":"UUIDv7 event id. It appears as nextCursor in paginated responses."},"type":{"type":"string","enum":["mempool_seen","mempool_dropped","confirmed","reorged_out","credited","uncredited"],"description":"Deposit lifecycle or balance accounting event type. credited adds zero or more available sats and uncredited reverses that credit."},"eventAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Event time decoded from the UUIDv7 event id."},"depositAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Deposit address that received this output."},"bip32Path":{"type":"string","pattern":"^(?:\\/[0-9]+){5}$","description":"Xpub-relative BIP32 path of the receiving deposit address."},"metadata":{"description":"Private metadata from the receiving deposit address.","$ref":"#/components/schemas/PrivateMetadata"},"depositTxid":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Bitcoin transaction id containing the deposit output."},"depositVout":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Transaction output index."},"amountSats":{"description":"Gross deposit output amount.","$ref":"#/components/schemas/Sats"},"blockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Block height for confirmed and reorged_out lifecycle events; otherwise null."},"blockHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Block hash for confirmed and reorged_out lifecycle events; otherwise null."},"blockTime":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Block timestamp for confirmed and reorged_out lifecycle events; otherwise null."},"txIndex":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"Transaction index for confirmed and reorged_out lifecycle events; otherwise null."},"confirmedBlockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Most recent confirmed block height for this deposit at or before this event."},"confirmedBlockHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Most recent confirmed block hash for this deposit at or before this event."},"confirmedBlockTime":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Most recent confirmed block timestamp for this deposit at or before this event."},"confirmedTxIndex":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"Most recent confirmed transaction index for this deposit at or before this event."},"balanceDeltaSats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Signed partner balance delta. Lifecycle events use 0. Credited events add available balance; uncredited events remove a previous credit."}},"required":["id","type","eventAt","depositAddress","bip32Path","metadata","depositTxid","depositVout","amountSats","blockHeight","blockHash","blockTime","txIndex","confirmedBlockHeight","confirmedBlockHash","confirmedBlockTime","confirmedTxIndex","balanceDeltaSats"],"additionalProperties":false,"description":"One immutable deposit lifecycle or reversible deposit-only accounting event."},"DepositEventList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DepositEvent"},"description":"Items on this page."},"nextCursor":{"type":"string","minLength":1,"description":"Cursor to pass as the next request's cursor query parameter. It remains useful when hasNext is false so clients can poll later."},"hasNext":{"type":"boolean","description":"Whether another page is available right now."}},"required":["items","nextCursor","hasNext"],"additionalProperties":false,"description":"Append-only deposit events visible to the authenticated partner."},"PutTicketRequest":{"type":"object","properties":{"metadata":{"description":"Public display metadata attached to the ticket. Its canonical encoding is limited to 4096 UTF-8 bytes. After the seal it is included directly in the generated canonical partner receipt manifest. Encrypt private values before storage.","$ref":"#/components/schemas/PublicTicketMetadata"},"contributedSats":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Fixed ticket contribution A. Exactly this amount plus the ticket fee is debited at purchase and added to the partner's aggregate round contribution."},"expectedRoundNumber":{"type":"integer","minimum":1,"maximum":2147483647,"description":"Optional new-purchase precondition. When supplied, a new ticket is created only in this round. An idempotent replay returns the stored ticket regardless of this value."},"expectedTicketFeeSats":{"description":"Optional new-purchase precondition. When supplied, a new ticket is created only when this is the current ticket fee. An idempotent replay returns the stored ticket regardless of this value. The caller asserts the fee but does not set it.","$ref":"#/components/schemas/Sats"}},"required":["metadata","contributedSats"],"additionalProperties":false,"description":"Request body for creating one funded Luckotto ticket."},"Ticket":{"type":"object","properties":{"id":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid","description":"Public canonical UUIDv4 funded-receipt identity and idempotency key. Core selects a partner, not an individual ticket."},"partnerPayoutAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Full partner Luckotto payout address."},"roundNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Round number this ticket belongs to."},"contributedSats":{"description":"Fixed contribution A debited at purchase.","$ref":"#/components/schemas/Sats"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Time the ticket was created."},"metadata":{"description":"Required public ticket display metadata included directly in the generated canonical partner receipt manifest after the round seals; metadata removal is not currently supported.","$ref":"#/components/schemas/PublicTicketMetadata"},"ticketFeeSats":{"description":"Fee charged to create this ticket.","$ref":"#/components/schemas/Sats"},"autoTicketFunding":{"anyOf":[{"type":"object","properties":{"txid":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Full funding transaction id."},"vout":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Funding transaction output index."},"depositAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Deposit address that received the funding output."}},"required":["txid","vout","depositAddress"],"additionalProperties":false,"description":"Partner-private funding outpoint for an automatically created ticket."},{"type":"null"}],"description":"Partner-private funding outpoint for an automatic ticket, or null for a manually purchased ticket."}},"required":["id","partnerPayoutAddress","roundNumber","contributedSats","createdAt","metadata","ticketFeeSats","autoTicketFunding"],"additionalProperties":false,"description":"A funded Luckotto ticket. Its UUID and metadata are public; createdAt and ticketFeeSats are partner-only operational fields."},"TicketList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Ticket"},"description":"Items on this page."},"nextCursor":{"type":"string","minLength":1,"description":"Cursor to pass as the next request's cursor query parameter. It remains useful when hasNext is false so clients can poll later."},"hasNext":{"type":"boolean","description":"Whether another page is available right now."}},"required":["items","nextCursor","hasNext"],"additionalProperties":false,"description":"Tickets owned by the authenticated partner."},"PublicTicket":{"type":"object","properties":{"id":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid","description":"Public canonical UUIDv4 ticket identity."},"metadata":{"description":"Required public ticket display metadata included directly in the generated canonical partner receipt manifest after the round seals; metadata removal is not currently supported.","$ref":"#/components/schemas/PublicTicketMetadata"},"partnerPayoutAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Full partner Luckotto payout address."},"roundNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Round number this ticket belongs to."},"contributedSats":{"description":"Fixed ticket contribution A.","$ref":"#/components/schemas/Sats"}},"required":["id","metadata","partnerPayoutAddress","roundNumber","contributedSats"],"additionalProperties":false,"description":"A public funded Luckotto ticket."},"PublicTicketList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicTicket"},"description":"Items on this page."},"nextCursor":{"type":"string","minLength":1,"description":"Cursor to pass as the next request's cursor query parameter. It remains useful when hasNext is false so clients can poll later."},"hasNext":{"type":"boolean","description":"Whether another page is available right now."}},"required":["items","nextCursor","hasNext"],"additionalProperties":false,"description":"Public Luckotto tickets."},"Round":{"type":"object","properties":{"roundNumber":{"type":"integer","minimum":1,"maximum":2147483647,"description":"Round number."},"opensAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When this round opened."},"closesAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Scheduled ticket-sales transition target. A due round remains accepting until sales move atomically to its successor."},"ticketSalesClosedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Actual atomic ticket-sales close time, or null while this round remains open. This may be later than closesAt."},"soldTicketCount":{"description":"Number of funded tickets in the round.","$ref":"#/components/schemas/Count"},"ticketFundedPotSats":{"description":"ticket-funded pot P=sum(contributedSats). It is available even while Q is unknown and is both the base prize and draw denominator.","$ref":"#/components/schemas/Sats"},"prizeBankrollSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Prize bankroll Q: the fully partner-owned bankroll backing final prize shortfalls. Null while prize bankroll pending. Q may rise through investment while the round is open and becomes immutable when the round closes; its final value prices shortfalls and draw allocations and is committed inside the manifest."},"roundManifestHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Plain SHA-256 of the committed round manifest's exact bytes (the on-chain OP_RETURN payload), or null until the round locks and seals. The manifest carries the protocol name, round number, final prize bankroll, round secret hash, VDF iteration count, and the participating-partner table with each partner's desired prize and aggregate contribution."},"roundSecretHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Tagged SHA-256 of the round secret bytes, embedded in the committed round manifest; published as soon as the round locks and seals."},"roundSecret":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Published 32-byte draw-secret input, or null while it remains private; its tagged SHA-256 must equal roundSecretHash."},"commitmentTxid":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Bitcoin transaction id committing to roundManifestHash, or null before broadcast."},"commitmentBlockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Block height containing the commitment transaction, or null before confirmation."},"drawBlockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Block height whose hash derives the fixed VDF discriminant."},"drawBlockHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Block hash used to derive the public Chia VDF discriminant."},"vdfIterations":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"One-shot VDF iteration count committed in the round manifest, or null before sealing."},"delayedDrawSeed":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Tagged SHA-256 of the canonical VDF output, or null before a solution is accepted."},"drawExtensionSeed":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Public downstream extension seed derived from the accepted draw attempt counter plus one. It never affects Core winner selection and is null until resolution."},"vdfSolutionAcceptedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Server acceptance time of the canonical VDF solution."},"roundSecretRevealAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Canonical VDF acceptance plus the fixed 30-minute reveal delay."},"status":{"type":"string","enum":["open","locked","revealPending","resolved"],"description":"Derived public round lifecycle state."},"winningPartnerPayoutAddress":{"anyOf":[{"type":"string","minLength":14,"maxLength":128},{"type":"null"}],"description":"Winning partner's full Luckotto payout address when the outcome is won, or null."},"outcome":{"anyOf":[{"type":"string","enum":["won","noWinner"]},{"type":"null"}],"description":"Resolution result: won or noWinner. Null until the round secret is revealed and the one-shot interval is selected."},"payoutTxid":{"anyOf":[{"type":"string","minLength":1,"maxLength":500},{"type":"null"}],"description":"Bitcoin payout transaction id, or null before payout."},"resolvedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"When the round was resolved, or null before resolution."}},"required":["roundNumber","opensAt","closesAt","ticketSalesClosedAt","soldTicketCount","ticketFundedPotSats","prizeBankrollSats","roundManifestHash","roundSecretHash","roundSecret","commitmentTxid","commitmentBlockHeight","drawBlockHeight","drawBlockHash","vdfIterations","delayedDrawSeed","drawExtensionSeed","vdfSolutionAcceptedAt","roundSecretRevealAt","status","winningPartnerPayoutAddress","outcome","payoutTxid","resolvedAt"],"additionalProperties":false,"description":"Public Luckotto round metadata and draw proof fields."},"RoundDetail":{"type":"object","properties":{"roundNumber":{"type":"integer","minimum":1,"maximum":2147483647,"description":"Round number."},"opensAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When this round opened."},"closesAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Scheduled ticket-sales transition target. A due round remains accepting until sales move atomically to its successor."},"ticketSalesClosedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Actual atomic ticket-sales close time, or null while this round remains open. This may be later than closesAt."},"soldTicketCount":{"description":"Number of funded tickets in the round.","$ref":"#/components/schemas/Count"},"ticketFundedPotSats":{"description":"ticket-funded pot P=sum(contributedSats). It is available even while Q is unknown and is both the base prize and draw denominator.","$ref":"#/components/schemas/Sats"},"prizeBankrollSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"Prize bankroll Q: the fully partner-owned bankroll backing final prize shortfalls. Null while prize bankroll pending. Q may rise through investment while the round is open and becomes immutable when the round closes; its final value prices shortfalls and draw allocations and is committed inside the manifest."},"roundManifestHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Plain SHA-256 of the committed round manifest's exact bytes (the on-chain OP_RETURN payload), or null until the round locks and seals. The manifest carries the protocol name, round number, final prize bankroll, round secret hash, VDF iteration count, and the participating-partner table with each partner's desired prize and aggregate contribution."},"roundSecretHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Tagged SHA-256 of the round secret bytes, embedded in the committed round manifest; published as soon as the round locks and seals."},"roundSecret":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Published 32-byte draw-secret input, or null while it remains private; its tagged SHA-256 must equal roundSecretHash."},"commitmentTxid":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Bitcoin transaction id committing to roundManifestHash, or null before broadcast."},"commitmentBlockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Block height containing the commitment transaction, or null before confirmation."},"drawBlockHeight":{"anyOf":[{"$ref":"#/components/schemas/Count"},{"type":"null"}],"description":"Block height whose hash derives the fixed VDF discriminant."},"drawBlockHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Block hash used to derive the public Chia VDF discriminant."},"vdfIterations":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"One-shot VDF iteration count committed in the round manifest, or null before sealing."},"delayedDrawSeed":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Tagged SHA-256 of the canonical VDF output, or null before a solution is accepted."},"drawExtensionSeed":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"Public downstream extension seed derived from the accepted draw attempt counter plus one. It never affects Core winner selection and is null until resolution."},"vdfSolutionAcceptedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Server acceptance time of the canonical VDF solution."},"roundSecretRevealAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"Canonical VDF acceptance plus the fixed 30-minute reveal delay."},"status":{"type":"string","enum":["open","locked","revealPending","resolved"],"description":"Derived public round lifecycle state."},"winningPartnerPayoutAddress":{"anyOf":[{"type":"string","minLength":14,"maxLength":128},{"type":"null"}],"description":"Winning partner's full Luckotto payout address when the outcome is won, or null."},"outcome":{"anyOf":[{"type":"string","enum":["won","noWinner"]},{"type":"null"}],"description":"Resolution result: won or noWinner. Null until the round secret is revealed and the one-shot interval is selected."},"payoutTxid":{"anyOf":[{"type":"string","minLength":1,"maxLength":500},{"type":"null"}],"description":"Bitcoin payout transaction id, or null before payout."},"resolvedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}],"description":"When the round was resolved, or null before resolution."},"winningPrizeShortfallSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"The winning partner's prize shortfall when the outcome is won, or null."},"prizeSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"The Core prize owed to the winning partner: ticketFundedPotSats + winningPrizeShortfallSats. Null for unresolved and noWinner rounds."}},"required":["roundNumber","opensAt","closesAt","ticketSalesClosedAt","soldTicketCount","ticketFundedPotSats","prizeBankrollSats","roundManifestHash","roundSecretHash","roundSecret","commitmentTxid","commitmentBlockHeight","drawBlockHeight","drawBlockHash","vdfIterations","delayedDrawSeed","drawExtensionSeed","vdfSolutionAcceptedAt","roundSecretRevealAt","status","winningPartnerPayoutAddress","outcome","payoutTxid","resolvedAt","winningPrizeShortfallSats","prizeSats"],"additionalProperties":false,"description":"Public Luckotto round metadata and draw proof fields."},"RoundList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Round"},"description":"Items on this page."},"nextCursor":{"type":"string","minLength":1,"description":"Cursor to pass as the next request's cursor query parameter. It remains useful when hasNext is false so clients can poll later."},"hasNext":{"type":"boolean","description":"Whether another page is available right now."}},"required":["items","nextCursor","hasNext"],"additionalProperties":false,"description":"Public Luckotto rounds."},"RoundManifest":{"type":"object","properties":{"protocol":{"type":"string","const":"LUCKOTTO-1"},"roundNumber":{"type":"integer","minimum":1,"maximum":2147483647},"prizeBankrollSats":{"$ref":"#/components/schemas/Sats"},"roundSecretHash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"vdfIterations":{"type":"integer","minimum":1,"maximum":9007199254740991},"partners":{"minItems":1,"type":"array","items":{"type":"object","properties":{"payoutAddress":{"type":"string","minLength":14,"maxLength":128},"desiredPrizeSats":{"$ref":"#/components/schemas/Sats"},"partnerCommitmentHash":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Lowercase plain SHA-256 of this partner's exact opaque commitment artifact bytes."},"totalContributedSats":{"$ref":"#/components/schemas/Sats"}},"required":["payoutAddress","desiredPrizeSats","partnerCommitmentHash","totalContributedSats"],"additionalProperties":false}}},"required":["protocol","roundNumber","prizeBankrollSats","roundSecretHash","vdfIterations","partners"],"additionalProperties":false,"description":"Canonical LUCKOTTO-1 round manifest committed on chain."},"PartnerReceiptManifest":{"type":"object","properties":{"partnerPayoutAddress":{"type":"string","minLength":14,"maxLength":128},"roundNumber":{"type":"integer","minimum":1,"maximum":2147483647},"tickets":{"type":"array","items":{"type":"object","properties":{"contributedSats":{"type":"integer","minimum":1,"maximum":9007199254740991},"id":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","format":"uuid"},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/JsonValue"}}},"required":["contributedSats","id","metadata"],"additionalProperties":false,"description":"One immutable ticket receipt in a partner receipt manifest."}}},"required":["partnerPayoutAddress","roundNumber","tickets"],"additionalProperties":false,"description":"Partner receipt manifest whose exact bytes are committed by its round-manifest entry."},"RoundPartner":{"type":"object","properties":{"roundNumber":{"type":"integer","minimum":1,"maximum":2147483647,"description":"Round number."},"payoutAddress":{"type":"string","minLength":14,"maxLength":128,"description":"Participating partner's full Luckotto payout address."},"displayName":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"description":"Public partner display name, or null when the partner is presented by payout address alone."},"soldTicketCount":{"description":"Number of funded tickets bought by this partner in the round.","$ref":"#/components/schemas/Count"},"ticketFundedPotSats":{"description":"This partner's aggregate contribution to the round ticket-funded pot.","$ref":"#/components/schemas/Sats"},"desiredPrizeSats":{"description":"The partner's live desired prize while ticket sales are open or its immutable snapshot after the atomic ticket-sales close.","$ref":"#/components/schemas/Sats"},"prizeIfWonSats":{"anyOf":[{"$ref":"#/components/schemas/Sats"},{"type":"null"}],"description":"The Core prize payable if this partner wins, or null while the prize bankroll is pending."}},"required":["roundNumber","payoutAddress","displayName","soldTicketCount","ticketFundedPotSats","desiredPrizeSats","prizeIfWonSats"],"additionalProperties":false,"description":"One partner's aggregate participation in a Luckotto round."},"RoundPartnerList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RoundPartner"},"description":"Participants ordered by aggregate contribution descending, then payout address ascending."}},"required":["items"],"additionalProperties":false,"description":"All partners participating in one Luckotto round."},"VdfSolution":{"type":"object","properties":{"output":{"type":"string","pattern":"^[0-9a-f]{200}$","description":"Canonical 100-byte Chia BQFC output."},"outputHash":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Tagged SHA-256 of the canonical VDF output bytes."},"witnessType":{"type":"integer","minimum":0,"maximum":64,"description":"Nested Wesolowski witness depth."},"proof":{"type":"string","pattern":"^[0-9a-f]+$","description":"LUCKOTTO-CHIAVDF-NWESO-1 proof bytes as lowercase hex."},"acceptedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"Database-generated time the first valid solution was accepted."},"solveDurationMs":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Elapsed server time from observing the draw block to accepting the solution."},"drawBlockHash":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Draw block hash for this solution."},"canonical":{"type":"boolean","description":"Whether this submission matches the round current draw block."}},"required":["output","outputHash","witnessType","proof","acceptedAt","solveDurationMs","drawBlockHash","canonical"],"additionalProperties":false,"description":"The verified solution for the round's current draw block."},"RoundVdfSolution":{"type":"object","properties":{"roundNumber":{"type":"integer","minimum":1,"maximum":2147483647},"canonicalDrawBlockHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}]},"roundManifestHash":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"description":"The plain manifest SHA-256 bound into the VDF seed."},"vdfIterations":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"solution":{"anyOf":[{"$ref":"#/components/schemas/VdfSolution"},{"type":"null"}],"description":"The canonical solution for the current draw block, or null."}},"required":["roundNumber","canonicalDrawBlockHash","roundManifestHash","vdfIterations","solution"],"additionalProperties":false,"description":"The canonical VDF solution for a round, when available."},"SubmitVdfSolutionRequest":{"type":"object","properties":{"drawBlockHash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"output":{"type":"string","pattern":"^[0-9a-f]{200}$"},"witnessType":{"type":"integer","minimum":0,"maximum":64},"proof":{"type":"string","pattern":"^[0-9a-f]+$"}},"required":["drawBlockHash","output","witnessType","proof"],"additionalProperties":false,"description":"One VDF solution proof."},"VdfSubmissionResult":{"type":"object","properties":{"status":{"type":"string","enum":["accepted","alreadyStored"]},"solution":{"$ref":"#/components/schemas/VdfSolution"},"roundStatus":{"type":"string","enum":["locked","revealPending","resolved"]},"roundSecretRevealAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"UTC date and time in ISO 8601 format."},{"type":"null"}]}},"required":["status","solution","roundStatus","roundSecretRevealAt"],"additionalProperties":false,"description":"Accepted or already-stored canonical VDF solution."}},"securitySchemes":{"partnerApiKey":{"type":"http","scheme":"bearer","description":"Partner API key created in dashboard settings. Account routes infer the account from this key."}}}}