{"openapi":"3.0.1","info":{"title":"GetSize Public API","description":"Shoe identification and size recommendation API.\n\nAll endpoints require an `X-Api-Key` header. Responses use the\ncanonical error envelope `{ \"error\": { \"code\", \"message\", \"details\" } }`.\nRate limit: 60 requests/minute per key by default (see headers).\n","contact":{"name":"GetSize","url":"https://www.getsize.shoes/docs/public-api/overview"},"version":"1.0.0"},"servers":[{"url":"https://www.getsize.shoes","description":"Production"},{"url":"https://staging.getsize.shoes","description":"Staging (request access)"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Shoe selection","description":"Wizard that narrows an unknown shoe down to a canonical reference (brand, model, variation). Walk it step by step, appending the user's answer each turn."},{"name":"Sessions","description":"Session lifecycle. A session groups shoes and foot measurements for a single end user of an integration."}],"paths":{"/api/public/v1/shoe-selection":{"post":{"tags":["Shoe selection"],"summary":"Advance the shoe-selection wizard","description":"Replays the current answers against the selection state machine and returns either the next question or the resolved canonical shoe.","operationId":"stepShoeSelection","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShoeSelectionRequest"}}}},"responses":{"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"200":{"description":"Next step or completed selection returned.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ShoeSelectionResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/api/public/v1/sessions":{"post":{"tags":["Sessions"],"summary":"Create a session","description":"Creates a new session bound to the calling API key. Session id is opaque — store and reuse it for the duration of the user's flow.","operationId":"createSession","responses":{"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"429":{"$ref":"#/components/responses/RateLimited"},"200":{"description":"Session created.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}}}}},"/api/public/v1/sessions/{sessionId}/shoes":{"get":{"tags":["Sessions"],"summary":"List shoes in a session","description":"Returns all shoes the end user has added to the session, most recent first.","operationId":"listSessionShoes","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"404":{"$ref":"#/components/responses/SessionNotFound"},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"200":{"description":"Shoes returned.","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ShoeView"}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Sessions"],"summary":"Add a shoe the user already owns","description":"Records a shoe that the end user owns so subsequent recommendations can use it as a fit reference. Maximum 20 shoes per session.","operationId":"addShoeToSession","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddShoeRequest"}}}},"responses":{"404":{"$ref":"#/components/responses/SessionNotFound"},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"200":{"description":"Shoe added.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CanonicalShoe"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"409":{"$ref":"#/components/responses/Conflict"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/api/public/v1/sessions/{sessionId}/recommendations":{"post":{"tags":["Sessions"],"summary":"Recommend a size for a target shoe","description":"Runs the sizing engine using the shoes + foot measurement already stored on the session plus the supplied target shoe.","operationId":"recommendForSession","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationRequest"}}}},"responses":{"200":{"description":"Recommendation returned.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}},"404":{"$ref":"#/components/responses/SessionNotFound"},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"429":{"$ref":"#/components/responses/RateLimited"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/api/public/v1/sessions/{sessionId}/foot-measurement":{"get":{"tags":["Sessions"],"summary":"Get the foot measurement for the session","description":"Returns the stored foot measurement, or 404 if none exists yet.","operationId":"getFootMeasurement","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Measurement found.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/FootMeasurementView"}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"429":{"$ref":"#/components/responses/RateLimited"},"404":{"$ref":"#/components/responses/SessionNotFound"}}},"post":{"tags":["Sessions"],"summary":"Set the foot measurement for the session","description":"Records left + right foot length in millimeters. Only one measurement is kept per session — call `DELETE /sessions/{id}` to clear before re-measuring.","operationId":"setFootMeasurement","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddFootMeasurementRequest"}}}},"responses":{"404":{"$ref":"#/components/responses/SessionNotFound"},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"200":{"description":"Measurement stored.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/FootMeasurementView"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"409":{"$ref":"#/components/responses/Conflict"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/api/public/v1/sessions/{sessionId}":{"get":{"tags":["Sessions"],"summary":"Get a session","description":"Returns the current state of a session (counts, expiry). A GET renews the session's inactivity TTL.","operationId":"getSession","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"404":{"$ref":"#/components/responses/SessionNotFound"},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"200":{"description":"Session exists.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"tags":["Sessions"],"summary":"Delete a session","description":"Removes the session and any associated shoes / foot measurements. Idempotent: returns 404 if the session is already gone.","operationId":"deleteSession","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"404":{"$ref":"#/components/responses/SessionNotFound"},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"429":{"$ref":"#/components/responses/RateLimited"},"204":{"description":"Session removed."}}}},"/api/public/v1/sessions/{sessionId}/shoes/{shoeId}":{"delete":{"tags":["Sessions"],"summary":"Remove a shoe from a session","description":"Deletes one shoe row from the session. Returns 404 if the id is unknown or belongs to another session.","operationId":"removeSessionShoe","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"shoeId","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"404":{"$ref":"#/components/responses/SessionNotFound"},"204":{"description":"Shoe removed."},"401":{"$ref":"#/components/responses/Unauthenticated"},"500":{"$ref":"#/components/responses/InternalError"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"schemas":{"ShoeSelection":{"type":"object","properties":{"answers":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}}}},"ShoeSelectionRequest":{"type":"object","properties":{"purpose":{"type":"string","enum":["ADD_TO_RACK","RECOMMENDATION_TARGET"]},"selection":{"$ref":"#/components/schemas/ShoeSelection"},"locale":{"type":"string"}}},"CanonicalShoe":{"type":"object","properties":{"brandId":{"type":"string"},"brandName":{"type":"string"},"modelId":{"type":"string"},"modelName":{"type":"string"},"variationId":{"type":"string"},"variationName":{"type":"string"},"globalChartName":{"type":"string"},"sizeSystem":{"type":"string"},"size":{"type":"string"},"lengthMm":{"type":"integer","format":"int32"},"metadata":{"type":"object","additionalProperties":{"type":"string"}}}},"NextStep":{"type":"object","properties":{"prompt":{"type":"string"},"options":{"type":"array","items":{"$ref":"#/components/schemas/SelectionOption"}},"sizeOptions":{"type":"array","items":{"$ref":"#/components/schemas/SizeOption"}}}},"SelectionOption":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"ShoeSelectionResponse":{"type":"object","properties":{"selection":{"$ref":"#/components/schemas/ShoeSelection"},"complete":{"type":"boolean"},"nextStep":{"$ref":"#/components/schemas/NextStep"},"shoe":{"$ref":"#/components/schemas/CanonicalShoe"}}},"SizeOption":{"type":"object","properties":{"size":{"type":"string"},"sizeSystem":{"type":"string"}}},"SessionResponse":{"type":"object","properties":{"sessionId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"shoeCount":{"type":"integer","format":"int32"},"hasFootMeasurement":{"type":"boolean"}}},"AddShoeRequest":{"required":["shoe"],"type":"object","properties":{"shoe":{"$ref":"#/components/schemas/ShoeSelection"}}},"RecommendationRequest":{"required":["target"],"type":"object","properties":{"target":{"$ref":"#/components/schemas/ShoeSelection"}}},"ConfidenceEntry":{"type":"object","properties":{"source":{"type":"string"},"description":{"type":"string"},"footLengthMm":{"type":"integer","format":"int32"}}},"RecommendationResponse":{"type":"object","properties":{"recommendedSize":{"type":"string"},"sizeSystem":{"type":"string"},"confidenceBasis":{"type":"array","items":{"$ref":"#/components/schemas/ConfidenceEntry"}}}},"AddFootMeasurementRequest":{"type":"object","properties":{"rightFootLengthMm":{"maximum":400,"minimum":100,"type":"integer","format":"int32"},"leftFootLengthMm":{"maximum":400,"minimum":100,"type":"integer","format":"int32"}}},"FootMeasurementView":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"rightFootLengthMm":{"type":"integer","format":"int32"},"leftFootLengthMm":{"type":"integer","format":"int32"}}},"ShoeView":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"brandId":{"type":"string"},"modelId":{"type":"string"},"variationId":{"type":"string"},"sizeSystem":{"type":"string"},"size":{"type":"string"},"metadata":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"BadRequest":{"description":"INVALID_INPUT — the request body, query, or path failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"default":{"$ref":"#/components/examples/InvalidInputExample"}}}}},"Unauthenticated":{"description":"UNAUTHENTICATED — missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"default":{"$ref":"#/components/examples/UnauthenticatedExample"}}}}},"SessionNotFound":{"description":"SESSION_NOT_FOUND — the session does not exist, has expired, or belongs to a different key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"default":{"$ref":"#/components/examples/SessionNotFoundExample"}}}}},"Conflict":{"description":"LIMIT_EXCEEDED — a per-session or per-key limit was hit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"default":{"$ref":"#/components/examples/LimitExceededExample"}}}}},"RateLimited":{"description":"RATE_LIMITED — exceeded 60 req/min (default). See `Retry-After` (seconds).","headers":{"Retry-After":{"description":"Number of seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"default":{"$ref":"#/components/examples/RateLimitedExample"}}}}},"InternalError":{"description":"INTERNAL_ERROR — unexpected server fault. Include the correlation id from `message` when reporting.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"examples":{"InvalidInputExample":{"value":"{ \"error\": { \"code\": \"INVALID_INPUT\", \"message\": \"purpose: must be one of [ADD_TO_RACK, RECOMMENDATION_TARGET]\" } }\n"},"UnauthenticatedExample":{"value":"{ \"error\": { \"code\": \"UNAUTHENTICATED\", \"message\": \"Invalid or missing API key.\" } }\n"},"SessionNotFoundExample":{"value":"{ \"error\": { \"code\": \"SESSION_NOT_FOUND\", \"message\": \"Session not found.\" } }\n"},"RateLimitedExample":{"value":"{ \"error\": { \"code\": \"RATE_LIMITED\", \"message\": \"Rate limit exceeded. Retry after 37 seconds.\" } }\n"},"LimitExceededExample":{"value":"{ \"error\": { \"code\": \"LIMIT_EXCEEDED\", \"message\": \"Maximum of 20 shoes per session reached.\" } }\n"}},"headers":{"X-RateLimit-Limit":{"description":"Total requests allowed per minute for this API key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current 60-second window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix epoch (seconds) when the current window resets.","schema":{"type":"integer"}}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","description":"Developer API key in the form `gsk_live_...`","name":"X-Api-Key","in":"header"}}}}