# HTTP contract v1 Tracking: #4 All production endpoints require HTTPS. JSON uses UTF-8, camel-case property names, compact output, string-valued camel-case enums, and ISO 8601 timestamps. Every request that contains a body carries `contractVersion: 1`; browse carries the same value as a required query parameter. ## Compatibility and parsing - Contract version matching is exact. Any value other than `1` fails with `unsupportedContractVersion`; it is never guessed or downgraded. - Gameplay protocol matching is exact. `buildVersion` is display and diagnostic text only and never decides compatibility. - Unknown JSON object properties are ignored so additive v1 responses remain readable. Unknown enum names, numeric enum values, comments, trailing commas, invalid identifier strings, and excessive nesting are rejected. - Game, environment, and region IDs are lowercase URL-safe slugs. Listing, lease, join-attempt, and mediation IDs are non-empty UUIDs serialized as JSON strings. - Clients must honor request cancellation. A disconnected or cancelled request does not promise a response body; the server should stop work where safe. ## Endpoints | Method | Path | Purpose | | --- | --- | --- | | `POST` | `/v1/sessions` | Register a session and create its renewable lease. | | `POST` | `/v1/sessions/{listingId}/renew` | Renew the listing lease. | | `PUT` | `/v1/sessions/{listingId}` | Replace mutable browser fields and capacity. | | `DELETE` | `/v1/sessions/{listingId}` | Withdraw a listing. | | `GET` | `/v1/sessions` | Browse compatible public sessions. | | `GET` | `/v1/sessions/{listingId}` | Resolve a public or explicitly shared unlisted listing. | | `POST` | `/v1/join-attempts` | Authorize and create a short-lived join attempt. | | `GET` | `/v1/sessions/{listingId}/join-attempts` | Let an authenticated host poll pending attempts. | | `POST` | `/v1/join-attempts/{attemptId}/outcome` | Report a bounded connection outcome. | | `GET` | `/health/live` | Report that the HTTP process is alive. | | `GET` | `/health/ready` | Report whether the UDP mediator is bound and ready. | The generated [OpenAPI document](../api/rendezvous-v1.json) is the normative shape reference for parameters, bodies, and responses. Contract-only endpoints return `501` until their behavior is implemented by the subsequent directory, lease, and join-orchestration issues. Host polling sends its reusable lease credential in `X-Rendezvous-Lease-Token`; it must never be placed in a URL. Lease credentials for mutation operations are carried in their request bodies. Public browser responses contain no IP endpoints, lease tokens, punch capabilities, connection tickets, player identifiers, or gameplay state. ## Idempotency, cursors, and retries Registration and join creation require a caller-generated visible-ASCII `idempotencyKey`. A repeat in the same authorization scope returns the original result while the key is retained; reusing a key with a different payload fails with `conflict`. Keys are opaque and must not contain credentials. Cursors are opaque, endpoint-specific, short-lived values. A client may echo a cursor only to the endpoint and filters that produced it. Invalid or expired cursors fail with `invalidRequest`; clients restart browsing from the first page. Renew, update, delete, and outcome reporting are safe to retry with the same lease/attempt identity after a transport-level failure. ## Limits Limits are measured after UTF-8 encoding where stated. Servers reject the entire request rather than truncate values. | Item | v1 limit | | --- | ---: | | HTTP request body | 16 KiB | | Browser response body | 256 KiB | | Browser page | 100 listings | | Metadata document | 4 KiB, 32 keys | | Metadata key / value | 64 / 256 UTF-8 bytes | | Game / environment / region ID | 64 / 32 / 32 characters | | Display name / build version | 128 / 64 UTF-8 bytes | | Idempotency key | 64 visible ASCII characters | | Cursor | 512 visible ASCII characters | | Diagnostic code | 64 visible ASCII characters | | Error message | 256 UTF-8 bytes | | Reusable HTTP credential | 1,024 characters | | Session capacity | 1–10,000 players | ## Error mapping Errors use `ApiError` with a stable `code`, bounded safe `message`, optional `correlationId`, and optional `retryAfterSeconds`. Messages are diagnostic and must not be parsed. Secrets and raw credentials are never echoed. | HTTP | Codes | | ---: | --- | | 400 | `invalidRequest`, `unsupportedContractVersion` | | 401 | `authenticationRequired` | | 403 | `forbidden` | | 404 | `notFound` | | 409 | `conflict`, `incompatibleProtocol`, `replayRejected`, `capacityExceeded` | | 410 | `expired`, `staleHost` | | 429 | `rateLimited` (with retry guidance when known) | | 503 | `serviceUnavailable` (with retry guidance when known) | | 500 | `internalError` | Malformed input must receive the same bounded error family regardless of which parser or validation stage rejected it.