{"openapi":"3.1.0","info":{"title":"Nordic Hackathon 2026 EPS service","summary":"Validate and score European Patient Summary bundles.","description":"Register a company, submit FHIR R4 EPS bundles for validation against `http://hl7.eu/fhir/eps/StructureDefinition/bundle-eu-eps`, and fetch other companies' documents to test against.\n\nTeam endpoints take the token from `POST /api/register`, sent as `X-Team-Token: TOKEN` or `Authorization: Bearer TOKEN`.","version":"1.0.0"},"paths":{"/api/register":{"post":{"tags":["Companies"],"summary":"Register a company and get its token","description":"One registration per company. The token comes back once and is not retrievable afterwards, so share it inside the company rather than registering again. Set REGISTER_CODE on the server to require a `code` field in the body as well.","operationId":"register_api_register_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["team"],"properties":{"team":{"type":"string","minLength":2,"maxLength":40,"description":"Company name, shown on the leaderboard."},"code":{"type":"string","description":"Only when the server sets REGISTER_CODE."}}},"example":{"team":"FHIR Starters"}}}}}},"/api/me":{"get":{"tags":["Companies"],"summary":"Which company this token belongs to","description":"The UI needs this to know which screenshots are yours to edit or withdraw. It returns no secrets - the token is the secret, and the caller already has it.","operationId":"whoami_api_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Whoami Api Me Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"TeamToken":[]}]}},"/api/eps":{"post":{"tags":["Submissions"],"summary":"Validate and score a bundle","description":"Sends the bundle to Matchbox for validation against the EPS profile, stores the result and returns the FHIR OperationOutcome. The score is in the response headers, not the body. 413 if the bundle is larger than MAX_BODY_BYTES, 502 if Matchbox cannot be reached.","operationId":"submit_eps_api_eps_post","responses":{"200":{"description":"The Matchbox OperationOutcome for this bundle.","content":{"application/fhir+json":{"schema":{"type":"object"}}},"headers":{"X-Pass":{"description":"true when the bundle had no error or fatal issue","schema":{"type":"string"}},"X-Score":{"description":"points this submission earned, bonuses included","schema":{"type":"integer"}},"X-Errors":{"description":"count of error and fatal issues","schema":{"type":"integer"}},"X-Sections":{"description":"distinct populated Composition sections","schema":{"type":"integer"}},"X-Resources":{"description":"clinical resources counted for richness","schema":{"type":"integer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"TeamToken":[]}],"requestBody":{"required":true,"content":{"application/fhir+json":{"schema":{"type":"object","description":"A FHIR R4 Bundle of type 'document'."},"example":{"resourceType":"Bundle","type":"document","entry":[]}},"application/json":{"schema":{"type":"object"}}}}}},"/api/leaderboard":{"get":{"tags":["Submissions"],"summary":"Current standings","description":"One row per registered company, best score first. Companies that have registered but never submitted appear at the bottom with no score.","operationId":"leaderboard_api_leaderboard_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response Leaderboard Api Leaderboard Get"}}}}}}},"/api/submissions":{"get":{"tags":["Submissions"],"summary":"Submission history","description":"Every company's attempts, newest first, or one company's with `team`.","operationId":"list_submissions_api_submissions_get","parameters":[{"name":"team","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Team"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Submissions Api Submissions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/submissions/{sub_id}":{"get":{"tags":["Submissions"],"summary":"One submission in full","description":"The validation verdict plus a readable summary of the bundle: patient, sections and the clinical items under each one.","operationId":"submission_detail_api_submissions__sub_id__get","parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"integer","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Submission Detail Api Submissions  Sub Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/submissions/{sub_id}/bundle":{"get":{"tags":["Submissions"],"summary":"Download the submitted bytes","description":"The exact bytes that were posted, unmodified.","operationId":"submission_bundle_api_submissions__sub_id__bundle_get","parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"integer","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/samples":{"get":{"tags":["Samples"],"summary":"List the worked examples","description":"Synthetic documents for the event scenarios. No real patient data.","operationId":"list_samples_api_samples_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Samples Api Samples Get"}}}}}}},"/api/samples/{sample_id}":{"get":{"tags":["Samples"],"summary":"One worked example","description":"The same readable summary shape as a submission, plus the scenario it illustrates.","operationId":"sample_detail_api_samples__sample_id__get","parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"string","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sample Detail Api Samples  Sample Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/samples/{sample_id}/bundle":{"get":{"tags":["Samples"],"summary":"Download a worked example","description":"The example bundle as FHIR JSON, for use as test input.","operationId":"sample_bundle_api_samples__sample_id__bundle_get","parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"string","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/exchange":{"get":{"tags":["Interop"],"summary":"Documents published for exchange","description":"Each company's best valid submission is published automatically. The list is open - the documents are the event's shared test corpus.","operationId":"exchange_list_api_exchange_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response Exchange List Api Exchange Get"}}}}}}},"/api/exchange/{team_slug}":{"get":{"tags":["Interop"],"summary":"Fetch a partner's document","description":"The published bundle, ready to load into your own system.","operationId":"exchange_fetch_api_exchange__team_slug__get","parameters":[{"name":"team_slug","in":"path","required":true,"schema":{"type":"string","title":"Team Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/exchange/{team_slug}/renderings":{"post":{"tags":["Interop"],"summary":"Publish a screenshot of a partner's document in your system","description":"Load a partner's exchange document into your own system, screenshot what it looks like, and POST the image bytes here. The body is the raw image - PNG, JPEG or WebP - not a multipart form. Use `note` to say what the picture shows. Nothing about this is scored. 400 if the body is not one of those three formats or the document is your own, 413 over MAX_IMAGE_BYTES.","operationId":"add_rendering_api_exchange__team_slug__renderings_post","parameters":[{"name":"team_slug","in":"path","required":true,"schema":{"type":"string","title":"Team Slug"}},{"name":"note","in":"query","required":false,"schema":{"type":"string","default":"","title":"Note"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"TeamToken":[]}],"requestBody":{"required":true,"description":"The raw image bytes - not a multipart form.","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}}},"/api/renderings":{"get":{"tags":["Interop"],"summary":"Screenshots of documents in other systems","description":"Newest first. Filter by `document` (a submission id), by `producer` or by `consumer` (company slugs). Unfiltered it is every screenshot the event has collected.","operationId":"list_renderings_api_renderings_get","parameters":[{"name":"document","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Document"}},{"name":"producer","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Producer"}},{"name":"consumer","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Consumer"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Renderings Api Renderings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/renderings/{rendering_id}/image":{"get":{"tags":["Interop"],"summary":"The screenshot itself","description":"The image bytes, served as the type its own bytes proved.","operationId":"rendering_image_api_renderings__rendering_id__image_get","parameters":[{"name":"rendering_id","in":"path","required":true,"schema":{"type":"integer","title":"Rendering Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/renderings/{rendering_id}":{"patch":{"tags":["Interop"],"summary":"Rewrite the note on a screenshot you uploaded","description":"The note is where the uploader says what to look at - which section came through wrong, what the picture is meant to show. It can be rewritten as often as you like; only the company that uploaded the screenshot may do it.","operationId":"update_rendering_api_renderings__rendering_id__patch","parameters":[{"name":"rendering_id","in":"path","required":true,"schema":{"type":"integer","title":"Rendering Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Update Rendering Api Renderings  Rendering Id  Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"TeamToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["note"],"properties":{"note":{"type":"string","maxLength":2000}}},"example":{"note":"Allergies section came through empty."}}}}},"delete":{"tags":["Interop"],"summary":"Withdraw a screenshot you uploaded","description":"Only the company that uploaded it can remove it; 403 otherwise.","operationId":"delete_rendering_api_renderings__rendering_id__delete","parameters":[{"name":"rendering_id","in":"path","required":true,"schema":{"type":"integer","title":"Rendering Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Rendering Api Renderings  Rendering Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"TeamToken":[]}]}},"/api/health":{"get":{"tags":["Service"],"summary":"Service and validator health","description":"Reports whether Matchbox is reachable (`up`), reachable but missing a package named in VALIDATION_IGS (`degraded` - profile claims from that package go unchecked), or unreachable (`down` - submissions fail). Also carries the bundle size limit and whether registration needs a code, for clients that want to warn before a doomed request.","operationId":"health_api_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Api Health Get"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"TeamToken":{"type":"apiKey","in":"header","name":"X-Team-Token","description":"The token returned by POST /api/register."}}}}