{"openapi":"3.1.0","info":{"title":"ComplyZero people and consent API","version":"1.0.0","description":"Create and update the records your own system holds by your reference, link references explicitly, manage the contact details messages go to, record the consent decisions your app or staff collected with the verification you performed, and read current permissions and the purpose catalogue. Every write is idempotent with replay of the original result. A key is bound to one Organization and, optionally, to Websites: such a key names and reads organisation-wide purposes and its Websites' purposes only.\n\nEvery refusal is a problem document: `type` ends in the code (`https://complyzero.com/errors/<code>`), `detail` carries the code or the stated message, and `invalid_choices` names its purposes in `purposeIds`. Responses are never cached (`Cache-Control: private, no-store`)."},"servers":[{"url":"https://api.complyzero.com/api/v1/external/consent"}],"security":[{"bearerKey":[]},{"headerKey":[]}],"tags":[{"name":"People"},{"name":"Receipts"},{"name":"Permissions"},{"name":"Purposes"}],"paths":{"/people":{"post":{"tags":["People"],"operationId":"upsertPerson","summary":"Create or update a record by your reference","description":"Finds the record that holds your reference as linked, or creates your own record with it. A record that someone typed the same value into on a public form is never taken over: that claim is retired and the person keeps their own record. Contact details are added as message destinations, never as ways to sign in, and every one is answered with its id (`existing: true` when it was already on the record). An email address or phone number never finds or combines records. A key bound to Websites may create a record with its contact details and name; on a record that already exists it may not add a contact detail or change the name (`403 scope`).\n\nExample: a clinic creates Asha's record (patient 1001) and Vikram's (patient 1002) with the family's shared email address and phone number. They stay two records, neither signs in with those details, and each gets contact ids of its own. When someone stops messages at that phone number, the stop applies to both records; each person then turns messages back on for their own record only.\n\nRequires the `write:consent` scope.","x-complyzero-scope":"write:consent","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonUpsert"},"examples":{"asha":{"summary":"Asha, patient 1001, with the family email and phone","value":{"reference":{"kind":"patient_id","value":"1001"},"displayName":"Asha","destinations":[{"method":"email","value":"family@example.in"},{"method":"phone","value":"+919812345678"}]}},"vikram":{"summary":"Vikram, patient 1002, with the same email and phone","description":"A second record with the same two contact details. The two records are never merged: each person manages their own choices.","value":{"reference":{"kind":"patient_id","value":"1002"},"displayName":"Vikram","destinations":[{"method":"email","value":"family@example.in"},{"method":"phone","value":"+919812345678"}]}}}}}},"responses":{"200":{"description":"The record existed.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PersonResult"}},"required":["data"],"additionalProperties":false},"examples":{"asha":{"summary":"The same request again finds Asha's record","value":{"data":{"personId":"3f73d7a1-997b-4cc9-b7b8-535303724e1c","created":false,"contacts":[{"contactId":"737abc62-40c1-458f-a07c-a9d5f3447a2c","method":"email","existing":true},{"contactId":"9b1515fe-4cd4-4856-8db1-f823c3b6a4e7","method":"phone","existing":true}]}}}}}}},"201":{"description":"The record was created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PersonResult"}},"required":["data"],"additionalProperties":false},"examples":{"asha":{"summary":"Asha's record was created","value":{"data":{"personId":"3f73d7a1-997b-4cc9-b7b8-535303724e1c","created":true,"contacts":[{"contactId":"737abc62-40c1-458f-a07c-a9d5f3447a2c","method":"email","existing":false},{"contactId":"9b1515fe-4cd4-4856-8db1-f823c3b6a4e7","method":"phone","existing":false}]}}},"vikram":{"summary":"Vikram's record was created, with contact details of its own","value":{"data":{"personId":"6ff4172d-4be3-4325-9e1f-66a21182c075","created":true,"contacts":[{"contactId":"821f7156-c6d3-4067-b3b6-7edb9ea725ed","method":"email","existing":false},{"contactId":"66957ede-cf39-4dca-9c4e-be4a1f514346","method":"phone","existing":false}]}}}}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden` as for every operation, or `scope`: a key bound to Websites would add a contact detail to an existing record or change its name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"`validation`: the body is larger than this operation accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"`validation`: the body must be sent as `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"tags":["People"],"operationId":"findPeople","summary":"Find records by contact detail or by reference","description":"By contact detail (`method` and `value`): every record holding it, as a way to sign in (`login: true`) or as a contact detail, with identity facts only, so you choose the record explicitly. By reference (`referenceKind`, optional `namespace`, `value`): the one record holding it as linked, with its contact details. A lookup links nothing and creates nothing.\n\nExample: a gym looks Ravi up by email, sees that he signs in with that address (`login: true`), and links its member id to the record it chose with `POST /people/{personId}/references`. An email match never links a record by itself.\n\nRequires the `read:consent` scope.","x-complyzero-scope":"read:consent","parameters":[{"name":"method","in":"query","schema":{"type":"string","enum":["email","phone"]},"description":"With `value`: find by contact detail.","example":"email"},{"name":"referenceKind","in":"query","schema":{"type":"string","enum":["enrolment_id","student_id","patient_id","visitor_id","customer_file_number","customer_id","membership_id","application_reference","licence_number","paper_form_number","employee_id","guardian_reference","other"]},"description":"With `value`: find by reference."},{"name":"namespace","in":"query","schema":{"type":"string","maxLength":120},"description":"The system namespace of the reference; absent is the default namespace."},{"name":"value","in":"query","required":true,"schema":{"type":"string","maxLength":500},"example":"ravi@example.in","description":"The contact detail or reference. A phone number is E.164 with its leading `+` (pattern `^\\+[1-9][0-9]{7,14}$`). A `+`, in a phone number or an email address, may be sent as is or as `%2B`."}],"responses":{"200":{"description":"The records holding the contact detail, or the record holding the reference.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/ContactHolders"},{"$ref":"#/components/schemas/ReferenceHolder"}]}},"required":["data"],"additionalProperties":false},"examples":{"byEmail":{"summary":"method=email&value=ravi@example.in: every record holding the address","description":"Ravi signs in with this address (`login: true`), so the gym chooses his record and links its member id to it.","value":{"data":[{"personId":"26e30aa8-bc97-4355-9e56-f8a6e8d31b97","login":true,"displayName":"Ravi"}]}},"byReference":{"summary":"referenceKind=membership_id&value=M-1024: the record holding the member id","value":{"data":{"personId":"26e30aa8-bc97-4355-9e56-f8a6e8d31b97","contacts":[{"contactId":"2540666f-9608-46e0-be46-c6cdc24843fe","method":"email"}]}}}}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden`: the key lacks the scope this operation needs (the detail names it), or the key's address allowlist or its own per-minute request limit refuses the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`unknown_person`: no record holds the reference as linked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/people/{personId}/references":{"post":{"tags":["People"],"operationId":"linkReference","summary":"Link a reference to a record you chose","description":"The explicit link: the only way a record found by contact detail gains your reference. A value someone typed on a public form for this record is adopted; one typed for another record is retired. Linking grants nothing and creates no way to sign in. Your staff can link a reference the same way from the person's page in ComplyZero.\n\nRequires the `write:consent` scope.","x-complyzero-scope":"write:consent","parameters":[{"name":"personId","in":"path","required":true,"description":"The record.","schema":{"type":"string","format":"uuid"},"example":"26e30aa8-bc97-4355-9e56-f8a6e8d31b97"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reference"},"examples":{"memberId":{"summary":"Link member id M-1024 to Ravi's record","value":{"kind":"membership_id","value":"M-1024"}}}}}},"responses":{"201":{"description":"The reference is linked.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReferenceLinkResult"}},"required":["data"],"additionalProperties":false},"examples":{"memberId":{"summary":"The member id is linked","value":{"data":{"referenceId":"90d04bc8-40b0-495b-a230-e69f828f9a1c"}}}}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden`: the key lacks the scope this operation needs (the detail names it), or the key's address allowlist or its own per-minute request limit refuses the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`unknown_person`: no such record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"`identifier_in_use`: another record holds the value as linked; `already_on_profile`: this record already does.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"inUse":{"summary":"Another record already holds M-1024","value":{"type":"https://complyzero.com/errors/identifier_in_use","title":"Conflict","status":409,"detail":"identifier_in_use"}}}}}},"413":{"description":"`validation`: the body is larger than this operation accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"`validation`: the body must be sent as `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/people/{personId}/contacts":{"post":{"tags":["People"],"operationId":"addContact","summary":"Add a contact detail","description":"Adds a message destination with no code and no verification declaration needed. A value already on the record answers its id with `existing: true`.\n\nRequires the `write:consent` scope.","x-complyzero-scope":"write:consent","parameters":[{"name":"personId","in":"path","required":true,"description":"The record.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"responses":{"200":{"description":"The value was already on the record.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactResult"}},"required":["data"],"additionalProperties":false}}}},"201":{"description":"The contact detail was added.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactResult"}},"required":["data"],"additionalProperties":false}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden` as for every operation, or `scope`: a key bound to Websites may not change a record's contact details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`unknown_person`: no such record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"`validation`: the body is larger than this operation accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"`validation`: the body must be sent as `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/people/{personId}/contacts/{contactId}":{"delete":{"tags":["People"],"operationId":"removeContact","summary":"Remove a contact detail","description":"Retires a message destination; choices recorded at it stop applying. A way to sign in cannot be removed here.\n\nRequires the `write:consent` scope.","x-complyzero-scope":"write:consent","parameters":[{"name":"personId","in":"path","required":true,"description":"The record.","schema":{"type":"string","format":"uuid"}},{"name":"contactId","in":"path","required":true,"description":"The contact detail.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The contact detail is retired.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactRetired"}},"required":["data"],"additionalProperties":false}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden` as for every operation, or `scope`: a key bound to Websites may not change a record's contact details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`not_found`: the contact detail is not on this record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"`login_contact`: the address is used to sign in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/receipts":{"post":{"tags":["Receipts"],"operationId":"recordReceipt","summary":"Record consent decisions","description":"Records the decisions a person made in your app or with your staff, naming the record by id or by your linked reference, never by email or phone alone. `evidence.collectedAt` is when the person acted; the purpose versions published at that time are recorded with their validity, and a validity counts from it. When `collectedAt` precedes a purpose's first publication, send the `validUntil` the person was told, otherwise the grant is recorded as `history (terms_unavailable)`. `attestation` declares how you verified the person: restoring a choice the person stopped needs a method other than `none`, and at a stopped contact detail an attestation naming that contact. A decision older than the latest change to what it targets is recorded as `history` and changes nothing; at an equal time a withdrawal or decline wins. `basedOnSequence` (optional) is the `sequence` the permissions query returned: a grant or allow made on an older read answers `stale`; withdrawals and declines never do. The same `clientEventId` with the same body returns the original result with `duplicate: true` for as long as the receipt is kept; with another body it is refused. After the receipt's retention period the event is no longer known: `GET /receipts/{clientEventId}` answers `404 unknown_event` and the same request is recorded as a new write.\n\nExample: Asha stopped WhatsApp alerts at her number. In the clinic's app she turns them back on after a one-time code to that number. Because the attestation names the number, the WhatsApp option applies, and the receipt keeps the evidence you declared with the purpose version published at `collectedAt` and how you verified her. Without `attestation.contact` the same body answers `not_saved` (`attestation_required`) for the WhatsApp option and applies the rest.\n\nRequires the `write:consent` scope.","x-complyzero-scope":"write:consent","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Receipt"},"examples":{"restoreWithVerifiedPhone":{"summary":"Asha turns WhatsApp alerts back on, verified by a code to her number","description":"Asha had stopped WhatsApp alerts at her number. In the clinic's app she turns them back on after a one-time code to that number, so the attestation names the number. `basedOnSequence` is the `sequence` the permissions query returned when the app showed her the choices.","value":{"clientEventId":"fa53adf1-b222-4795-8c8b-9bc6771e4ba2","person":{"reference":{"kind":"patient_id","value":"1001"}},"basedOnSequence":8812,"evidence":{"collectedAt":"2026-11-03T09:12:00+05:30","customerNotice":{"reference":"app-privacy-v7"}},"attestation":{"method":"customer_phone_otp","at":"2026-11-03T09:11:40+05:30","reference":"otp-5f2a","contact":{"method":"phone","value":"+919812345678"}},"decisions":[{"purposeId":"5c7fddad-30d7-4192-8b3d-10402aab8e22","decision":"grant","options":[{"optionId":"acb4af16-7a1a-4d6d-99fa-afdd7a4b7951","contactId":"9b1515fe-4cd4-4856-8db1-f823c3b6a4e7","decision":"allow"}]}]}},"withoutNamingThePhone":{"summary":"The same change without naming the verified number","value":{"clientEventId":"f6f8d10f-ea29-4026-8ccd-d4fb56e26dbc","person":{"reference":{"kind":"patient_id","value":"1001"}},"basedOnSequence":8812,"evidence":{"collectedAt":"2026-11-03T09:12:00+05:30","customerNotice":{"reference":"app-privacy-v7"}},"attestation":{"method":"customer_phone_otp","at":"2026-11-03T09:11:40+05:30","reference":"otp-5f2a"},"decisions":[{"purposeId":"5c7fddad-30d7-4192-8b3d-10402aab8e22","decision":"grant","options":[{"optionId":"acb4af16-7a1a-4d6d-99fa-afdd7a4b7951","contactId":"9b1515fe-4cd4-4856-8db1-f823c3b6a4e7","decision":"allow"}]}]}}}}}},"responses":{"200":{"description":"A replay of the same request: the original result with `duplicate: true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Acknowledgement"}},"required":["data"],"additionalProperties":false}}}},"201":{"description":"The receipt was recorded. Each decision and option carries its outcome (`applied`, `unchanged`, `history`, `stale`, `not_saved`) and reason.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Acknowledgement"}},"required":["data"],"additionalProperties":false},"examples":{"restoreWithVerifiedPhone":{"summary":"WhatsApp alerts are on again at Asha's number","value":{"data":{"schemaVersion":3,"state":"accepted","receiptId":"89eb78bb-e198-4995-b335-9e19ade069cf","clientEventId":"fa53adf1-b222-4795-8c8b-9bc6771e4ba2","payloadDigest":"3720af24911e48f9e7750581a58f9d7c2a7b1598abc77c79c7b2c5bec08c1b02","acceptedAt":"2026-11-03T03:42:05.120Z","personId":"3f73d7a1-997b-4cc9-b7b8-535303724e1c","decisions":[{"purposeId":"5c7fddad-30d7-4192-8b3d-10402aab8e22","outcome":"applied","options":[{"optionId":"acb4af16-7a1a-4d6d-99fa-afdd7a4b7951","outcome":"applied"}]}],"current":[{"purposeId":"5c7fddad-30d7-4192-8b3d-10402aab8e22","state":"granted","validUntil":null,"entries":[{"optionId":"b76e637b-916f-4811-8793-abea17fa3fc3","contactId":"737abc62-40c1-458f-a07c-a9d5f3447a2c","type":"email","state":"allowed","validUntil":"2027-05-10T04:30:00.000Z"},{"optionId":"acb4af16-7a1a-4d6d-99fa-afdd7a4b7951","contactId":"9b1515fe-4cd4-4856-8db1-f823c3b6a4e7","type":"whatsapp","state":"allowed","validUntil":"2027-11-03T03:42:00.000Z"}]}],"duplicate":false,"receiptDigest":"df3c91da26b6b3e9e805d8c30cc934c79fb293a13c296ae1c6798574bf7cdcad","capture":null}}},"withoutNamingThePhone":{"summary":"The WhatsApp option is not saved (`attestation_required`); the number stays stopped","value":{"data":{"schemaVersion":3,"state":"accepted","receiptId":"14bca720-9e9f-4556-a3c9-e666cbd3c98f","clientEventId":"f6f8d10f-ea29-4026-8ccd-d4fb56e26dbc","payloadDigest":"04d02ddad19277a8c6c2e7844bd555b625060b4ad1918b431e550885f2cf0300","acceptedAt":"2026-11-03T03:42:05.120Z","personId":"3f73d7a1-997b-4cc9-b7b8-535303724e1c","decisions":[{"purposeId":"5c7fddad-30d7-4192-8b3d-10402aab8e22","outcome":"not_saved","reason":"attestation_required","options":[{"optionId":"acb4af16-7a1a-4d6d-99fa-afdd7a4b7951","outcome":"not_saved","reason":"attestation_required"}]}],"current":[{"purposeId":"5c7fddad-30d7-4192-8b3d-10402aab8e22","state":"granted","validUntil":null,"entries":[{"optionId":"b76e637b-916f-4811-8793-abea17fa3fc3","contactId":"737abc62-40c1-458f-a07c-a9d5f3447a2c","type":"email","state":"allowed","validUntil":"2027-05-10T04:30:00.000Z"},{"optionId":"acb4af16-7a1a-4d6d-99fa-afdd7a4b7951","contactId":"9b1515fe-4cd4-4856-8db1-f823c3b6a4e7","type":"whatsapp","state":"not_allowed","reason":"stopped_at_contact","validUntil":"2027-05-10T04:30:00.000Z"}]}],"duplicate":false,"receiptDigest":"5b325c6a72dc28d8811be924df1902cbc96bea13a8c7481ce460f4e0c558ceed","capture":null}}}}}}},"400":{"description":"`validation` (as above); `invalid_time`: `collectedAt` is later than now; `invalid_attestation`: the attested contact is not on the record; `invalid_choices`: a decision names a purpose or option that does not exist (see `purposeIds`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden` as for every operation, or `scope`: a decision names another Website's purpose.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`unknown_person`: no such record, or no record holds the reference as linked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"`idempotency_conflict`: the `clientEventId` was used with another body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"`validation`: the body is larger than this operation accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"`validation`: the body must be sent as `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/receipts/batch":{"post":{"tags":["Receipts"],"operationId":"recordReceipts","summary":"Record up to 100 receipts","description":"Each item is recorded on its own, in order, and answered exactly as a single request would be, with its status; one item's failure never blocks another. An item that failed unexpectedly answers status 500 with `internal`; send it again with the same `clientEventId`. A batch holds at most 100 items and counts as one request against the rate limits.\n\nRequires the `write:consent` scope.","x-complyzero-scope":"write:consent","requestBody":{"required":true,"description":"An array of 1 to 100 receipt bodies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceiptBatch"}}}},"responses":{"200":{"description":"One result per item, in request order.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BatchResult"}},"required":["data"],"additionalProperties":false}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden`: the key lacks the scope this operation needs (the detail names it), or the key's address allowlist or its own per-minute request limit refuses the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"`validation`: the body is larger than this operation accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"`validation`: the body must be sent as `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/receipts/{clientEventId}":{"get":{"tags":["Receipts"],"operationId":"readReceipt","summary":"Read the original result of a receipt","description":"The stored result with `duplicate: true`, at any age while the receipt is kept. A key bound to Websites reads it filtered to its scope. Before resending a request older than the receipt's retention period, read it here: `404 unknown_event` means the event is no longer known, and a resent request would be recorded as a new write.\n\nRequires the `read:consent` scope.","x-complyzero-scope":"read:consent","parameters":[{"name":"clientEventId","in":"path","required":true,"description":"The `clientEventId` of the receipt.","schema":{"type":"string","format":"uuid"},"example":"fa53adf1-b222-4795-8c8b-9bc6771e4ba2"}],"responses":{"200":{"description":"The stored result.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Acknowledgement"}},"required":["data"],"additionalProperties":false}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden`: the key lacks the scope this operation needs (the detail names it), or the key's address allowlist or its own per-minute request limit refuses the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`unknown_event`: no receipt holds the event (never recorded, deleted at the end of its retention, or outside the key's scope).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/permissions/query":{"post":{"tags":["Permissions"],"operationId":"queryPermissions","summary":"Read current permissions","description":"For up to 100 people, named by record id, contact detail or reference, the current permission of each record: per purpose its state, and per option and contact detail whether messages are allowed. A contact detail answers for every record holding it. Each record carries its `sequence`, the value to send as `basedOnSequence` on a write that follows this read. Without `purposes`, every purpose the record holds a choice for; with it, the named purposes (`unanswered` where the person has not chosen). Ids that are not person purposes this key can read are left out of the answer. A key bound to Websites reads its scope's purposes only.\n\nRequires the `read:consent` scope.","x-complyzero-scope":"read:consent","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionsQuery"},"examples":{"beforeTheChange":{"summary":"Asha's alerts, read before the app shows her the choices","value":{"people":[{"reference":{"kind":"patient_id","value":"1001"}}],"purposes":["5c7fddad-30d7-4192-8b3d-10402aab8e22"]}}}}}},"responses":{"200":{"description":"One result per requested person, in request order.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PermissionsResult"}},"required":["data"],"additionalProperties":false},"examples":{"beforeTheChange":{"summary":"WhatsApp is stopped at her number; send `sequence` as `basedOnSequence` with the change","value":{"data":{"results":[{"profiles":[{"personId":"3f73d7a1-997b-4cc9-b7b8-535303724e1c","sequence":8812,"purposes":[{"purposeId":"5c7fddad-30d7-4192-8b3d-10402aab8e22","state":"granted","validUntil":null,"entries":[{"optionId":"b76e637b-916f-4811-8793-abea17fa3fc3","contactId":"737abc62-40c1-458f-a07c-a9d5f3447a2c","type":"email","state":"allowed","validUntil":"2027-05-10T04:30:00.000Z"},{"optionId":"acb4af16-7a1a-4d6d-99fa-afdd7a4b7951","contactId":"9b1515fe-4cd4-4856-8db1-f823c3b6a4e7","type":"whatsapp","state":"not_allowed","reason":"stopped_at_contact","validUntil":"2027-05-10T04:30:00.000Z"}]}]}]}]}}}}}}},"400":{"description":"`validation`: the body, path or query does not fit; `errors` names each field by its full path (`destinations.1.value`), and a phone number without its leading `+` is `invalid_contact` at its field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden`: the key lacks the scope this operation needs (the detail names it), or the key's address allowlist or its own per-minute request limit refuses the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"`validation`: the body is larger than this operation accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"`validation`: the body must be sent as `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/purposes":{"get":{"tags":["Purposes"],"operationId":"listPurposes","summary":"Read the purpose catalogue","description":"The published purposes in the key's scope, each with its current version (the wording shown to people, in every checked language) and its options. A purpose due to retire shows `retiredAt`.\n\nRequires the `read:consent` scope.","x-complyzero-scope":"read:consent","responses":{"200":{"description":"The catalogue.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PurposesResult"}},"required":["data"],"additionalProperties":false}}}},"401":{"description":"`unauthorized`: no API key, or a key that is invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"`forbidden`: the key lacks the scope this operation needs (the detail names it), or the key's address allowlist or its own per-minute request limit refuses the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`too-many-requests`: too many requests arrived from your address in a short time. Wait the number of seconds in `Retry-After`, then send the request again with the same body.","headers":{"Retry-After":{"description":"The seconds to wait before sending the request again.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"securitySchemes":{"bearerKey":{"type":"http","scheme":"bearer","description":"The API key as `Authorization: Bearer <key>`."},"headerKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"The API key as `X-API-Key: <key>`."}},"schemas":{"Contact":{"oneOf":[{"type":"object","properties":{"method":{"const":"email"},"value":{"type":"string","maxLength":320,"format":"email"}},"required":["method","value"],"additionalProperties":false},{"type":"object","properties":{"method":{"const":"phone"},"value":{"type":"string","pattern":"^\\+[1-9][0-9]{7,14}$"}},"required":["method","value"],"additionalProperties":false}]},"Reference":{"type":"object","properties":{"kind":{"type":"string","enum":["enrolment_id","student_id","patient_id","visitor_id","customer_file_number","customer_id","membership_id","application_reference","licence_number","paper_form_number","employee_id","guardian_reference","other"]},"namespace":{"type":"string","maxLength":120},"value":{"type":"string","minLength":1,"maxLength":500}},"required":["kind","value"],"additionalProperties":false},"PersonUpsert":{"type":"object","properties":{"reference":{"$ref":"#/components/schemas/Reference"},"displayName":{"type":"string","minLength":1,"maxLength":500},"destinations":{"type":"array","items":{"$ref":"#/components/schemas/Contact"},"maxItems":20,"default":[]}},"required":["reference"],"additionalProperties":false},"PersonResult":{"type":"object","properties":{"personId":{"type":"string","format":"uuid"},"created":{"type":"boolean"},"contacts":{"type":"array","items":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"method":{"type":"string","enum":["email","phone"]},"existing":{"type":"boolean"}},"required":["contactId","method","existing"],"additionalProperties":false}}},"required":["personId","created","contacts"],"additionalProperties":false},"ContactHolders":{"type":"array","items":{"type":"object","properties":{"personId":{"type":"string","format":"uuid"},"login":{"type":"boolean"},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["personId","login","displayName"],"additionalProperties":false}},"ReferenceHolder":{"type":"object","properties":{"personId":{"type":"string","format":"uuid"},"contacts":{"type":"array","items":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"method":{"type":"string","enum":["email","phone"]}},"required":["contactId","method"],"additionalProperties":false}}},"required":["personId","contacts"],"additionalProperties":false},"ReferenceLinkResult":{"type":"object","properties":{"referenceId":{"type":"string","format":"uuid"}},"required":["referenceId"],"additionalProperties":false},"ContactResult":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"existing":{"type":"boolean"}},"required":["contactId","existing"],"additionalProperties":false},"ContactRetired":{"type":"object","properties":{"state":{"const":"retired"}},"required":["state"],"additionalProperties":false},"PersonSelector":{"anyOf":[{"type":"object","properties":{"personId":{"type":"string","format":"uuid"}},"required":["personId"],"additionalProperties":false},{"type":"object","properties":{"reference":{"$ref":"#/components/schemas/Reference"}},"required":["reference"],"additionalProperties":false}]},"OptionDecision":{"anyOf":[{"type":"object","properties":{"optionId":{"type":"string","format":"uuid"},"decision":{"type":"string","enum":["allow","decline","unchanged","unanswered"]},"contactId":{"type":"string","format":"uuid"}},"required":["optionId","decision","contactId"],"additionalProperties":false},{"type":"object","properties":{"optionId":{"type":"string","format":"uuid"},"decision":{"type":"string","enum":["allow","decline","unchanged","unanswered"]},"destination":{"$ref":"#/components/schemas/Contact"}},"required":["optionId","decision","destination"],"additionalProperties":false}]},"Decision":{"type":"object","properties":{"purposeId":{"type":"string","format":"uuid"},"decision":{"type":"string","enum":["grant","decline","withdraw","unchanged","unanswered"]},"options":{"type":"array","items":{"$ref":"#/components/schemas/OptionDecision"},"maxItems":20,"default":[]}},"required":["purposeId","decision"],"additionalProperties":false},"Evidence":{"type":"object","properties":{"collectedAt":{"type":"string","format":"date-time"},"validUntil":{"type":"string","format":"date-time"},"customerNotice":{"type":"object","properties":{"reference":{"type":"string","minLength":1,"maxLength":200},"version":{"type":"string","minLength":1,"maxLength":200}},"required":["reference"],"additionalProperties":false}},"required":["collectedAt"],"additionalProperties":false},"Attestation":{"type":"object","properties":{"method":{"type":"string","enum":["customer_account","customer_phone_otp","customer_email_otp","staff_in_person","none"]},"at":{"type":"string","format":"date-time"},"reference":{"type":"string","minLength":1,"maxLength":200},"contact":{"$ref":"#/components/schemas/Contact"}},"required":["method","at"],"additionalProperties":false},"Receipt":{"type":"object","properties":{"clientEventId":{"type":"string","format":"uuid"},"person":{"$ref":"#/components/schemas/PersonSelector"},"basedOnSequence":{"type":"integer","minimum":0,"maximum":9007199254740991},"evidence":{"$ref":"#/components/schemas/Evidence"},"attestation":{"$ref":"#/components/schemas/Attestation"},"decisions":{"type":"array","items":{"$ref":"#/components/schemas/Decision"},"minItems":1,"maxItems":100}},"required":["clientEventId","person","evidence","attestation","decisions"],"additionalProperties":false},"ReceiptBatch":{"type":"array","items":{"$ref":"#/components/schemas/Receipt"},"minItems":1,"maxItems":100},"EntryEvaluation":{"type":"object","properties":{"optionId":{"type":"string","format":"uuid"},"contactId":{"type":"string","format":"uuid"},"type":{"anyOf":[{"type":"string","enum":["email","sms","whatsapp"]},{"type":"null"}]},"state":{"type":"string","enum":["allowed","not_allowed"]},"reason":{"type":"string","enum":["purpose_not_granted","purpose_expired","option_declined","option_unanswered","option_expired","option_retired","contact_retired","stopped_at_contact","external_unsubscribe","bounced","restricted"]},"validUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["optionId","contactId","type","state","validUntil"],"additionalProperties":false},"PurposeEvaluation":{"type":"object","properties":{"purposeId":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["restricted","unanswered","retired","expired","fresh_consent_needed","stopped","granted","declined","withdrawn"]},"reason":{"type":"string","enum":["erasure","regulatory","protection","validity_elapsed","purpose_changed","stopped_by_person"]},"validUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"entries":{"type":"array","items":{"$ref":"#/components/schemas/EntryEvaluation"}}},"required":["purposeId","state","validUntil","entries"],"additionalProperties":false},"Acknowledgement":{"type":"object","properties":{"schemaVersion":{"const":3},"state":{"const":"accepted"},"receiptId":{"type":"string","format":"uuid"},"clientEventId":{"type":"string","format":"uuid"},"payloadDigest":{"type":"string","pattern":"^[a-f0-9]{64}$"},"acceptedAt":{"type":"string","format":"date-time"},"personId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"decisions":{"type":"array","items":{"type":"object","properties":{"purposeId":{"type":"string","format":"uuid"},"outcome":{"type":"string","enum":["applied","unchanged","pending","history","stale","not_saved"]},"reason":{"type":"string","enum":["verification_required","verification_unavailable","verification_consumed","changed_since_verification","assistance_required","restricted","purpose_retired","option_retired","stale_packet","idempotency_conflict","ambiguous_record","attestation_required","terms_unavailable","unknown_contact","blocked_by_restriction","confirmation_required"]},"options":{"type":"array","items":{"type":"object","properties":{"optionId":{"type":"string","format":"uuid"},"outcome":{"type":"string","enum":["applied","unchanged","pending","history","stale","not_saved"]},"reason":{"type":"string","enum":["verification_required","verification_unavailable","verification_consumed","changed_since_verification","assistance_required","restricted","purpose_retired","option_retired","stale_packet","idempotency_conflict","ambiguous_record","attestation_required","terms_unavailable","unknown_contact","blocked_by_restriction","confirmation_required"]}},"required":["optionId","outcome"],"additionalProperties":false}}},"required":["purposeId","outcome","options"],"additionalProperties":false}},"current":{"type":"array","items":{"$ref":"#/components/schemas/PurposeEvaluation"}},"duplicate":{"type":"boolean"},"receiptDigest":{"type":"string","pattern":"^[a-f0-9]{64}$"},"capture":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["form","centre","handoff"]},"id":{"type":"string","format":"uuid"},"versionId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"publicationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"generation":{"type":"integer","minimum":0},"journey":{"type":"string","enum":["adult_only","child_handling_required"]}},"required":["kind","id","versionId","publicationId","generation","journey"],"additionalProperties":false},{"type":"null"}]},"submissionGroupId":{"type":"string","format":"uuid"},"campaignId":{"type":"string","format":"uuid"}},"required":["schemaVersion","state","receiptId","clientEventId","payloadDigest","acceptedAt","personId","decisions","current","duplicate","receiptDigest","capture"],"additionalProperties":false},"BatchResult":{"type":"object","properties":{"results":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"status":{"type":"integer"},"data":{"$ref":"#/components/schemas/Acknowledgement"}},"required":["status","data"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"integer"},"error":{"$ref":"#/components/schemas/Problem"}},"required":["status","error"],"additionalProperties":false}]}}},"required":["results"],"additionalProperties":false},"PermissionsQuery":{"type":"object","properties":{"people":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"personId":{"type":"string","format":"uuid"}},"required":["personId"],"additionalProperties":false},{"$ref":"#/components/schemas/Contact"},{"type":"object","properties":{"reference":{"$ref":"#/components/schemas/Reference"}},"required":["reference"],"additionalProperties":false}]},"minItems":1,"maxItems":100},"purposes":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":200,"description":"The purposes to answer, each with its state (`unanswered` where the person has not chosen); without it, every purpose the record holds a choice for. Ids that are not person purposes this key can read (a cookie purpose, another Website's purpose, an id that does not exist) are left out of the answer."}},"required":["people"],"additionalProperties":false},"PermissionProfile":{"type":"object","properties":{"personId":{"type":"string","format":"uuid"},"sequence":{"type":"integer","minimum":0},"purposes":{"type":"array","items":{"$ref":"#/components/schemas/PurposeEvaluation"}}},"required":["personId","sequence","purposes"],"additionalProperties":false},"PermissionsResult":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"profiles":{"type":"array","items":{"$ref":"#/components/schemas/PermissionProfile"}}},"required":["profiles"],"additionalProperties":false}}},"required":["results"],"additionalProperties":false},"PurposeContent":{"type":"object","properties":{"sourceLanguage":{"type":"string","enum":["en","hi","bn","te","mr","ta","gu","kn","ml","pa","or","as","brx","ur","sa","ks","sd","ne","doi","mai","kok","sat","mni"]},"name":{"type":"string","maxLength":255},"description":{"type":"string","maxLength":4000},"dataItems":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":255},"category":{"type":"string","maxLength":255},"requiredForPurpose":{"type":"boolean"}},"required":["label","category","requiredForPurpose"],"additionalProperties":false},"maxItems":50},"people":{"type":"array","items":{"type":"string","maxLength":255},"maxItems":50},"peopleDescription":{"type":"string","maxLength":4000},"retention":{"type":"object","properties":{"statement":{"type":"string","maxLength":4000},"durationOrCondition":{"type":"string","maxLength":4000},"scope":{"type":"string","maxLength":4000}},"required":["statement","durationOrCondition","scope"],"additionalProperties":false},"recipients":{"type":"object","properties":{"applicability":{"type":"string","maxLength":255},"description":{"type":"string","maxLength":4000}},"required":["applicability","description"],"additionalProperties":false},"transfers":{"type":"object","properties":{"applicability":{"type":"string","maxLength":255},"description":{"type":"string","maxLength":4000}},"required":["applicability","description"],"additionalProperties":false},"withdrawalConsequences":{"type":"string","maxLength":4000},"legalGround":{"type":"object","properties":{"ground":{"type":"string","enum":["consent","voluntary_sharing","employment","government_disclosure","legal_order"]},"explanation":{"type":"string","maxLength":4000}},"required":["ground","explanation"],"additionalProperties":false},"options":{"type":"array","items":{"type":"object","properties":{"optionId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["channel"]},"type":{"type":"string","enum":["email","sms","whatsapp"]},"label":{"type":"string","maxLength":255},"help":{"type":"string","maxLength":2000}},"required":["optionId","kind","type","label","help"],"additionalProperties":false},"maxItems":20},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","enum":["en","hi","bn","te","mr","ta","gu","kn","ml","pa","or","as","brx","ur","sa","ks","sd","ne","doi","mai","kok","sat","mni"]},"wording":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"description":{"type":"string","maxLength":4000},"dataItems":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":255}},"required":["label"],"additionalProperties":false},"maxItems":50},"people":{"type":"array","items":{"type":"string","maxLength":255},"maxItems":50},"peopleDescription":{"type":"string","maxLength":4000},"retention":{"type":"object","properties":{"statement":{"type":"string","maxLength":4000},"durationOrCondition":{"type":"string","maxLength":4000},"scope":{"type":"string","maxLength":4000}},"required":["statement","durationOrCondition","scope"],"additionalProperties":false},"recipients":{"type":"object","properties":{"description":{"type":"string","maxLength":4000}},"required":["description"],"additionalProperties":false},"transfers":{"type":"object","properties":{"description":{"type":"string","maxLength":4000}},"required":["description"],"additionalProperties":false},"withdrawalConsequences":{"type":"string","maxLength":4000},"legalGround":{"type":"object","properties":{"explanation":{"type":"string","maxLength":4000}},"required":["explanation"],"additionalProperties":false},"options":{"type":"array","items":{"type":"object","properties":{"optionId":{"type":"string","format":"uuid"},"label":{"type":"string","maxLength":255},"help":{"type":"string","maxLength":2000}},"required":["optionId","label","help"],"additionalProperties":false},"maxItems":20}},"required":["name","description","dataItems","people","peopleDescription","retention","recipients","transfers","withdrawalConsequences","legalGround","options"],"additionalProperties":false}},"required":["language","wording"],"additionalProperties":false},"maxItems":22},"validityDays":{"anyOf":[{"type":"integer","minimum":1,"maximum":36500},{"type":"null"}]}},"required":["sourceLanguage","name","description","dataItems","people","peopleDescription","retention","recipients","transfers","withdrawalConsequences","legalGround","options","translations","validityDays"],"additionalProperties":false},"Purpose":{"type":"object","properties":{"purposeId":{"type":"string","format":"uuid"},"key":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9]+(?:[_-][a-z0-9]+)*$"},"scopeKind":{"type":"string","enum":["organization","property"]},"propertyId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"generation":{"type":"integer","minimum":1},"validityDays":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}]},"retiredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"currentVersion":{"type":"object","properties":{"versionId":{"type":"string","format":"uuid"},"version":{"type":"integer","minimum":1},"generation":{"type":"integer","minimum":1},"publishedAt":{"type":"string","format":"date-time"},"languages":{"type":"array","items":{"type":"string","enum":["en","hi","bn","te","mr","ta","gu","kn","ml","pa","or","as","brx","ur","sa","ks","sd","ne","doi","mai","kok","sat","mni"]}},"content":{"$ref":"#/components/schemas/PurposeContent"}},"required":["versionId","version","generation","publishedAt","languages","content"],"additionalProperties":false},"options":{"type":"array","items":{"type":"object","properties":{"optionId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["channel"]},"type":{"type":"string","enum":["email","sms","whatsapp"]},"retiredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["optionId","kind","type","retiredAt"],"additionalProperties":false}}},"required":["purposeId","key","scopeKind","propertyId","generation","validityDays","retiredAt","currentVersion","options"],"additionalProperties":false},"PurposesResult":{"type":"object","properties":{"purposes":{"type":"array","items":{"$ref":"#/components/schemas/Purpose"}}},"required":["purposes"],"additionalProperties":false},"Problem":{"type":"object","properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"correlationId":{"type":"string"},"purposeIds":{"type":"array","items":{"type":"string","format":"uuid"}},"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},"formErrors":{"type":"array","items":{"type":"string"}}},"required":["type","title","status","detail"],"additionalProperties":false},"ErrorCodes":{"type":"string","enum":["validation","unauthorized","forbidden","scope","not_found","unknown_person","unknown_event","invalid_time","invalid_attestation","invalid_choices","invalid_contact","idempotency_conflict","identifier_in_use","already_on_profile","login_contact","too-many-requests","internal"],"description":"The codes a problem's `type` ends in."}}}}