mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 22:33:42 +00:00
109 lines
15 KiB
JSON
109 lines
15 KiB
JSON
{
|
|
"openapi": "3.1.0",
|
|
"info": {
|
|
"title": "Cosmic Clash Matchmaking API",
|
|
"version": "1.0.0",
|
|
"description": "Versioned control-plane contract. Simulation traffic never uses this API."
|
|
},
|
|
"servers": [{"url": "https://matchmaking.invalid/api/v1"}],
|
|
"security": [{"bearerAuth": []}],
|
|
"paths": {
|
|
"/session/steam": {
|
|
"post": {
|
|
"security": [],
|
|
"operationId": "createSteamSession",
|
|
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SteamLogin"}}}},
|
|
"responses": {"200": {"description": "Session created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Session"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "429": {"$ref": "#/components/responses/RateLimited"}}
|
|
}
|
|
},
|
|
"/profile": {
|
|
"get": {"operationId": "getProfile", "responses": {"200": {"description": "Profile", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Profile"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}}}
|
|
},
|
|
"/profile/ranked": {
|
|
"get": {"operationId": "getRankedProfile", "responses": {"200": {"description": "Authoritative ranked profile", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RankedProfile"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "503": {"$ref": "#/components/responses/Unavailable"}}}
|
|
},
|
|
"/queue/tickets": {
|
|
"post": {
|
|
"operationId": "createQueueTicket",
|
|
"parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}],
|
|
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QueueCreate"}}}},
|
|
"responses": {"201": {"description": "Ticket created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QueueTicket"}}}}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Invalid"}}
|
|
}
|
|
},
|
|
"/queue/tickets/{ticketId}": {
|
|
"parameters": [{"$ref": "#/components/parameters/TicketId"}],
|
|
"get": {"operationId": "getQueueTicket", "responses": {"200": {"description": "Ticket", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QueueTicket"}}}}, "404": {"$ref": "#/components/responses/NotFound"}}},
|
|
"delete": {"operationId": "cancelQueueTicket", "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}, {"$ref": "#/components/parameters/ExpectedRevision"}], "responses": {"204": {"description": "Cancelled"}, "409": {"$ref": "#/components/responses/Conflict"}}}
|
|
},
|
|
"/queue/tickets/{ticketId}/heartbeat": {
|
|
"post": {"operationId": "heartbeatQueueTicket", "parameters": [{"$ref": "#/components/parameters/TicketId"}, {"$ref": "#/components/parameters/IdempotencyKey"}, {"$ref": "#/components/parameters/ExpectedRevision"}], "responses": {"200": {"description": "Ticket renewed", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QueueTicket"}}}}, "409": {"$ref": "#/components/responses/Conflict"}}}
|
|
},
|
|
"/proposals/{proposalId}/accept": {
|
|
"post": {"operationId": "acceptProposal", "parameters": [{"$ref": "#/components/parameters/ProposalId"}, {"$ref": "#/components/parameters/IdempotencyKey"}, {"$ref": "#/components/parameters/ExpectedRevision"}], "responses": {"200": {"description": "Proposal updated", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Proposal"}}}}, "409": {"$ref": "#/components/responses/Conflict"}, "410": {"$ref": "#/components/responses/Expired"}}}
|
|
},
|
|
"/proposals/{proposalId}/decline": {
|
|
"post": {"operationId": "declineProposal", "parameters": [{"$ref": "#/components/parameters/ProposalId"}, {"$ref": "#/components/parameters/IdempotencyKey"}, {"$ref": "#/components/parameters/ExpectedRevision"}], "responses": {"200": {"description": "Proposal declined", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Proposal"}}}}, "409": {"$ref": "#/components/responses/Conflict"}, "410": {"$ref": "#/components/responses/Expired"}}}
|
|
},
|
|
"/assignments/{matchId}": {
|
|
"get": {"operationId": "getAssignment", "parameters": [{"$ref": "#/components/parameters/MatchId"}], "responses": {"200": {"description": "Assignment", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Assignment"}}}}, "404": {"$ref": "#/components/responses/NotFound"}}}
|
|
},
|
|
"/servers/{serverId}/register": {
|
|
"post": {"security": [{"serverCredential": []}], "operationId": "registerServer", "parameters": [{"$ref": "#/components/parameters/ServerId"}, {"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerRegistration"}}}}, "responses": {"204": {"description": "Registered"}, "409": {"$ref": "#/components/responses/Conflict"}}}
|
|
},
|
|
"/servers/{serverId}/connect": {
|
|
"post": {"security": [{"serverCredential": []}], "operationId": "claimPlayerConnection", "parameters": [{"$ref": "#/components/parameters/ServerId"}, {"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerConnectionClaim"}}}}, "responses": {"200": {"description": "Connection generation claimed", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerConnectionLease"}}}}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Invalid"}, "503": {"$ref": "#/components/responses/Unavailable"}}}
|
|
},
|
|
"/servers/{serverId}/disconnect": {
|
|
"post": {"security": [{"serverCredential": []}], "operationId": "recordPlayerDisconnected", "parameters": [{"$ref": "#/components/parameters/ServerId"}, {"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerConnectionDisconnect"}}}}, "responses": {"204": {"description": "Disconnection recorded"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Invalid"}, "503": {"$ref": "#/components/responses/Unavailable"}}}
|
|
},
|
|
"/servers/{serverId}/result": {
|
|
"post": {"security": [{"serverCredential": []}], "operationId": "submitMatchResult", "parameters": [{"$ref": "#/components/parameters/ServerId"}, {"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MatchResult"}}}}, "responses": {"202": {"description": "Result accepted"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Invalid"}}}
|
|
},
|
|
"/servers/{serverId}/shutdown": {
|
|
"post": {"security": [{"serverCredential": []}], "operationId": "acknowledgeServerShutdown", "parameters": [{"$ref": "#/components/parameters/ServerId"}, {"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerShutdown"}}}}, "responses": {"204": {"description": "Shutdown acknowledged"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/Invalid"}}}
|
|
}
|
|
},
|
|
"components": {
|
|
"securitySchemes": {
|
|
"bearerAuth": {"type": "http", "scheme": "bearer"},
|
|
"serverCredential": {"type": "http", "scheme": "bearer", "bearerFormat": "match-bound workload credential"}
|
|
},
|
|
"parameters": {
|
|
"IdempotencyKey": {"name": "Idempotency-Key", "in": "header", "required": true, "schema": {"type": "string", "minLength": 16, "maxLength": 128}},
|
|
"ExpectedRevision": {"name": "If-Match-Revision", "in": "header", "required": true, "schema": {"type": "integer", "minimum": 0}},
|
|
"TicketId": {"name": "ticketId", "in": "path", "required": true, "schema": {"$ref": "#/components/schemas/OpaqueId"}},
|
|
"ProposalId": {"name": "proposalId", "in": "path", "required": true, "schema": {"$ref": "#/components/schemas/OpaqueId"}},
|
|
"MatchId": {"name": "matchId", "in": "path", "required": true, "schema": {"$ref": "#/components/schemas/OpaqueId"}},
|
|
"ServerId": {"name": "serverId", "in": "path", "required": true, "schema": {"$ref": "#/components/schemas/OpaqueId"}}
|
|
},
|
|
"responses": {
|
|
"Unauthorized": {"description": "Authentication failed"},
|
|
"RateLimited": {"description": "Rate limit exceeded"},
|
|
"Conflict": {"description": "Revision or idempotency conflict"},
|
|
"Invalid": {"description": "Invalid state or schema"},
|
|
"NotFound": {"description": "Resource not found"},
|
|
"Unavailable": {"description": "Authoritative profile temporarily unavailable"},
|
|
"Expired": {"description": "Resource expired"}
|
|
},
|
|
"schemas": {
|
|
"OpaqueId": {"type": "string", "pattern": "^[A-Za-z0-9_-]{16,128}$"},
|
|
"SteamLogin": {"type": "object", "required": ["web_api_ticket"], "additionalProperties": false, "properties": {"web_api_ticket": {"type": "string", "minLength": 1, "maxLength": 4096}}},
|
|
"Session": {"type": "object", "required": ["player_id", "expires_at", "access_token"], "additionalProperties": false, "properties": {"player_id": {"$ref": "#/components/schemas/OpaqueId"}, "expires_at": {"type": "string", "format": "date-time"}, "access_token": {"type": "string"}}},
|
|
"Profile": {"type": "object", "required": ["player_id", "rating", "rd", "provisional"], "additionalProperties": false, "properties": {"player_id": {"$ref": "#/components/schemas/OpaqueId"}, "rating": {"type": "number"}, "rd": {"type": "number"}, "provisional": {"type": "boolean"}}},
|
|
"RankedProfile": {"type": "object", "required": ["rating", "rd", "volatility", "ranked_games", "tier", "provisional"], "additionalProperties": false, "properties": {"rating": {"type": "number", "minimum": 0}, "rd": {"type": "number", "minimum": 0}, "volatility": {"type": "number", "minimum": 0}, "ranked_games": {"type": "integer", "minimum": 0}, "tier": {"type": "string", "enum": ["PROVISIONAL", "BRONZE", "SILVER", "GOLD", "PLATINUM", "DIAMOND"]}, "provisional": {"type": "boolean"}, "season_id": {"$ref": "#/components/schemas/OpaqueId"}, "season_ends_at": {"type": "string", "format": "date-time"}}},
|
|
"QueueCreate": {"type": "object", "required": ["playlist", "client_build", "protocol_version"], "additionalProperties": false, "properties": {"playlist": {"type": "string", "enum": ["casual", "ranked"]}, "client_build": {"type": "string", "minLength": 1, "maxLength": 128}, "protocol_version": {"type": "integer", "minimum": 1}}},
|
|
"QueueTicket": {"type": "object", "required": ["ticket_id", "player_id", "playlist", "state", "revision", "enqueued_at", "expires_at"], "additionalProperties": false, "properties": {"ticket_id": {"$ref": "#/components/schemas/OpaqueId"}, "player_id": {"$ref": "#/components/schemas/OpaqueId"}, "proposal_id": {"$ref": "#/components/schemas/OpaqueId"}, "match_id": {"$ref": "#/components/schemas/OpaqueId"}, "playlist": {"type": "string", "enum": ["casual", "ranked"]}, "state": {"$ref": "#/components/schemas/QueueState"}, "revision": {"type": "integer", "minimum": 0}, "enqueued_at": {"type": "string", "format": "date-time"}, "expires_at": {"type": "string", "format": "date-time"}}},
|
|
"QueueState": {"type": "string", "enum": ["QUEUED", "PROPOSED", "ACCEPTED", "ALLOCATING", "PROCESS_READY", "ASSIGNMENT_READY", "ASSIGNED", "CONNECTING", "LIVE", "RESULT_PENDING", "COMPLETED", "CANCELLED", "EXPIRED", "FAILED"]},
|
|
"Proposal": {"type": "object", "required": ["proposal_id", "revision", "state", "expires_at", "participants"], "additionalProperties": false, "properties": {"proposal_id": {"$ref": "#/components/schemas/OpaqueId"}, "revision": {"type": "integer", "minimum": 0}, "state": {"type": "string", "enum": ["OPEN", "ACCEPTED", "DECLINED", "EXPIRED", "CANCELLED"]}, "expires_at": {"type": "string", "format": "date-time"}, "participants": {"type": "array", "minItems": 2, "maxItems": 6, "items": {"$ref": "#/components/schemas/ProposalParticipant"}}}},
|
|
"ProposalParticipant": {"type": "object", "required": ["player_id", "response", "team", "slot"], "additionalProperties": false, "properties": {"player_id": {"$ref": "#/components/schemas/OpaqueId"}, "response": {"type": "string", "enum": ["PENDING", "ACCEPTED", "DECLINED", "TIMED_OUT"]}, "team": {"type": "integer", "minimum": 0, "maximum": 1}, "slot": {"type": "integer", "minimum": 0, "maximum": 5}}},
|
|
"Assignment": {"type": "object", "required": ["match_id", "server_id", "player_id", "slot", "expires_at", "protocol_version", "transport", "endpoint", "join_authorisation"], "additionalProperties": false, "properties": {"match_id": {"$ref": "#/components/schemas/OpaqueId"}, "server_id": {"$ref": "#/components/schemas/OpaqueId"}, "player_id": {"$ref": "#/components/schemas/OpaqueId"}, "slot": {"type": "integer", "minimum": 0, "maximum": 5}, "expires_at": {"type": "string", "format": "date-time"}, "protocol_version": {"type": "integer", "minimum": 1}, "transport": {"type": "string", "enum": ["steam_sdr", "enet"]}, "endpoint": {"type": "string", "minLength": 3, "maxLength": 256}, "join_authorisation": {"type": "string"}}},
|
|
"ServerRegistration": {"type": "object", "required": ["match_id", "protocol_version", "image_digest", "assignment_ready"], "additionalProperties": false, "properties": {"match_id": {"$ref": "#/components/schemas/OpaqueId"}, "protocol_version": {"type": "integer", "minimum": 1}, "image_digest": {"type": "string", "pattern": "^sha256:[a-f0-9]{64}$"}, "assignment_ready": {"type": "boolean"}}},
|
|
"ServerConnectionClaim": {"type": "object", "required": ["player_id", "expected_generation"], "additionalProperties": false, "properties": {"player_id": {"$ref": "#/components/schemas/OpaqueId"}, "expected_generation": {"type": "integer", "minimum": 0}}},
|
|
"ServerConnectionDisconnect": {"type": "object", "required": ["player_id", "generation"], "additionalProperties": false, "properties": {"player_id": {"$ref": "#/components/schemas/OpaqueId"}, "generation": {"type": "integer", "minimum": 1}}},
|
|
"ServerConnectionLease": {"type": "object", "required": ["generation"], "additionalProperties": false, "properties": {"generation": {"type": "integer", "minimum": 1}}},
|
|
"ServerShutdown": {"type": "object", "required": ["reason"], "additionalProperties": false, "properties": {"reason": {"type": "string", "minLength": 1, "maxLength": 96}}},
|
|
"MatchResult": {"type": "object", "required": ["match_id", "result_nonce", "score", "integrity_state"], "additionalProperties": false, "properties": {"match_id": {"$ref": "#/components/schemas/OpaqueId"}, "result_nonce": {"type": "string", "minLength": 16, "maxLength": 128}, "score": {"type": "object", "required": ["team_0", "team_1"], "additionalProperties": false, "properties": {"team_0": {"type": "integer", "minimum": 0}, "team_1": {"type": "integer", "minimum": 0}}}, "integrity_state": {"type": "string", "enum": ["CERTIFIED", "SUPPRESSED", "REVIEW"]}}}
|
|
}
|
|
}
|
|
}
|