{"openapi":"3.1.0","info":{"title":"4D OS Partner API","version":"0.1.0","description":"REST API for 4D OS partners. Authenticate with your organization API key: `Authorization: Bearer <key>`.\n\nRequests and responses are JSON with `snake_case` field names. Errors share one envelope: `{ \"error\": { \"code\", \"status\", \"message\", \"details\"? } }`.\n\nMutating endpoints that declare it accept an `Idempotency-Key` header so retries are safe.\n\nBulk-migrating members? See the [Migrating to 4D guide](https://docs.fourdos.dev/walkthroughs/migrate-existing-members) for the canonical import schema, a worked example, and the `/v1/imports` sequence."},"tags":[{"name":"Users","description":"Create, read, and manage users and their org membership"},{"name":"Imports","description":"Bulk member import jobs (staging → validate → commit)"},{"name":"Engagement","description":"Browser event tracking (publishable keys) and tracking-key management"}],"security":[{"partnerApiKey":[]}],"paths":{"/v1/users":{"post":{"operationId":"createOrAttachUser","tags":["Users"],"summary":"Create or attach a user (idempotent via Idempotency-Key)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserBody"}}}},"responses":{"200":{"description":"Existing user/member returned unchanged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"201":{"description":"User and/or membership created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"409":{"description":"Idempotency or external_id conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/users/{userId}":{"get":{"operationId":"getUser","tags":["Users"],"summary":"Fetch a user within the caller's organization","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User not found in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateUser","tags":["Users"],"summary":"Update a user's profile fields","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserBody"}}}},"responses":{"200":{"description":"User updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User not found in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/users/{userId}/lock":{"post":{"operationId":"lockMember","tags":["Users"],"summary":"Lock the caller-org membership for a user","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LockMemberBody"}}}},"responses":{"200":{"description":"Membership locked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User not found in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/users/{userId}/unlock":{"post":{"operationId":"unlockMember","tags":["Users"],"summary":"Unlock the caller-org membership for a user","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Membership unlocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User not found in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/users/{userId}/membership":{"delete":{"operationId":"removeMember","tags":["Users"],"summary":"Remove (soft-delete) the caller-org membership for a user","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Membership removed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"404":{"description":"User not found in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports":{"post":{"operationId":"createImportJob","tags":["Imports"],"summary":"Create a bulk import job (starts in `staging`)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateImportJobBody"}}}},"responses":{"201":{"description":"Import job created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"404":{"description":"Caller may not manage imports for this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The organization already has an active import job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}/rows":{"post":{"operationId":"appendImportRows","tags":["Imports"],"summary":"Stage a chunk of rows onto a job (≤5k rows/request, job must be `staging`)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppendImportRowsBody"}}}},"responses":{"200":{"description":"Rows staged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppendImportRowsResponse"}}}},"404":{"description":"Import job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The job is not in `staging`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error, or the row/chunk cap was exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listImportRows","tags":["Imports"],"summary":"Page a job's per-row outcomes, optionally filtered by state","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","enum":["staged","valid","invalid","created","attached","failed"]}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Rows page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportRowPageResponse"}}}},"404":{"description":"Caller may not manage imports for this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid `state` filter, `cursor`, or `limit`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}/validate":{"post":{"operationId":"validateImportJob","tags":["Imports"],"summary":"Seal staging and start async dry-run validation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Job sealed; now `validating`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"404":{"description":"Import job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The job is not in `staging`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}/commit":{"post":{"operationId":"commitImportJob","tags":["Imports"],"summary":"Commit a validated job, or start validation with `dry_run: false` on a `staging` job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitImportJobBody"}}}},"responses":{"202":{"description":"Commit started, or validation started (`dry_run: false` convenience)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"404":{"description":"Import job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The job is not `validated` (and no `dry_run: false` convenience applied)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}":{"get":{"operationId":"getImportJob","tags":["Imports"],"summary":"Fetch an import job's status and counts","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import job found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"404":{"description":"Import job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}/error-report":{"get":{"operationId":"getImportErrorReport","tags":["Imports"],"summary":"Download the invalid+failed rows as CSV (also the console's download URL, cookie auth)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"RFC-4180 CSV: original payload columns + row_number, error_code, error_message","content":{"text/csv":{"schema":{"type":"string"}}}},"404":{"description":"Caller may not manage imports for this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/track":{"post":{"operationId":"trackEngagementEvents","tags":["Engagement"],"summary":"Track engagement events (public, publishable tracking key)","description":"Public CORS-enabled receptor for browser engagement events. Authenticates with a publishable `ek_live_…` tracking key sent as `?key=` or the body `key` field - partner bearer keys are not accepted here. Accepts a batch (`events: [...]`, max 20) or a single event spread at the top level. Events are accepted per-item: the 202 envelope reports `accepted`/`duplicate`/`rejected` per event.","security":[{"trackingKey":[]}],"parameters":[{"name":"key","in":"query","required":false,"description":"Publishable tracking key (alternative to the body `key` field)","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackBody"}}}},"responses":{"202":{"description":"Per-event outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackResponse"}}}},"401":{"description":"Missing, unknown, or revoked tracking key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The request Origin is not on the key's allowlist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Track rate limit exceeded for this key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/engagement/keys":{"post":{"operationId":"createTrackingKey","tags":["Engagement"],"summary":"Issue a publishable tracking key","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTrackingKeyBody"}}}},"responses":{"201":{"description":"Tracking key created (token included)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingKeyResponse"}}}},"401":{"description":"Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listTrackingKeys","tags":["Engagement"],"summary":"List the organization's tracking keys","responses":{"200":{"description":"Tracking keys","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/TrackingKeyResponse"}}},"required":["keys"]}}}},"401":{"description":"Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/engagement/keys/{id}":{"delete":{"operationId":"revokeTrackingKey","tags":["Engagement"],"summary":"Revoke a tracking key (idempotent)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking key revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingKeyResponse"}}}},"401":{"description":"Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tracking key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"CreateUserBody":{"type":"object","properties":{"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"external_id":{"type":"string"},"display_name":{"type":"string"},"locale":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"country":{"type":"string","pattern":"^[A-Za-z]{2}$"},"dob":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["email"]},"UpdateUserBody":{"type":"object","properties":{"display_name":{"type":"string"},"locale":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"country":{"type":"string","pattern":"^[A-Za-z]{2}$"},"dob":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}},"LockMemberBody":{"type":"object","properties":{"reason":{"type":"string","minLength":1}},"required":["reason"]},"UserResponse":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"age_band":{"type":"string","enum":["under_13","13_15","16_17","adult","unknown"]},"dob_verification_status":{"type":"string","enum":["unverified","self_declared","verified"]},"last_active_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","locked","deleted"]},"wallet":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["provisioning","active","failed","destroyed"]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["status","address"]},{"type":"null"}]},"membership":{"type":"object","properties":{"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["member","partner_admin"]},"status":{"type":"string","enum":["active","locked","removed"]},"joined_at":{"type":"string"},"locked_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"locked_reason":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","external_id","role","status","joined_at","locked_at","locked_reason"]}},"required":["id","email","display_name","first_name","last_name","country","age_band","dob_verification_status","last_active_at","status","wallet","membership"]},"AdminUserResponse":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"age_band":{"type":"string","enum":["under_13","13_15","16_17","adult","unknown"]},"dob_verification_status":{"type":"string","enum":["unverified","self_declared","verified"]},"last_active_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","locked","deleted"]},"wallet":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["provisioning","active","failed","destroyed"]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["status","address"]},{"type":"null"}]},"membership":{"type":"object","properties":{"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["member","partner_admin"]},"status":{"type":"string","enum":["active","locked","removed"]},"joined_at":{"type":"string"},"locked_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"locked_reason":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","external_id","role","status","joined_at","locked_at","locked_reason"]},"dob":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","email","display_name","first_name","last_name","country","age_band","dob_verification_status","last_active_at","status","wallet","membership","dob"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"status":{"type":"integer"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}},"required":["code","status","message"]}},"required":["error"]},"CreateImportJobBody":{"type":"object","properties":{"mapping":{"type":"object","properties":{"columns":{"minItems":1,"type":"array","items":{"oneOf":[{"type":"object","properties":{"sourceColumn":{"type":"string","minLength":1},"target":{"type":"string","const":"core_field"},"fieldKey":{"type":"string","enum":["email","external_id","first_name","last_name","display_name","locale","country","dob"]}},"required":["sourceColumn","target","fieldKey"]},{"type":"object","properties":{"sourceColumn":{"type":"string","minLength":1},"target":{"type":"string","const":"attribute"},"attributeKey":{"type":"string","minLength":1}},"required":["sourceColumn","target","attributeKey"]},{"type":"object","properties":{"sourceColumn":{"type":"string","minLength":1},"target":{"type":"string","const":"labels"}},"required":["sourceColumn","target"]},{"type":"object","properties":{"sourceColumn":{"type":"string","minLength":1},"target":{"type":"string","const":"ignored"}},"required":["sourceColumn","target"]}]}}},"required":["columns"]},"file_name":{"type":"string","minLength":1},"declared_total":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["declared_total"]},"AppendImportRowsBody":{"type":"object","properties":{"rows":{"minItems":1,"type":"array","items":{"type":"object","properties":{"rowNumber":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"payload":{"type":"object","properties":{"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"external_id":{"type":"string"},"display_name":{"type":"string"},"locale":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"country":{"type":"string","pattern":"^[A-Za-z]{2}$"},"dob":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"attributes":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"labels":{"maxItems":20,"type":"array","items":{"type":"string"}}},"required":["email"],"additionalProperties":false}},"required":["rowNumber","payload"]}}},"required":["rows"]},"AppendImportRowsResponse":{"type":"object","properties":{"staged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["staged"]},"CommitImportJobBody":{"type":"object","properties":{"dry_run":{"type":"boolean"}}},"ImportJobResponse":{"type":"object","properties":{"id":{"type":"string"},"organization_id":{"type":"string"},"created_by_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"string","enum":["console","api"]},"state":{"type":"string","enum":["staging","validating","validated","committing","completed","failed"]},"mapping":{},"file_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"declared_total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"staged_rows":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"processed_rows":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"valid_rows":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"invalid_rows":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"attached_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expires_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","organization_id","created_by_id","source","state","mapping","file_name","declared_total","staged_rows","processed_rows","valid_rows","invalid_rows","created_count","attached_count","failed_count","expires_at","created_at","updated_at"]},"ImportRowResponse":{"type":"object","properties":{"id":{"type":"string"},"job_id":{"type":"string"},"organization_id":{"type":"string"},"row_number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"payload":{},"state":{"type":"string","enum":["staged","valid","invalid","created","attached","failed"]},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}]},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","job_id","organization_id","row_number","payload","state","error_code","error_message","user_id"]},"ImportRowPageResponse":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"job_id":{"type":"string"},"organization_id":{"type":"string"},"row_number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"payload":{},"state":{"type":"string","enum":["staged","valid","invalid","created","attached","failed"]},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}]},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","job_id","organization_id","row_number","payload","state","error_code","error_message","user_id"]}},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["rows","next_cursor"]},"TrackBody":{"anyOf":[{"type":"object","properties":{"key":{"type":"string"},"events":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"member_external_id":{"type":"string","minLength":1},"user_id":{"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)$"},"action":{"type":"string","minLength":1,"maxLength":64},"tags":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"string"}},"event_id":{"type":"string","minLength":1,"maxLength":128},"occurred_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tags"]}}},"required":["events"]},{"type":"object","properties":{"member_external_id":{"type":"string","minLength":1},"user_id":{"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)$"},"action":{"type":"string","minLength":1,"maxLength":64},"tags":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"string"}},"event_id":{"type":"string","minLength":1,"maxLength":128},"occurred_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"key":{"type":"string"}},"required":["tags"]}]},"CreateTrackingKeyBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":128},"allowed_origins":{"default":[],"maxItems":20,"type":"array","items":{"type":"string","minLength":1}}},"required":["name"]},"TrackResponse":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string","enum":["accepted","duplicate","rejected"]},"id":{"type":"string","description":"Stored engagement event id (status `accepted`)"},"event_id":{"type":"string","description":"Client-supplied dedupe id, echoed back"},"reason":{"type":"string","description":"Why the event was rejected (status `rejected`)"}},"required":["status"]}}},"required":["results"]},"TrackingKeyResponse":{"type":"object","properties":{"id":{"type":"string"},"organization_id":{"type":"string"},"name":{"type":"string"},"key":{"type":"string","description":"The publishable `ek_live_…` token"},"allowed_origins":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["active","revoked"]},"last_used_at":{"type":["string","null"],"format":"date-time"},"revoked_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","organization_id","name","key","allowed_origins","status","last_used_at","revoked_at","created_at","updated_at"]}},"securitySchemes":{"partnerApiKey":{"type":"http","scheme":"bearer","description":"Organization API key (`org_…`), sent as `Authorization: Bearer <key>`. Keys are scoped to one organization; every request operates within that tenant."},"trackingKey":{"type":"apiKey","in":"query","name":"key","description":"Publishable engagement tracking key (`ek_live_…`), sent as `?key=` or the body `key` field. Safe to embed in client code - abuse is bounded by the per-key origin allowlist and rate limit."}}}}