{"openapi":"3.1.0","info":{"title":"Ukrainian Pattern Archive API","version":"v1","description":"Search and identification of embroidery patterns. Exact identity follows contract upa:inv:v1: keys are unchanged by rotation, mirror, repeat phase and repeat count, in colour, palette-renaming and colour-blind modes. Near-variants follow upa:sim:v1: graded similarity after stitch edits, with thresholds calibrated to at most 1% false positives among the nearest unrelated patterns. Similar patterns are evidence only; they are never merged and similarity is not transitive."},"servers":[{"url":"/non/upa/"}],"paths":{"/api/v1":{"get":{"summary":"Service description","operationId":"describe","responses":{"200":{"description":"Contracts, thresholds, corpus size and endpoints","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DescribeResponse"}}}},"503":{"description":"Database unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/patterns":{"get":{"summary":"Search patterns","operationId":"searchPatterns","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Text in the pattern id, name or provenance (case-insensitive)."},{"name":"kind","in":"query","schema":{"enum":["band","medallion","diagonal","tile"]},"description":"Catalog motif kind."},{"name":"page","in":"query","schema":{"type":"integer","minimum":0},"description":"Zero-based catalog page index (pdfPage − 1)."},{"name":"frieze","in":"query","schema":{"enum":["p1","p11g","p1m1","p11m","p2","p2mg","p2mm"]},"description":"Stitch-aware frieze group."},{"name":"wallpaper","in":"query","schema":{"type":"string"},"description":"Wallpaper group."},{"name":"profile","in":"query","schema":{"enum":["empty","finite","band","tile"]},"description":"Identity profile of the colour key."},{"name":"status","in":"query","schema":{"enum":["verified","candidate","provisional-source"]},"description":"Identity status of the colour key."},{"name":"color","in":"query","schema":{"type":"array","items":{"$ref":"#/components/schemas/Color"}},"description":"Patterns using every listed ink colour; repeat or comma-separate. Not B (background).","style":"form","explode":true},{"name":"hash","in":"query","schema":{"type":"string","pattern":"^[0-9a-f]{8,64}$"},"description":"Prefix of any invariant (color/palette/structure) or legacy hash."},{"name":"minWidth","in":"query","schema":{"type":"integer","minimum":0},"description":"Minimum width in cells."},{"name":"maxWidth","in":"query","schema":{"type":"integer","minimum":0},"description":"Maximum width in cells."},{"name":"minHeight","in":"query","schema":{"type":"integer","minimum":0},"description":"Minimum height in cells."},{"name":"maxHeight","in":"query","schema":{"type":"integer","minimum":0},"description":"Maximum height in cells."},{"name":"include","in":"query","schema":{"enum":["geometry"]},"description":"Add matrix, stitches and unit cell to every item."},{"name":"sort","in":"query","schema":{"enum":["patternId","symmetry","density"],"default":"patternId"},"description":"Order of results."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Items to skip."}],"responses":{"200":{"description":"A page of matching patterns","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Invalid request; the message names the field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Database unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/patterns/{patternId}":{"get":{"summary":"One pattern with its relations","operationId":"getPattern","parameters":[{"name":"patternId","in":"path","required":true,"schema":{"type":"string"},"example":"p07_L_b07"},{"name":"similar","in":"query","schema":{"type":"integer","minimum":0,"maximum":50,"default":10},"description":"Maximum near-variants returned."}],"responses":{"200":{"description":"Pattern, symmetry, exact matches and near-variants","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatternResponse"}}}},"400":{"description":"Invalid request; the message names the field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such pattern","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Database unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/identify":{"post":{"summary":"Identify a pattern against the archive","operationId":"identify","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentifyRequest"}}}},"responses":{"200":{"description":"Identity, symmetry, exact matches per mode and calibrated near-variants","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentifyResponse"}}}},"400":{"description":"Invalid request; the message names the field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Too large (≤ 128 cells per side, ≤ 8192 cells, tiles ≤ 64, body ≤ 2 MB, ≤ 64 segments per cell)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Database unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/openapi.json":{"get":{"summary":"This document","operationId":"openapi","responses":{"200":{"description":"OpenAPI 3.1"}}}},"/api/v1/docs":{"get":{"summary":"Interactive documentation (Swagger UI)","operationId":"docs","responses":{"200":{"description":"HTML"}}}}},"components":{"schemas":{"Color":{"type":"string","description":"Palette symbol: A red, B white/background, C blue, D black, E green, F yellow, G orange (aliases R, W, K, Y, O… accepted in requests).","examples":["D"]},"Cell":{"description":"A fill (optionally a triangular half) plus independently coloured stitches. Requests also accept legacy strings (., S, /, \\, X, -, |, +, a stitch kind, fill:<shape>), which take their colour from `matrix`.","oneOf":[{"type":"string"},{"type":"object","properties":{"fill":{"anyOf":[{"$ref":"#/components/schemas/Color"},{"type":"null"}]},"fillShape":{"enum":["upper-left","upper-right","lower-left","lower-right"]},"segments":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["top","right","bottom","left","horizontal","vertical","slash","backslash","top-left","top-right","right-top","right-bottom","bottom-left","bottom-right","left-top","left-bottom","horizontal-left","horizontal-right","vertical-top","vertical-bottom","slash-bottom-left","slash-top-right","backslash-top-left","backslash-bottom-right","corner-tl-to-right","corner-bl-to-right","corner-tr-to-left","corner-br-to-left","corner-tl-to-bottom","corner-tr-to-bottom","corner-bl-to-top","corner-br-to-top"]},"color":{"$ref":"#/components/schemas/Color"}},"required":["kind","color"]},"maxItems":64},"sourcePixels":{"type":"array","items":{"type":"array","items":{"$ref":"#/components/schemas/Color"},"minItems":5,"maxItems":5},"minItems":5,"maxItems":5,"description":"Unrecognised 5×5 source patch; it matches anything in symmetry tests."}},"required":["segments"]}]},"Grid":{"type":"array","items":{"type":"array","items":{"$ref":"#/components/schemas/Color"}}},"Geometry":{"type":"object","properties":{"matrix":{"$ref":"#/components/schemas/Grid"},"stitches":{"anyOf":[{"type":"array","items":{"type":"array","items":{"$ref":"#/components/schemas/Cell"}}},{"type":"null"}]},"unitCell":{"anyOf":[{"$ref":"#/components/schemas/Grid"},{"type":"null"}]}},"required":["matrix","stitches","unitCell"]},"Hashes":{"type":"object","properties":{"color":{"type":"string"},"palette":{"type":"string"},"structure":{"type":"string"}},"required":["color","palette","structure"]},"StoredSymmetry":{"type":"object","description":"Symmetry stored with the pattern.","properties":{"frieze":{"type":["string","null"]},"wallpaper":{"type":["string","null"]},"score":{"type":["number","null"]},"period":{"type":["integer","null"]}},"required":["frieze","wallpaper","score","period"]},"IdentitySummary":{"type":"object","properties":{"version":{"const":"upa:inv:v1"},"profile":{"enum":["empty","finite","band","tile"]},"status":{"enum":["verified","candidate","provisional-source"]},"hashes":{"$ref":"#/components/schemas/Hashes"}},"required":["version","profile","status","hashes"]},"PeriodEvidence":{"type":"object","properties":{"period":{"type":"integer"},"observed":{"type":"integer"},"closed":{"type":"boolean"}},"required":["period","observed","closed"]},"ModeIdentity":{"type":"object","description":"Analysis behind one key: the basis, periods and the canonical move.","properties":{"profile":{"enum":["empty","finite","band","tile"]},"status":{"enum":["verified","candidate","provisional-source"]},"basis":{"type":"object","properties":{"x":{"type":"integer"},"y":{"type":"integer"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["x","y","width","height"]},"periods":{"type":"object","properties":{"x":{"$ref":"#/components/schemas/PeriodEvidence"},"y":{"$ref":"#/components/schemas/PeriodEvidence"}},"required":[]},"notes":{"type":"array","items":{"type":"string"}},"d4":{"enum":["r0","r90","r180","r270","m0","m90","m180","m270"]},"shift":{"type":"array","items":{"type":"integer"},"minItems":2,"maxItems":2},"palette":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Color"}},"informative":{"type":"boolean","description":"False when every basis cell is alike, so the key says nothing about a motif."}},"required":["profile","status","basis","periods","notes","d4","shift"]},"PatternRef":{"type":"object","properties":{"patternId":{"type":"string","examples":["p07_L_b07"]},"name":{"type":"string"},"kind":{"type":["string","null"]},"pdfPage":{"type":["integer","null"],"description":"Printed PDF page (catalogPage + 1)."},"links":{"type":"object","properties":{"self":{"type":"string"},"catalog":{"type":["string","null"]}},"required":["self","catalog"]}},"required":["patternId","name","kind","pdfPage","links"]},"PatternSummary":{"type":"object","properties":{"patternId":{"type":"string","examples":["p07_L_b07"]},"name":{"type":"string"},"kind":{"type":["string","null"]},"pdfPage":{"type":["integer","null"],"description":"Printed PDF page (catalogPage + 1)."},"links":{"type":"object","properties":{"self":{"type":"string"},"catalog":{"type":["string","null"]}},"required":["self","catalog"]},"catalogPage":{"type":["integer","null"],"description":"Zero-based page index used by the catalog data."},"width":{"type":"integer"},"height":{"type":"integer"},"colors":{"type":"array","items":{"$ref":"#/components/schemas/Color"}},"symmetry":{"$ref":"#/components/schemas/StoredSymmetry"},"identity":{"anyOf":[{"$ref":"#/components/schemas/IdentitySummary"},{"type":"null"}]},"geometry":{"$ref":"#/components/schemas/Geometry"}},"required":["patternId","name","kind","pdfPage","links","catalogPage","width","height","colors","symmetry","identity"]},"PatternDetail":{"type":"object","properties":{"patternId":{"type":"string","examples":["p07_L_b07"]},"name":{"type":"string"},"kind":{"type":["string","null"]},"pdfPage":{"type":["integer","null"],"description":"Printed PDF page (catalogPage + 1)."},"links":{"type":"object","properties":{"self":{"type":"string"},"catalog":{"type":["string","null"]}},"required":["self","catalog"]},"catalogPage":{"type":["integer","null"],"description":"Zero-based page index used by the catalog data."},"width":{"type":"integer"},"height":{"type":"integer"},"colors":{"type":"array","items":{"$ref":"#/components/schemas/Color"}},"symmetry":{"$ref":"#/components/schemas/StoredSymmetry"},"identity":{"anyOf":[{"$ref":"#/components/schemas/IdentitySummary"},{"type":"null"}]},"geometry":{"$ref":"#/components/schemas/Geometry"},"provenance":{"type":["string","null"]},"density":{"type":["number","null"]},"bbox":{"anyOf":[{"type":"array","items":{"type":"number"},"minItems":4,"maxItems":4},{"type":"null"}]},"legacyHashes":{"type":"object","properties":{"colorHash":{"type":"string"},"structureHash":{"type":"string"}},"required":["colorHash","structureHash"]},"canonicalTransform":{"anyOf":[{"type":"object","properties":{"color":{"$ref":"#/components/schemas/ModeIdentity"},"palette":{"$ref":"#/components/schemas/ModeIdentity"},"structure":{"$ref":"#/components/schemas/ModeIdentity"}},"required":["color","palette","structure"]},{"type":"null"}]}},"required":["patternId","name","kind","pdfPage","links","catalogPage","width","height","colors","symmetry","identity","geometry","provenance","density","bbox","legacyHashes","canonicalTransform"]},"Relation":{"type":"object","description":"Move the first pattern by `d4` (r = clockwise rotation, m = mirror columns, then rotate), then start it `shift` cells later; `palette` maps its colours.","properties":{"d4":{"enum":["r0","r90","r180","r270","m0","m90","m180","m270"]},"shift":{"type":"array","items":{"type":"integer"},"minItems":2,"maxItems":2},"palette":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Color"}}},"required":["d4","shift"]},"Match":{"type":"object","properties":{"patternId":{"type":"string","examples":["p07_L_b07"]},"name":{"type":"string"},"kind":{"type":["string","null"]},"pdfPage":{"type":["integer","null"],"description":"Printed PDF page (catalogPage + 1)."},"links":{"type":"object","properties":{"self":{"type":"string"},"catalog":{"type":["string","null"]}},"required":["self","catalog"]},"relation":{"anyOf":[{"$ref":"#/components/schemas/Relation"},{"type":"null"}]}},"required":["patternId","name","kind","pdfPage","links","relation"]},"Matches":{"type":"object","description":"Exact matches per requested mode.","properties":{"color":{"type":"array","items":{"$ref":"#/components/schemas/Match"}},"palette":{"type":"array","items":{"$ref":"#/components/schemas/Match"}},"structure":{"type":"array","items":{"$ref":"#/components/schemas/Match"}}},"required":[]},"Edits":{"type":"object","properties":{"fillAdded":{"type":"integer"},"fillRemoved":{"type":"integer"},"fillShape":{"type":"integer"},"fillColor":{"type":"integer"},"stitchAdded":{"type":"integer"},"stitchRemoved":{"type":"integer"},"stitchColor":{"type":"integer"},"moved":{"type":"integer"},"cells":{"type":"integer"}},"required":["fillAdded","fillRemoved","fillShape","fillColor","stitchAdded","stitchRemoved","stitchColor","moved","cells"]},"SimilarVariant":{"type":"object","properties":{"patternId":{"type":"string","examples":["p07_L_b07"]},"name":{"type":"string"},"kind":{"type":["string","null"]},"pdfPage":{"type":["integer","null"],"description":"Printed PDF page (catalogPage + 1)."},"links":{"type":"object","properties":{"self":{"type":"string"},"catalog":{"type":["string","null"]}},"required":["self","catalog"]},"mode":{"enum":["color","palette","structure"],"description":"Strictest mode at or above its threshold."},"similarity":{"type":"number"},"scores":{"type":"object","properties":{"color":{"type":"number"},"palette":{"type":"number"},"structure":{"type":"number"}},"required":["color","palette","structure"]},"knownFraction":{"type":"number"},"relation":{"$ref":"#/components/schemas/Relation"},"edits":{"$ref":"#/components/schemas/Edits"}},"required":["patternId","name","kind","pdfPage","links","mode","similarity","scores","knownFraction","relation","edits"]},"SymmetryAnalysis":{"type":"object","properties":{"frieze":{"enum":["p1","p11g","p1m1","p11m","p2","p2mg","p2mm"]},"wallpaper":{"type":"string"},"score":{"type":"number"},"basis":{"enum":["repeat","excerpt","motif","empty"]},"period":{"type":"integer"},"elements":{"type":"array","items":{"type":"object","properties":{"d4":{"enum":["r0","r90","r180","r270","m0","m90","m180","m270"]},"shift":{"type":"array","items":{"type":"integer"},"minItems":2,"maxItems":2}},"required":["d4","shift"]}},"near":{"type":"array","items":{"type":"object","properties":{"op":{"enum":["verticalMirror","horizontalMirror","rotation180","rotation90","glide"]},"mismatches":{"type":"integer"},"cells":{"type":"array","items":{"type":"array","items":{"type":"integer"},"minItems":2,"maxItems":2}}},"required":["op","mismatches","cells"]}}},"required":["frieze","wallpaper","score","basis","period","elements","near"]},"SimilarityInfo":{"type":"object","properties":{"version":{"type":"string"},"thresholds":{"type":"object","properties":{"color":{"type":"number"},"palette":{"type":"number"},"structure":{"type":"number"}},"required":["color","palette","structure"]}},"required":["version","thresholds"]},"IdentifyRequest":{"type":"object","description":"Give `stitches`, `matrix` or both (same size).","properties":{"stitches":{"type":"array","items":{"type":"array","items":{"$ref":"#/components/schemas/Cell"}}},"matrix":{"$ref":"#/components/schemas/Grid"},"kind":{"enum":["band","tile","medallion","diagonal","motif"],"default":"motif","description":"band: repeats horizontally; tile: in both directions; others are finite motifs."},"axes":{"type":"array","items":{"enum":["x","y"]},"description":"Repeat axes; overrides kind (a vertical band: [\"y\"])."},"modes":{"type":"array","items":{"enum":["color","palette","structure"]},"default":["color","palette","structure"]},"similar":{"type":"integer","minimum":0,"maximum":50,"default":10}},"required":[],"examples":[{"kind":"band","stitches":[[{"fill":"A","segments":[]},{"fill":null,"segments":[{"kind":"slash","color":"D"}]}]]}]},"IdentifyResponse":{"type":"object","properties":{"apiVersion":{"const":"v1"},"identity":{"type":"object","properties":{"version":{"const":"upa:inv:v1"},"profile":{"enum":["empty","finite","band","tile"]},"status":{"enum":["verified","candidate","provisional-source"]},"hashes":{"$ref":"#/components/schemas/Hashes"},"modes":{"type":"object","properties":{"color":{"$ref":"#/components/schemas/ModeIdentity"},"palette":{"$ref":"#/components/schemas/ModeIdentity"},"structure":{"$ref":"#/components/schemas/ModeIdentity"}},"required":["color","palette","structure"]}},"required":["version","profile","status","hashes","modes"]},"symmetry":{"$ref":"#/components/schemas/SymmetryAnalysis"},"matches":{"$ref":"#/components/schemas/Matches"},"similar":{"type":"array","items":{"$ref":"#/components/schemas/SimilarVariant"}},"similarity":{"$ref":"#/components/schemas/SimilarityInfo"}},"required":["apiVersion","identity","symmetry","matches","similar","similarity"]},"PatternResponse":{"type":"object","properties":{"apiVersion":{"const":"v1"},"pattern":{"$ref":"#/components/schemas/PatternDetail"},"symmetry":{"$ref":"#/components/schemas/SymmetryAnalysis"},"matches":{"$ref":"#/components/schemas/Matches"},"similar":{"type":"array","items":{"$ref":"#/components/schemas/SimilarVariant"}},"similarity":{"$ref":"#/components/schemas/SimilarityInfo"}},"required":["apiVersion","pattern","symmetry","matches","similar","similarity"]},"SearchResponse":{"type":"object","properties":{"apiVersion":{"const":"v1"},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"nextOffset":{"type":["integer","null"],"description":"Offset of the next page; null on the last page."},"items":{"type":"array","items":{"$ref":"#/components/schemas/PatternSummary"}}},"required":["apiVersion","total","limit","offset","nextOffset","items"]},"DescribeResponse":{"type":"object","properties":{"apiVersion":{"const":"v1"},"contracts":{"type":"object","properties":{"identity":{"type":"string"},"similarity":{"type":"string"}},"required":["identity","similarity"]},"corpus":{"type":"object","properties":{"patterns":{"type":"integer"},"withIdentity":{"type":"integer"}},"required":["patterns","withIdentity"]},"similarity":{"type":"object","properties":{"version":{"type":"string"},"weights":{"type":"object","properties":{"fill":{"type":"number"},"fillShape":{"type":"number"},"fillColor":{"type":"number"},"stitch":{"type":"number"},"stitchColor":{"type":"number"}},"required":["fill","fillShape","fillColor","stitch","stitchColor"]},"thresholds":{"type":"object","properties":{"color":{"type":"number"},"palette":{"type":"number"},"structure":{"type":"number"}},"required":["color","palette","structure"]}},"required":["version","weights","thresholds"]},"endpoints":{"type":"object","properties":{"search":{"type":"string"},"pattern":{"type":"string"},"identify":{"type":"string"},"openapi":{"type":"string"},"docs":{"type":"string"}},"required":["search","pattern","identify","openapi","docs"]}},"required":["apiVersion","contracts","corpus","similarity","endpoints"]},"Error":{"type":"object","properties":{"apiVersion":{"const":"v1"},"error":{"type":"object","properties":{"code":{"enum":["invalid_request","invalid_json","too_large","not_found","unavailable","internal"]},"message":{"type":"string"},"details":{}},"required":["code","message"]}},"required":["apiVersion","error"]}}}}