{"openapi":"3.1.0","info":{"title":"Taply API","version":"0.0.0"},"paths":{"/health":{"get":{"operationId":"getHealth","summary":"Read API readiness across required subsystems (API-FND-10, API-OBS-1)","tags":["health"],"security":[],"responses":{"200":{"description":"Every required subsystem is ready","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"checks":{"type":"object","properties":{"d1":{"type":"string","enum":["ok","fail"]},"auth":{"type":"string","enum":["ok","fail"]},"access":{"type":"string","enum":["ok","fail"]},"kv":{"type":"string","enum":["ok","fail"]},"r2":{"type":"string","enum":["ok","fail"]},"mediaSourceSigning":{"type":"string","enum":["ok","fail"]},"claimCodeHmac":{"type":"string","enum":["ok","fail"]}},"required":["d1","auth","access","kv","r2","mediaSourceSigning","claimCodeHmac"],"additionalProperties":false}},"required":["status","checks"],"additionalProperties":false}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"One or more required subsystems are unavailable or unconfigured","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"checks":{"type":"object","properties":{"d1":{"type":"string","enum":["ok","fail"]},"auth":{"type":"string","enum":["ok","fail"]},"access":{"type":"string","enum":["ok","fail"]},"kv":{"type":"string","enum":["ok","fail"]},"r2":{"type":"string","enum":["ok","fail"]},"mediaSourceSigning":{"type":"string","enum":["ok","fail"]},"claimCodeHmac":{"type":"string","enum":["ok","fail"]}},"required":["d1","auth","access","kv","r2","mediaSourceSigning","claimCodeHmac"],"additionalProperties":false}},"required":["status","checks"],"additionalProperties":false}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiDocument","summary":"Read this OpenAPI 3.1 document (API-FND-10)","tags":["health"],"security":[],"responses":{"200":{"description":"Taply API OpenAPI 3.1 document","content":{"application/json":{"schema":{}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/me":{"get":{"operationId":"getMe","summary":"Synchronize the caller and read onboarding state (API-AUTH-3)","tags":["identity"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Authenticated account/member state","content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","minLength":1},"memberId":{"type":"string","minLength":1},"onboarded":{"type":"boolean"},"profileIds":{"type":"array","items":{"type":"string","minLength":1}},"profileId":{"type":"string","minLength":1},"email":{"type":"string","minLength":1},"name":{"type":"string","minLength":1}},"required":["accountId","memberId","onboarded","profileIds"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/onboarding/sessions":{"post":{"operationId":"createOnboardingSession","summary":"Start or resume the caller's onboarding session (TAP-140)","tags":["onboarding"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Existing active onboarding session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSession"}}}},"201":{"description":"New onboarding session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSession"}}}},"400":{"description":"Request failed validation; `error.details` lists the offending fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/onboarding/sessions/{id}":{"get":{"operationId":"getOnboardingSession","summary":"Read a caller-owned onboarding session (TAP-140)","tags":["onboarding"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Caller-owned onboarding session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSession"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Onboarding session not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateOnboardingSession","summary":"Persist one onboarding step under version CAS (TAP-140)","tags":["onboarding"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"stepKey":{"type":"string","enum":["destination_kind","custom_url","taply_page_type","taply_page_identity","taply_page_professional","taply_page_business","taply_page_networks","taply_page_theme","complete"]},"kind":{"anyOf":[{"type":"string","enum":["taply_page","custom_url"]},{"type":"null"}]},"answers":{"type":"object","properties":{"schemaVersion":{"type":"number","const":1},"customUrl":{"type":"string"},"profileType":{"type":"string","enum":["professional","business"]},"photoMediaId":{"type":"string","minLength":1},"displayName":{"type":"string","maxLength":120},"headline":{"type":"string","maxLength":160},"slug":{"type":"string","maxLength":30},"slugEdited":{"type":"boolean"},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"networks":{"maxItems":32,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"url":{"type":"string","maxLength":2048}},"required":["productId","url"],"additionalProperties":false}},"themeId":{"type":"string","maxLength":64}},"required":["schemaVersion"],"additionalProperties":false}},"required":["version","stepKey","kind","answers"],"additionalProperties":false}}}},"responses":{"200":{"description":"Updated onboarding session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSession"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Onboarding session not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Onboarding session version is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteOnboardingSession","summary":"Delete a caller-owned onboarding session (TAP-140)","tags":["onboarding"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"204":{"description":"Onboarding session deleted"},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Onboarding session not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/onboarding/sessions/{id}/complete":{"post":{"operationId":"completeOnboardingSession","summary":"Complete onboarding under version CAS (TAP-140/TAP-141)","tags":["onboarding"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["version"],"additionalProperties":false}}}},"responses":{"200":{"description":"Completed session and materialized Destination; the Taply Page branch also returns the Profile this write created (TAP-141)","content":{"application/json":{"schema":{"type":"object","properties":{"session":{"$ref":"#/components/schemas/OnboardingSession"},"destination":{"$ref":"#/components/schemas/Destination"},"profile":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}},"required":["session","destination"],"additionalProperties":false}}}},"400":{"description":"Validation error or incomplete onboarding session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Onboarding session not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Onboarding session version is stale, or the chosen Slug is no longer available (slug_taken)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/slugs/{slug}/availability":{"get":{"operationId":"checkSlugAvailability","summary":"Check whether a slug is available to claim (API-PROF-1)","tags":["profiles"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"slug","schema":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"required":true}],"responses":{"200":{"description":"Collapsed slug availability result","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"type":"boolean"},"reason":{"type":"string","enum":["invalid"]}},"required":["available"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found, or not visible to the caller (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles":{"post":{"operationId":"createProfile","summary":"Create the caller's profile (API-PROF-2)","tags":["profiles"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["professional","business"]},"displayName":{"type":"string","minLength":1,"maxLength":120},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},"required":["type","displayName","slug"],"additionalProperties":false}}}},"responses":{"201":{"description":"Profile created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Slug unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listProfiles","summary":"List the caller's profiles (API-PROF-2)","tags":["profiles"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Caller-owned profiles","content":{"application/json":{"schema":{"type":"object","properties":{"profiles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}},"required":["profiles"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}":{"get":{"operationId":"getProfile","summary":"Get a caller-owned profile in detail (API-PROF-2)","tags":["profiles"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Profile detail","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"},"links":{"type":"array","items":{}},"media":{"type":"array","items":{}},"cards":{"type":"array","items":{}}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt","links","media","cards"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateProfile","summary":"Update caller-owned profile fields (API-PROF-3)","tags":["profiles"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"headline":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"belongsToBusinessName":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"businessCategory":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"businessDetails":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}]}},"additionalProperties":false}}}},"responses":{"200":{"description":"Updated profile","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/avatar_media_id":{"patch":{"operationId":"updateProfileAvatar","summary":"Set or clear a caller-owned profile's avatar media (API-MEDIA-5)","tags":["profiles","media"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"avatarMediaId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]}},"required":["avatarMediaId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Updated profile","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile or media not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/slug":{"post":{"operationId":"changeProfileSlug","summary":"Change a caller-owned profile's slug (API-PROF-4)","tags":["profiles"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},"required":["slug"],"additionalProperties":false}}}},"responses":{"200":{"description":"Profile with its current slug","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Slug unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/publish":{"post":{"operationId":"publishProfile","summary":"Publish a caller-owned profile (API-PROF-5)","tags":["profiles"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Published profile","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Profile does not meet publishability requirements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Taken-down profile cannot be published by its owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/unpublish":{"post":{"operationId":"unpublishProfile","summary":"Unpublish a caller-owned profile (API-PROF-5)","tags":["profiles"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Unpublished profile","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Taken-down profile cannot be unpublished by its owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/links":{"post":{"operationId":"createLink","summary":"Create a link on a caller-owned profile (API-LINK-2)","tags":["links"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"label":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["type","label","url"],"additionalProperties":false}}}},"responses":{"201":{"description":"Link created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"type":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"label":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048},"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"enabled":{"type":"boolean"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","profileId","type","label","url","position","enabled","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error or disallowed link URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listLinks","summary":"List links on a caller-owned profile (API-LINK-2)","tags":["links"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Links ordered by position","content":{"application/json":{"schema":{"type":"object","properties":{"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"type":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"label":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048},"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"enabled":{"type":"boolean"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","profileId","type","label","url","position","enabled","createdAt","updatedAt"],"additionalProperties":false}}},"required":["links"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/links/{linkId}":{"patch":{"operationId":"updateLink","summary":"Update a link on a caller-owned profile (API-LINK-3)","tags":["links"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"path","name":"linkId","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"label":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048},"enabled":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Updated link","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"type":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"label":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048},"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"enabled":{"type":"boolean"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","profileId","type","label","url","position","enabled","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error or disallowed link URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile or link not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteLink","summary":"Delete a link from a caller-owned profile (API-LINK-4)","tags":["links"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"path","name":"linkId","schema":{"type":"string","minLength":1},"required":true}],"responses":{"204":{"description":"Link deleted"},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile or link not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/links/reorder":{"post":{"operationId":"reorderLinks","summary":"Set all link positions on a caller-owned profile (API-LINK-5)","tags":["links"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"minItems":1,"type":"array","items":{"type":"object","properties":{"linkId":{"type":"string","minLength":1},"position":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["linkId","position"],"additionalProperties":false}}}}},"responses":{"200":{"description":"Reordered links","content":{"application/json":{"schema":{"type":"object","properties":{"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"type":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"label":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048},"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"enabled":{"type":"boolean"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","profileId","type","label","url","position","enabled","createdAt","updatedAt"],"additionalProperties":false}}},"required":["links"],"additionalProperties":false}}}},"400":{"description":"Validation error or link set mismatch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/media":{"post":{"operationId":"uploadAccountMedia","summary":"Upload raw image bytes, unattached to any Profile yet (TAP-155)","description":"Account-scoped upload for the identity screen, before a Profile exists (ADR-0034/0035). Same raw-body convention as POST /v1/profiles/{id}/media: the request body is the image itself (not multipart). Content-Type must be one of image/jpeg, image/png, image/webp, or image/avif. X-File-Name is optional. The created media's `profileId` is omitted until it is claimed via POST /v1/profiles/{id}/media/{mediaId}/attach.","tags":["media"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Media stored, unattached","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"objectKey":{"type":"string","minLength":1},"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/avif"]},"byteSize":{"type":"integer","exclusiveMinimum":0,"maximum":8388608},"etag":{"type":"string","minLength":1},"originalFilename":{"type":"string","minLength":1},"createdAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","objectKey","contentType","byteSize","createdAt"],"additionalProperties":false}}}},"400":{"description":"Validation error, unsupported bytes, or upload exceeds 8 MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Account media quota exceeded (TAP-157/ADR-0038) — row count or byte total ceiling reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/media/{mediaId}":{"get":{"operationId":"getAccountMedia","summary":"Read image bytes owned by the authenticated account","description":"Reads attached or unattached account media. Supports Range and If-None-Match request headers. Successful, conditional, and range responses use Cache-Control: private, no-store.","tags":["media"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"mediaId","schema":{"type":"string","minLength":1},"required":true},{"in":"header","name":"Range","schema":{"description":"Optional single byte range, for example `bytes=0-499`.","type":"string"},"description":"Optional single byte range, for example `bytes=0-499`."},{"in":"header","name":"If-None-Match","schema":{"description":"Optional entity tag for a conditional read.","type":"string"},"description":"Optional entity tag for a conditional read."}],"responses":{"200":{"description":"Complete media object","headers":{"ETag":{"schema":{"type":"string","description":"Quoted entity tag for the stored media object."}},"Cache-Control":{"required":true,"description":"Account-scoped media is private and must not be stored by caches.","schema":{"type":"string","const":"private, no-store","description":"Account-scoped media is private and must not be stored by caches."}},"Accept-Ranges":{"required":true,"description":"The endpoint accepts byte ranges.","schema":{"type":"string","const":"bytes","description":"The endpoint accepts byte ranges."}}},"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"206":{"description":"Requested byte range","headers":{"ETag":{"schema":{"type":"string","description":"Quoted entity tag for the stored media object."}},"Cache-Control":{"required":true,"description":"Account-scoped media is private and must not be stored by caches.","schema":{"type":"string","const":"private, no-store","description":"Account-scoped media is private and must not be stored by caches."}},"Accept-Ranges":{"required":true,"description":"The endpoint accepts byte ranges.","schema":{"type":"string","const":"bytes","description":"The endpoint accepts byte ranges."}},"Content-Range":{"required":true,"description":"Byte range served, or `bytes */<length>` when the range is unsatisfiable.","schema":{"type":"string","description":"Byte range served, or `bytes */<length>` when the range is unsatisfiable."}}},"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"304":{"description":"Not modified","headers":{"ETag":{"required":true,"description":"Quoted entity tag for the stored media object.","schema":{"type":"string","description":"Quoted entity tag for the stored media object."}},"Cache-Control":{"required":true,"description":"Account-scoped media is private and must not be stored by caches.","schema":{"type":"string","const":"private, no-store","description":"Account-scoped media is private and must not be stored by caches."}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Media not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"416":{"description":"Requested byte range is not satisfiable","headers":{"Cache-Control":{"required":true,"description":"Account-scoped media is private and must not be stored by caches.","schema":{"type":"string","const":"private, no-store","description":"Account-scoped media is private and must not be stored by caches."}},"Content-Range":{"required":true,"description":"Byte range served, or `bytes */<length>` when the range is unsatisfiable.","schema":{"type":"string","description":"Byte range served, or `bytes */<length>` when the range is unsatisfiable."}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/media":{"post":{"operationId":"uploadMedia","summary":"Upload raw image bytes to a caller-owned profile (API-MEDIA-1)","description":"The request body is the image itself (not multipart). Content-Type must be one of image/jpeg, image/png, image/webp, or image/avif. X-File-Name is optional.","tags":["media"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Media stored","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"objectKey":{"type":"string","minLength":1},"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/avif"]},"byteSize":{"type":"integer","exclusiveMinimum":0,"maximum":8388608},"etag":{"type":"string","minLength":1},"originalFilename":{"type":"string","minLength":1},"createdAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","objectKey","contentType","byteSize","createdAt"],"additionalProperties":false}}}},"400":{"description":"Validation error, unsupported bytes, or upload exceeds 8 MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Account media quota exceeded (TAP-157/ADR-0038) — row count or byte total ceiling reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listMedia","summary":"List media metadata for a caller-owned profile (API-MEDIA-2)","tags":["media"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Media metadata","content":{"application/json":{"schema":{"type":"object","properties":{"media":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"objectKey":{"type":"string","minLength":1},"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/avif"]},"byteSize":{"type":"integer","exclusiveMinimum":0,"maximum":8388608},"etag":{"type":"string","minLength":1},"originalFilename":{"type":"string","minLength":1},"createdAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","objectKey","contentType","byteSize","createdAt"],"additionalProperties":false}}},"required":["media"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/media/{mediaId}":{"get":{"operationId":"getMedia","summary":"Read image bytes owned by the caller (API-MEDIA-2)","description":"Supports Range and If-None-Match request headers.","tags":["media"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"path","name":"mediaId","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Complete media object","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"206":{"description":"Requested byte range","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"304":{"description":"Not modified"},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile or media not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"416":{"description":"Requested byte range is not satisfiable"},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteMedia","summary":"Delete media owned by the caller (API-MEDIA-3)","tags":["media"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"path","name":"mediaId","schema":{"type":"string","minLength":1},"required":true}],"responses":{"204":{"description":"Media deleted"},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile or media not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Media is referenced by a published profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/media/{mediaId}/attach":{"post":{"operationId":"attachMedia","summary":"Claim an unattached, account-owned media row onto a caller-owned Profile (TAP-155)","description":"Attaches media uploaded via POST /v1/media to a Profile the caller owns. Claimable only by the account that uploaded it, and only once: a foreign account, a nonexistent media id, and an already-attached row all return the same 404 (ADR-0004, ADR-0035).","tags":["media"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"path","name":"mediaId","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Media attached","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"profileId":{"type":"string","minLength":1},"objectKey":{"type":"string","minLength":1},"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/avif"]},"byteSize":{"type":"integer","exclusiveMinimum":0,"maximum":8388608},"etag":{"type":"string","minLength":1},"originalFilename":{"type":"string","minLength":1},"createdAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","objectKey","contentType","byteSize","createdAt"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found, or media not found/foreign/already attached (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/media/{mediaId}":{"get":{"operationId":"getPublicMedia","summary":"Read a transformed image referenced by a published profile (API-MEDIA-4)","description":"Returns only a Cloudflare-transformed variant. The optional w/h pair must match an allowlisted square preset (64, 128, 256, or 512 pixels).","tags":["media"],"security":[],"parameters":[{"in":"path","name":"mediaId","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"w","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"in":"query","name":"h","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},{"in":"query","name":"format","schema":{"type":"string","enum":["auto","avif","webp"]}},{"in":"query","name":"quality","schema":{"type":"integer","minimum":1,"maximum":100}},{"in":"query","name":"fit","schema":{"type":"string","enum":["scale-down","contain","cover","crop","pad"]}}],"responses":{"200":{"description":"Transformed public image","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Unsupported media variant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Media not found or not referenced by a published profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/media/{mediaId}/source":{"get":{"operationId":"getPublicMediaSource","summary":"Read the short-lived transform source for public media (API-SEC-9)","description":"Cloudflare Image Resizing source endpoint. Requires the server-minted HMAC signature in sig and its expiry in exp; missing, invalid, expired, unpublished, and unknown cases all return 404.","tags":["media"],"security":[{"mediaSourceTokenAuth":[]}],"parameters":[{"in":"path","name":"mediaId","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"exp","schema":{"type":"integer","minimum":0,"maximum":9007199254740991},"required":true},{"in":"query","name":"sig","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Original media bytes for the authorized transform subrequest","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/avif":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Media not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/profiles/{slug}":{"get":{"operationId":"getPublicProfile","summary":"Read a composed published profile by slug (API-PROF-7)","tags":["profiles"],"security":[],"parameters":[{"in":"path","name":"slug","schema":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"required":true}],"responses":{"200":{"description":"Published profile with enabled links and avatar metadata","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"status":{"type":"string","const":"published"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"avatar":{"type":"object","properties":{"id":{"type":"string","minLength":1},"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/avif"]},"byteSize":{"type":"integer","exclusiveMinimum":0,"maximum":8388608}},"required":["id","contentType","byteSize"],"additionalProperties":false},"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"label":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048},"position":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["id","type","label","url","position"],"additionalProperties":false}},"publishedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","type","slug","status","displayName","links","publishedAt"],"additionalProperties":false}}}},"404":{"description":"Published profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/sitemap":{"get":{"operationId":"getPublicSitemap","summary":"List canonical URLs for all published profiles (API-PROF-8)","tags":["profiles"],"security":[],"responses":{"200":{"description":"Published profile sitemap entries","content":{"application/json":{"schema":{"type":"object","properties":{"profiles":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"canonicalUrl":{"type":"string","minLength":1},"publishedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["slug","canonicalUrl","publishedAt"],"additionalProperties":false}}},"required":["profiles"],"additionalProperties":false}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/link-catalogue":{"get":{"operationId":"getPublicLinkCatalogue","summary":"List enabled link products in display order (TAP-131)","tags":["links"],"security":[],"responses":{"200":{"description":"Enabled link catalogue products","content":{"application/json":{"schema":{"type":"object","properties":{"products":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"kind":{"type":"string","enum":["social_media","messaging","review","website","contact","custom"]},"brand":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"displayName":{"type":"string","minLength":1},"iconRef":{"anyOf":[{"type":"string","maxLength":4096},{"type":"null"}]},"displayOrder":{"type":"integer","minimum":0,"maximum":9007199254740991},"enabled":{"type":"boolean"},"scheme":{"anyOf":[{"type":"string","enum":["tel","mailto"]},{"type":"null"}]}},"required":["id","kind","brand","displayName","iconRef","displayOrder","enabled","scheme"],"additionalProperties":false}}},"required":["products"],"additionalProperties":false}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/profiles/{id}/takedown":{"post":{"operationId":"takedownProfile","summary":"Take down a profile and purge its public caches (API-SEC-7)","tags":["profiles"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Taken-down profile","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/profiles/{id}/untakedown":{"post":{"operationId":"untakedownProfile","summary":"Return a taken-down profile to draft (API-SEC-7)","tags":["profiles"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Draft profile","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"type":{"type":"string","enum":["professional","business"]},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"themeId":{"anyOf":[{"type":"string","enum":["profesional","corporativo","emprendedor","tienda-de-barrio"]},{"type":"null"}]},"avatarMediaId":{"type":"string","minLength":1},"headline":{"type":"string","maxLength":160},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"status":{"type":"string","enum":["draft","published","unpublished","taken_down"]},"publishedAt":{"$ref":"#/components/schemas/EpochMs"},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","type","slug","displayName","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Only a taken-down profile can be restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/destinations":{"get":{"operationId":"listDestinations","summary":"List Destinations owned by the caller (TAP-134)","tags":["destinations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Caller-owned Destinations","content":{"application/json":{"schema":{"type":"object","properties":{"destinations":{"type":"array","items":{"$ref":"#/components/schemas/Destination"}}},"required":["destinations"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createDestination","summary":"Create a Destination (TAP-134/TAP-136)","description":"Creates either a Taply Page with {kind:'taply_page',profileId} or a Custom URL with {kind:'custom_url',url}. Custom URLs use the Destinations redirect-target policy.","tags":["destinations"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"taply_page"},"profileId":{"type":"string","minLength":1}},"required":["kind","profileId"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"custom_url"},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["kind","url"],"additionalProperties":false}],"type":"object"}}}},"responses":{"201":{"description":"Destination created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Destination"}}}},"400":{"description":"Validation error or invalid Custom URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Taply Page Profile not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/destinations/{id}":{"get":{"operationId":"getDestination","summary":"Read a caller-owned Destination (TAP-134)","tags":["destinations"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Destination detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Destination"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Destination not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateDestination","summary":"Update a Destination target (TAP-134/TAP-136)","description":"Updates profileId for a Taply Page or url for a Custom URL. Destination kind is immutable.","tags":["destinations"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"profileId":{"type":"string","minLength":1}},"required":["profileId"],"additionalProperties":false},{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["url"],"additionalProperties":false}]}}}},"responses":{"200":{"description":"Updated Destination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Destination"}}}},"400":{"description":"Validation error, target-kind mismatch, or invalid Custom URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Destination or Profile not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteDestination","summary":"Delete an unreferenced caller-owned Destination (TAP-134)","tags":["destinations"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"204":{"description":"Destination deleted"},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Destination not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Destination is referenced by one or more Cards","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/cards":{"post":{"operationId":"registerCards","summary":"Register a batch of cards (API-CARD-3)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":500},"batchId":{"type":"string","minLength":1}},"required":["count"],"additionalProperties":false}}}},"responses":{"201":{"description":"Cards registered","content":{"application/json":{"schema":{"type":"object","properties":{"cards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"},"claimCode":{"type":"string","pattern":"^[0-9A-HJKMNP-TV-Z]{12}$"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt","claimCode"],"additionalProperties":false}}},"required":["cards"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listCards","summary":"List cards, optionally filtered by status/batchId (API-CARD-9)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["unassigned","assigned","disabled","lost"]}},{"in":"query","name":"batchId","schema":{"type":"string","minLength":1}},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Cards page","content":{"application/json":{"schema":{"type":"object","properties":{"cards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}},"nextCursor":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]}},"required":["cards","nextCursor"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/cards/{id}":{"get":{"operationId":"getCardWithHistory","summary":"Get a card and its assignment history (API-CARD-4)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Card and its assignment history","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"},"assignments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"cardId":{"type":"string","minLength":1},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"profileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedBy":{"type":"string","minLength":1},"assignedAt":{"$ref":"#/components/schemas/EpochMs"},"unassignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"reason":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"closedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","cardId","destinationId","profileId","assignedBy","assignedAt","unassignedAt","reason","closedBy","createdAt"],"additionalProperties":false}}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt","assignments"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"transitionCardLifecycle","summary":"Disable, mark lost, or reactivate a card to unassigned (API-CARD-6)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["disabled","lost","unassigned"]}},"required":["status"],"additionalProperties":false}}}},"responses":{"200":{"description":"Card after the lifecycle transition","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Card cannot transition to the requested status from its current state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/cards/{id}/assign":{"post":{"operationId":"assignCard","summary":"Assign an unassigned card to a profile (API-CARD-5)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profileId":{"type":"string","minLength":1}},"required":["profileId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Card after assignment","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card or profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Card is not available to assign","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/cards/{id}/reassign":{"post":{"operationId":"reassignCard","summary":"Reassign an already-assigned card to a new profile (API-CARD-5)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profileId":{"type":"string","minLength":1}},"required":["profileId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Card after reassignment","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card or profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Card is not currently assigned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/cards/{id}/claim-code/regenerate":{"post":{"operationId":"regenerateClaimCode","summary":"Regenerate a card's one-time Claim Code (TAP-132)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"One-time plaintext Claim Code","content":{"application/json":{"schema":{"type":"object","properties":{"claimCode":{"type":"string","pattern":"^[0-9A-HJKMNP-TV-Z]{12}$"}},"required":["claimCode"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Claim Code could not be regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/internal/cards/{id}/unassign":{"post":{"operationId":"unassignCard","summary":"Unassign a currently-assigned card (API-CARD-5)","tags":["cards"],"security":[{"internalOperatorAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Card after unassignment","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Request failed validation; `error.details` lists the offending fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid internal operator principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Card is not currently assigned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/cards":{"get":{"operationId":"listOwnedCards","summary":"List Cards explicitly owned by the caller (TAP-137)","tags":["cards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Caller-owned Cards","content":{"application/json":{"schema":{"type":"object","properties":{"cards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}}},"required":["cards"],"additionalProperties":false}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/cards/claim":{"post":{"operationId":"claimCard","summary":"Claim an unowned Card with its one-time Claim Code (TAP-137)","tags":["cards"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string","minLength":1,"maxLength":255},"required":true}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"claimCode":{"type":"string","pattern":"^[0-9A-HJKMNP-TV-Z]{12}$"},"destinationId":{"type":"string","minLength":1}},"required":["claimCode"],"additionalProperties":false}}}},"responses":{"200":{"description":"Claimed Card","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Claim Code, Card state, or Destination is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/cards":{"get":{"operationId":"listCardsForProfile","summary":"List cards assigned to a profile the caller owns (API-CARD-7)","tags":["cards"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Cards page","content":{"application/json":{"schema":{"type":"object","properties":{"cards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}},"nextCursor":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]}},"required":["cards","nextCursor"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/cards/{id}/destination":{"put":{"operationId":"setCardDestination","summary":"Point an owned Card at an owned Destination (TAP-134)","description":"The Destination relation is authoritative for reads. destination_id and the live legacy target columns are dual-written atomically for rollback safety.","tags":["cards","destinations"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"destinationId":{"type":"string","minLength":1}},"required":["destinationId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Card after Destination binding","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"publicCode":{"type":"string","minLength":1},"accountId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"status":{"type":"string","enum":["unassigned","assigned","disabled","lost"]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedProfileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"assignedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"assignedBy":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"batchId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"targetType":{"type":"string","enum":["profile","external_url"]},"targetUrl":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","publicCode","accountId","status","destinationId","assignedProfileId","assignedAt","assignedBy","batchId","targetType","targetUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"description":"Validation error or invalid stored Custom URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card or Destination not found (404-not-403)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Card Destination changed concurrently","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/resolve/{public_code}":{"get":{"operationId":"resolveCard","summary":"Resolve a physical card's public code to its target (API-CARD-8)","description":"Enumeration-safe (ADR-0021): every non-active case (unknown code, unassigned, disabled, lost, unpublished Profile, or failed Custom URL revalidation) returns the SAME byte-identical `{status:'inactive'}` body at the same HTTP status as the active case — no sub-reason, no oracle. Active results identify either a Taply Page Profile or a stored external URL.","tags":["resolution"],"security":[],"parameters":[{"in":"path","name":"public_code","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"origin","schema":{"type":"string","enum":["nfc","qr"]},"required":true}],"responses":{"200":{"description":"Profile, external URL, or inactive resolution result","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","const":"active"},"targetType":{"type":"string","const":"profile"},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"type":{"type":"string","enum":["professional","business"]}},"required":["status","targetType","slug","type"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","const":"active"},"targetType":{"type":"string","const":"external_url"},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["status","targetType","url"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","const":"inactive"}},"required":["status"],"additionalProperties":false}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found, or not visible to the caller (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/resolve":{"get":{"operationId":"resolveCardEmptyCodeNoSlash","summary":"Resolve with a missing public_code (API-CARD-8, ADR-0021 empty-code edge case)","description":"A missing public_code runs the SAME lookup path as any other code -- it simply misses and returns the identical `{status:'inactive'}` body, never a distinguishable 404.","tags":["resolution"],"security":[],"parameters":[{"in":"query","name":"origin","schema":{"type":"string","enum":["nfc","qr"]},"required":true}],"responses":{"200":{"description":"Resolution result (always inactive for an empty code)","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","const":"active"},"targetType":{"type":"string","const":"profile"},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"type":{"type":"string","enum":["professional","business"]}},"required":["status","targetType","slug","type"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","const":"active"},"targetType":{"type":"string","const":"external_url"},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["status","targetType","url"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","const":"inactive"}},"required":["status"],"additionalProperties":false}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/resolve/":{"get":{"operationId":"resolveCardEmptyCodeTrailingSlash","summary":"Resolve with an empty public_code segment (API-CARD-8, ADR-0021 empty-code edge case)","description":"Same as `GET /v1/public/resolve` above -- an empty trailing segment is treated identically, never a distinguishable 404.","tags":["resolution"],"security":[],"parameters":[{"in":"query","name":"origin","schema":{"type":"string","enum":["nfc","qr"]},"required":true}],"responses":{"200":{"description":"Resolution result (always inactive for an empty code)","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","const":"active"},"targetType":{"type":"string","const":"profile"},"slug":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"type":{"type":"string","enum":["professional","business"]}},"required":["status","targetType","slug","type"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","const":"active"},"targetType":{"type":"string","const":"external_url"},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["status","targetType","url"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","const":"inactive"}},"required":["status"],"additionalProperties":false}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/public/events/link-click":{"post":{"operationId":"recordLinkClickEvent","summary":"Record a link click from a published profile page (API-ANL-3)","tags":["analytics"],"security":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profileId":{"type":"string","minLength":1},"linkId":{"type":"string","minLength":1}},"required":["profileId","linkId"],"additionalProperties":false}}}},"responses":{"204":{"description":"Click recorded"},"400":{"description":"Validation error or cross-site request rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Link not found on an enabled, published profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/profiles/{id}/analytics":{"get":{"operationId":"getProfileAnalytics","summary":"Read link-click and entry rollups for a profile the caller owns (API-ANL-4)","tags":["analytics"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"days","schema":{"type":"number"},"required":true}],"responses":{"200":{"description":"Analytics for the requested window","content":{"application/json":{"schema":{"type":"object","properties":{"periodDays":{"anyOf":[{"type":"number","const":7},{"type":"number","const":30},{"type":"number","const":90}]},"linkClicks":{"type":"array","items":{"type":"object","properties":{"linkId":{"type":"string","minLength":1},"linkType":{"type":"string","enum":["website","instagram","facebook","tiktok","youtube","x","linkedin","whatsapp","phone","email","google_maps_review","other"]},"total":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["linkId","linkType","total"],"additionalProperties":false}},"entries":{"type":"object","properties":{"nfc":{"type":"integer","minimum":0,"maximum":9007199254740991},"qr":{"type":"integer","minimum":0,"maximum":9007199254740991},"direct":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["nfc","qr","direct"],"additionalProperties":false},"series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"clicks":{"type":"integer","minimum":0,"maximum":9007199254740991},"entries":{"type":"object","properties":{"nfc":{"type":"integer","minimum":0,"maximum":9007199254740991},"qr":{"type":"integer","minimum":0,"maximum":9007199254740991},"direct":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["nfc","qr","direct"],"additionalProperties":false}},"required":["date","clicks","entries"],"additionalProperties":false}}},"required":["periodDays","linkClicks","entries","series"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Profile not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/cards/{id}/analytics":{"get":{"operationId":"getCardAnalytics","summary":"Read entry rollups for a card the caller owns (TAP-163) -- totals + origin breakdown only, no per-link dimension (there is no page)","tags":["analytics"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"days","schema":{"type":"number"},"required":true}],"responses":{"200":{"description":"Analytics for the requested window","content":{"application/json":{"schema":{"type":"object","properties":{"periodDays":{"anyOf":[{"type":"number","const":7},{"type":"number","const":30},{"type":"number","const":90}]},"entries":{"type":"object","properties":{"nfc":{"type":"integer","minimum":0,"maximum":9007199254740991},"qr":{"type":"integer","minimum":0,"maximum":9007199254740991},"direct":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["nfc","qr","direct"],"additionalProperties":false},"series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"entries":{"type":"object","properties":{"nfc":{"type":"integer","minimum":0,"maximum":9007199254740991},"qr":{"type":"integer","minimum":0,"maximum":9007199254740991},"direct":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["nfc","qr","direct"],"additionalProperties":false}},"required":["date","entries"],"additionalProperties":false}}},"required":["periodDays","entries","series"],"additionalProperties":false}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Card not found (404-not-403, ADR-0004)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"The path exists but not under this method; see the `Allow` response header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limit exceeded (ADR-0011: best-effort throttle, never the security boundary)","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Unexpected internal error; `error.requestId` correlates with the server log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Authentication is not configured; the API fails closed rather than open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}},"components":{"schemas":{"EpochMs":{"type":"integer","minimum":0,"maximum":9007199254740991},"ErrorEnvelope":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string","minLength":1,"description":"Human-readable summary. Safe to surface; never contains internals or stack traces."},"requestId":{"type":"string","minLength":1,"description":"Correlation id, identical to the `X-Request-Id` response header and to the server log line."},"details":{"description":"Optional machine-readable context, e.g. `[{ field, message }]` for a validation error."}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"description":"Typed error model shared by every 4xx/5xx response."},"ErrorCode":{"type":"string","enum":["validation_error","not_found","method_not_allowed","conflict","authentication_required","auth_unconfigured","operator_auth_unconfigured","rate_limited","unsupported_media_type","slug_taken","media_quota_exceeded","request_hash_mismatch","internal_error"],"description":"Stable, machine-readable error identifier. Prefer this over the HTTP status or the message."},"Destination":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"},"kind":{"type":"string","const":"taply_page"},"profileId":{"type":"string","minLength":1},"url":{"type":"null"}},"required":["id","accountId","createdAt","updatedAt","kind","profileId","url"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"},"kind":{"type":"string","const":"custom_url"},"profileId":{"type":"null"},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["id","accountId","createdAt","updatedAt","kind","profileId","url"],"additionalProperties":false}],"type":"object"},"OnboardingSession":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"stepKey":{"type":"string","enum":["destination_kind","custom_url","taply_page_type","taply_page_identity","taply_page_professional","taply_page_business","taply_page_networks","taply_page_theme","complete"]},"kind":{"anyOf":[{"type":"string","enum":["taply_page","custom_url"]},{"type":"null"}]},"answers":{"type":"object","properties":{"schemaVersion":{"type":"number","const":1},"customUrl":{"type":"string"},"profileType":{"type":"string","enum":["professional","business"]},"photoMediaId":{"type":"string","minLength":1},"displayName":{"type":"string","maxLength":120},"headline":{"type":"string","maxLength":160},"slug":{"type":"string","maxLength":30},"slugEdited":{"type":"boolean"},"bio":{"type":"string","maxLength":2000},"belongsToBusinessName":{"type":"string","maxLength":120},"businessCategory":{"type":"string","maxLength":80},"businessDetails":{"type":"string","maxLength":4000},"networks":{"maxItems":32,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"url":{"type":"string","maxLength":2048}},"required":["productId","url"],"additionalProperties":false}},"themeId":{"type":"string","maxLength":64}},"required":["schemaVersion"],"additionalProperties":false},"profileId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"destinationId":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}]},"completedAt":{"anyOf":[{"$ref":"#/components/schemas/EpochMs"},{"type":"null"}]},"version":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"createdAt":{"$ref":"#/components/schemas/EpochMs"},"updatedAt":{"$ref":"#/components/schemas/EpochMs"}},"required":["id","accountId","stepKey","kind","answers","profileId","destinationId","completedAt","version","createdAt","updatedAt"],"additionalProperties":false},"Uuid":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"Cursor":{"type":"object","properties":{"after":{"type":"string","minLength":1},"limit":{"default":20,"type":"integer","minimum":1,"maximum":100}},"required":["limit"],"additionalProperties":false}},"headers":{"RateLimit":{"required":true,"description":"Remaining quota for the active policy. Emitted ONLY on 429, where `r=0` is proven; the Workers rate-limit binding exposes no remaining count on allowed requests, so none is claimed there. `t` is the full policy window, an upper bound on the reset.","schema":{"type":"string","description":"Remaining quota for the active policy. Emitted ONLY on 429, where `r=0` is proven; the Workers rate-limit binding exposes no remaining count on allowed requests, so none is claimed there. `t` is the full policy window, an upper bound on the reset.","example":"\"default\";r=0;t=60"}},"RateLimit-Policy":{"required":true,"description":"Quota policy in force, draft-ietf-httpapi-ratelimit-headers form. Present on every response from a throttled route.","schema":{"type":"string","description":"Quota policy in force, draft-ietf-httpapi-ratelimit-headers form. Present on every response from a throttled route.","example":"\"default\";q=1000;w=60"}},"Retry-After":{"required":true,"description":"Seconds to wait before retrying: the full policy window.","schema":{"type":"string","description":"Seconds to wait before retrying: the full policy window.","example":"60"}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Authenticated owner session (Stytch-issued JWT)."},"internalOperatorAuth":{"type":"apiKey","in":"header","name":"Cf-Access-Jwt-Assertion","description":"Internal operator principal (Cloudflare Access service token, ADR-0019) — distinct from bearerAuth, never the owner's Stytch session."},"mediaSourceTokenAuth":{"type":"apiKey","in":"query","name":"sig","description":"Short-lived HMAC capability for the media transform source route; valid only for the requested mediaId and the accompanying exp value."}}}}