{"openapi":"3.1.0","info":{"title":"Giftafari API","version":"1.0.0","description":"The base URL https://api.giftafari.com/v1 is also the OAuth resource: GET it without a token for the WWW-Authenticate challenge. Every response uses the envelope { data, error, meta }. Sensitive operations take two calls: POST /approvals with the exact arguments (validated there, so a bad id fails before any token is issued), then the operation with the same arguments and approvalToken. Every request body and query is validated against the schemas below: a malformed id answers 400 INVALID_ID and a field that breaks its schema answers 400 INVALID_INPUT naming the field. Unknown body fields are ignored. Every 4xx and 5xx response from https://api.giftafari.com/v1 carries the ErrorEnvelope: a machine-readable error.code and a human-readable error.message. The OAuth endpoints answer errors in the RFC 6749 shape instead. Each operation allows 120 requests per 60 seconds per client IP address (POST /approvals allows 30), counted per server instance. Every response under https://api.giftafari.com/v1 except this document and an OPTIONS preflight reports the window in RateLimit and RateLimit-Policy headers, whose policy name is usually the operationId; a 429 adds Retry-After. The retired /api/v1 prefix answers 410 API_MOVED with the new address in movedTo."},"servers":[{"url":"https://api.giftafari.com/v1"}],"paths":{"/profile":{"get":{"operationId":"profile.get","summary":"Get profile","description":"Read your own Giftafari profile: name, display name, and photo. Read it before PATCH /profile, which replaces every field.","security":[{"oauth2":["account:read"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Profile"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"patch":{"operationId":"profile.update","summary":"Update profile","description":"Change your first name, last name, and photo. Send every field you want to keep: an omitted avatarUrl clears the photo. Returns the updated profile.","security":[{"oauth2":["account:write"]}],"x-confirmation":"none","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":80,"description":"First name, 1 to 80 characters."},"lastName":{"description":"Last name, up to 79 characters. Omit for none.","type":"string","maxLength":79},"avatarUrl":{"description":"Photo URL. Omit or send null to remove the photo.","type":["string","null"]}},"required":["firstName"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Profile"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/groups":{"get":{"operationId":"groups.list","summary":"List my groups","description":"List every gift group your account belongs to, with your role in each. This connection acts on one of them; the others need their own connection.","security":[{"oauth2":["account:memberships"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GroupsListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/groups/{groupId}":{"get":{"operationId":"groups.get","summary":"Get group","description":"Read the connected group's name and version. Use the version with PATCH /groups/{groupId}.","security":[{"oauth2":["group:read"]}],"x-confirmation":"none","parameters":[{"name":"groupId","in":"path","required":true,"description":"The connected group's id. It must match the group the token was granted for.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Group"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"patch":{"operationId":"groups.update","summary":"Rename group","description":"Rename the connected group. Owner only. Pass the version from GET /groups/{groupId}. Returns the renamed group.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"none","parameters":[{"name":"groupId","in":"path","required":true,"description":"The connected group's id. It must match the group the token was granted for.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"New group name, 1 to 80 characters."},"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The version from your last read. A stale version returns VERSION_CONFLICT."}},"required":["name","version"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Group"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include VERSION_CONFLICT, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/groups/{groupId}/transfer":{"post":{"operationId":"groups.transfer","summary":"Transfer group ownership","description":"Make another member the owner of the connected group. Owner only. Get their user id from GET /groups/{groupId}/memberships. Set leave to also leave the group.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"groupId","in":"path","required":true,"description":"The connected group's id. It must match the group the token was granted for.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"newOwnerUserId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The new owner's user id, from GET /groups/{groupId}/memberships."},"leave":{"description":"Also leave the group after the transfer.","type":"boolean"},"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["newOwnerUserId","approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TransferResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/groups/{groupId}/leave":{"delete":{"operationId":"groups.leave","summary":"Leave group","description":"Leave the connected group. An owner must transfer ownership first. This connection stops working afterwards.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"groupId","in":"path","required":true,"description":"The connected group's id. It must match the group the token was granted for.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LeaveResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/groups/{groupId}/memberships":{"get":{"operationId":"memberships.list","summary":"List group members","description":"List the members of the connected group with their roles. Use a membership id with DELETE /groups/{groupId}/memberships/{membershipId}, or a user id with POST /groups/{groupId}/transfer.","security":[{"oauth2":["group:read"]}],"x-confirmation":"none","parameters":[{"name":"groupId","in":"path","required":true,"description":"The connected group's id. It must match the group the token was granted for.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipsListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/groups/{groupId}/memberships/{membershipId}":{"delete":{"operationId":"memberships.remove","summary":"Remove collaborator","description":"Remove a collaborator from the connected group. Owner only; the owner cannot be removed. Their connected apps for this group are signed out.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"groupId","in":"path","required":true,"description":"The connected group's id. It must match the group the token was granted for.","schema":{"type":"string","format":"uuid"}},{"name":"membershipId","in":"path","required":true,"description":"The membership to remove, from GET /groups/{groupId}/memberships.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RemovedMembership"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/people":{"get":{"operationId":"people.list","summary":"List people","description":"List the people this group gives gifts to, oldest first. Active people by default; pass state ARCHIVED for archived ones. Use a person id as a list's recipient.","security":[{"oauth2":["people:read"]}],"x-confirmation":"none","parameters":[{"name":"state","in":"query","required":false,"description":"Which people to list. Omit for ACTIVE.","schema":{"type":"string","enum":["ACTIVE","ARCHIVED"]}}],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PeopleListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"post":{"operationId":"people.create","summary":"Add person","description":"Add someone the group gives gifts to. Only a name is required; notes are a good place for sizes and likes. Returns the new person.","security":[{"oauth2":["people:write"]}],"x-confirmation":"none","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160,"description":"Their name, 1 to 160 characters."},"relationship":{"description":"How they relate to the group, such as sister or neighbor.","anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"birthDate":{"description":"Birthday as YYYY-MM-DD. Null or an empty string clears it.","anyOf":[{"type":"string","pattern":"^(\\d{4}-\\d{2}-\\d{2})?$"},{"type":"null"}]},"gender":{"description":"female or male. Null or an empty string clears it.","anyOf":[{"anyOf":[{"type":"string","enum":["female","male"]},{"type":"string","const":""}]},{"type":"null"}]},"notes":{"description":"Gift notes: sizes, likes, dislikes. Up to 2000 characters.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"required":["name"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), IDEMPOTENCY_KEY_REQUIRED, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/people/{personId}":{"patch":{"operationId":"people.update","summary":"Update person","description":"Change a person's details. Send only the fields to change; null or an empty string clears an optional field. Pass the version from GET /people.","security":[{"oauth2":["people:write"]}],"x-confirmation":"none","parameters":[{"name":"personId","in":"path","required":true,"description":"The person to change, from GET /people.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The version from your last read. A stale version returns VERSION_CONFLICT."},"name":{"description":"New name, 1 to 160 characters.","type":"string","minLength":1,"maxLength":160},"relationship":{"description":"How they relate to the group. Null clears it.","anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"birthDate":{"description":"Birthday as YYYY-MM-DD. Null or an empty string clears it.","anyOf":[{"type":"string","pattern":"^(\\d{4}-\\d{2}-\\d{2})?$"},{"type":"null"}]},"gender":{"description":"female or male. Null or an empty string clears it.","anyOf":[{"anyOf":[{"type":"string","enum":["female","male"]},{"type":"string","const":""}]},{"type":"null"}]},"notes":{"description":"Gift notes, up to 2000 characters. Null clears them.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"required":["version"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include VERSION_CONFLICT, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"post":{"operationId":"people.lifecycle","summary":"Archive, restore, or delete a person","description":"ARCHIVE hides a person from the active list, RESTORE brings them back, DELETE removes them for good (only when no list uses them). Returns the person in the new state.","security":[{"oauth2":["people:write"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"personId","in":"path","required":true,"description":"The person to change, from GET /people.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","enum":["ARCHIVE","RESTORE","DELETE"],"description":"ARCHIVE, RESTORE, or DELETE."},"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["event","approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/people/{personId}/link":{"post":{"operationId":"people.link","summary":"Link a person to their account","description":"Create a one-time link that connects a person to their own Giftafari account, so they see their lists as the recipient. Owner only. Nothing is emailed: share the returned token with that person yourself. Expires in 48 hours.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"none","parameters":[{"name":"personId","in":"path","required":true,"description":"The person to link, from GET /people.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","minLength":3,"maxLength":320,"description":"The email of their Giftafari account."}},"required":["email"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PersonLink"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/lists":{"get":{"operationId":"lists.list","summary":"Show lists","description":"List the group's active gift lists, most recently active first, with each list's recipient and version. Start here, then call GET /lists/{listId}/gifts for one list.","security":[{"oauth2":["lists:read"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListsListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"post":{"operationId":"lists.create","summary":"Create gift list","description":"Create and publish a gift list. Name the recipient with recipientPersonId (from GET /people) or add a new person with newPersonName, not both; omit both for a list with no recipient. Returns the active list.","security":[{"oauth2":["lists:write"]}],"x-confirmation":"none","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"List name, 1 to 120 characters."},"recipientPersonId":{"description":"An existing active person the list is for, from GET /people.","anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"newPersonName":{"description":"Add a new person with this name as the recipient.","anyOf":[{"type":"string","maxLength":160},{"type":"null"}]},"timezone":{"description":"IANA timezone such as America/Chicago. Omit for UTC.","type":"string","minLength":1}},"required":["name"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/List"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), IDEMPOTENCY_KEY_REQUIRED, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/lists/trash":{"get":{"operationId":"lists.trash","summary":"Show lists in trash","description":"List the group's lists in trash from the last 30 days, newest first. Restore one with POST /lists/{listId} event RESTORE.","security":[{"oauth2":["lists:read"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListsTrashResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/lists/{listId}":{"patch":{"operationId":"lists.update","summary":"Update gift list","description":"Rename a list, change its recipient, or change its timezone. Send only the fields to change; null recipientPersonId removes the recipient. A recipient cannot change while someone holds a claim on the list. Pass the version from GET /lists.","security":[{"oauth2":["lists:write"]}],"x-confirmation":"none","parameters":[{"name":"listId","in":"path","required":true,"description":"The list to change, from GET /lists.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The version from your last read. A stale version returns VERSION_CONFLICT."},"name":{"description":"New name, 1 to 120 characters.","type":"string","minLength":1,"maxLength":120},"recipientPersonId":{"description":"The new recipient from GET /people, or null for none.","anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"timezone":{"description":"IANA timezone such as Europe/London.","type":"string","minLength":1}},"required":["version"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/List"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include VERSION_CONFLICT, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"post":{"operationId":"lists.lifecycle","summary":"Publish, move to trash, or restore a list","description":"TRASH moves a list and its gifts to trash for 30 days and turns off its share links; RESTORE brings it back; PUBLISH publishes a draft. A list with claimed gifts cannot be trashed. Returns the list in its new state.","security":[{"oauth2":["lists:write"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"listId","in":"path","required":true,"description":"The list to change, from GET /lists or GET /lists/trash.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","enum":["PUBLISH","TRASH","RESTORE"],"description":"PUBLISH, TRASH, or RESTORE."},"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["event","approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/List"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/lists/{listId}/gifts":{"get":{"operationId":"gifts.list","summary":"List gifts on a list","description":"List the active gifts on one list, newest first, with each gift's price, state, and version. Results never say whether a gift is claimed, so they are safe to show a recipient.","security":[{"oauth2":["gifts:read"]}],"x-confirmation":"none","parameters":[{"name":"listId","in":"path","required":true,"description":"The list to read, from GET /lists.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GiftsListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"post":{"operationId":"gifts.create","summary":"Save a gift idea","description":"Save a gift idea to a list and publish it. When the user pastes a product link, call POST /gifts/preview first and pass its title, price, and URLs here. If the same product link is in trash, that gift is restored instead of copied. Returns the active gift.","security":[{"oauth2":["gifts:write"]}],"x-confirmation":"none","parameters":[{"name":"listId","in":"path","required":true,"description":"The list to add the gift to, from GET /lists.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":240,"description":"What the gift is, as the giver would say it."},"priceMinor":{"type":"integer","minimum":0,"maximum":2147483647,"description":"Price in minor units: 8500 means 85.00."},"currency":{"type":"string","pattern":"^[A-Za-z]{3}$","description":"ISO 4217 currency code such as USD."},"description":{"description":"Details, up to 5000 characters.","type":"string","maxLength":5000},"productUrl":{"description":"Where to buy it.","type":["string","null"]},"canonicalUrl":{"description":"The product page's canonical URL, from POST /gifts/preview.","type":["string","null"]},"retailer":{"description":"Store name.","anyOf":[{"type":"string","maxLength":160},{"type":"null"}]},"quantity":{"description":"How many, 1 to 99. Omit for 1.","type":"integer","minimum":1,"maximum":99}},"required":["title","priceMinor","currency"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Gift"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, IDEMPOTENCY_KEY_REQUIRED, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/gifts/trash":{"get":{"operationId":"gifts.trash","summary":"List gifts in trash","description":"List the group's gifts in trash from the last 30 days, newest first. Restore one with POST /gifts/{giftId} event RESTORE.","security":[{"oauth2":["gifts:read"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GiftsTrashResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/gifts/{giftId}":{"patch":{"operationId":"gifts.update","summary":"Update gift","description":"Change a gift's details. title is always required; send the other fields only to change them. Pass the version from GET /lists/{listId}/gifts. Returns the updated gift.","security":[{"oauth2":["gifts:write"]}],"x-confirmation":"none","parameters":[{"name":"giftId","in":"path","required":true,"description":"The gift to change, from GET /lists/{listId}/gifts.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The version from your last read. A stale version returns VERSION_CONFLICT."},"title":{"type":"string","minLength":1,"maxLength":240,"description":"The gift's title, changed or not."},"description":{"description":"Details. Null clears them.","anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"productUrl":{"description":"Where to buy it. Null clears it.","type":["string","null"]},"retailer":{"description":"Store name. Null clears it.","anyOf":[{"type":"string","maxLength":160},{"type":"null"}]},"priceMinor":{"description":"Price in minor units. A gift always keeps a price.","type":"integer","minimum":0,"maximum":2147483647},"currency":{"description":"ISO 4217 currency code.","type":"string","pattern":"^[A-Za-z]{3}$"},"quantity":{"description":"How many, 1 to 99.","type":"integer","minimum":1,"maximum":99}},"required":["version","title"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Gift"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include VERSION_CONFLICT, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"post":{"operationId":"gifts.lifecycle","summary":"Publish, move to trash, or restore a gift","description":"TRASH moves a gift to trash for 30 days, RESTORE brings it back, PUBLISH publishes a draft. A gift someone has claimed cannot be trashed, and a gift on a list in trash cannot be restored until its list is. Returns the gift in its new state.","security":[{"oauth2":["gifts:write"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"giftId","in":"path","required":true,"description":"The gift to change, from GET /lists/{listId}/gifts or GET /gifts/trash.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","enum":["PUBLISH","TRASH","RESTORE"],"description":"PUBLISH, TRASH, or RESTORE."},"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["event","approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Gift"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/gifts/{giftId}/move":{"post":{"operationId":"gifts.move","summary":"Move gift to another list","description":"Move a gift to another active list in the group. A claimed gift cannot move. Returns the gift with its new list_id.","security":[{"oauth2":["gifts:write"]}],"x-confirmation":"none","parameters":[{"name":"giftId","in":"path","required":true,"description":"The gift to move, from GET /lists/{listId}/gifts.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetListId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The list to move it to, from GET /lists."}},"required":["targetListId"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Gift"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/gifts/{giftId}/manual-claim":{"post":{"operationId":"gifts.manualClaim","summary":"Mark a gift as claimed outside Giftafari","description":"Mark a gift as claimed when someone bought it outside Giftafari, or clear that mark, so nobody else buys it. To claim a gift for yourself in Giftafari, use POST /claims. Not for the list's recipient. Pass the version from GET /lists/{listId}/gifts. Returns the gift and its claimed state.","security":[{"oauth2":["gifts:write"]}],"x-confirmation":"none","parameters":[{"name":"giftId","in":"path","required":true,"description":"The gift to mark, from GET /lists/{listId}/gifts.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The version from your last read. A stale version returns VERSION_CONFLICT."},"claimed":{"type":"boolean","description":"true to mark it claimed, false to clear the mark."}},"required":["version","claimed"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GiftWithClaim"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include VERSION_CONFLICT, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/gifts/{giftId}/duplicate":{"post":{"operationId":"gifts.duplicate","summary":"Copy gift to a list","description":"Copy a gift onto another list (or the same one) and publish the copy. Returns the new gift; duplicated_from_gift_id points at the original.","security":[{"oauth2":["gifts:write"]}],"x-confirmation":"none","parameters":[{"name":"giftId","in":"path","required":true,"description":"The gift to copy, from GET /lists/{listId}/gifts.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetListId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The list to put the copy on, from GET /lists."}},"required":["targetListId"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Gift"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, IDEMPOTENCY_KEY_REQUIRED, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/gifts/preview":{"post":{"operationId":"gifts.preview","summary":"Read a product link","description":"Read a product page and return a gift draft: title, price, store, and images. Saves nothing; pass the draft to POST /lists/{listId}/gifts. When the page cannot be read, the draft comes back mostly empty with a warning. Limited to 60 previews an hour.","security":[{"oauth2":["gifts:write"]}],"x-confirmation":"none","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2048,"description":"The product page URL, https only."}},"required":["url"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GiftDraft"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/claims":{"post":{"operationId":"claims.create","summary":"Claim a gift","description":"Claim a gift for yourself so nobody else in the group buys it. The list's recipient never sees the claim and cannot claim their own gifts. If someone bought it outside Giftafari, use POST /gifts/{giftId}/manual-claim instead. Returns the claim id.","security":[{"oauth2":["claims:write"]}],"x-confirmation":"none","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"giftId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The gift to claim, from GET /lists/{listId}/gifts."}},"required":["giftId"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimCreated"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), IDEMPOTENCY_KEY_REQUIRED, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"get":{"operationId":"claims.list","summary":"List my claims","description":"List the gifts you have claimed in this group that are still reserved, bought, or given, newest first. Use GET /claims/{claimId}/gift for a claim's gift details.","security":[{"oauth2":["claims:read"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimsListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/claims/{claimId}/gift":{"get":{"operationId":"claims.gift","summary":"View a gift I claimed","description":"Read the gift behind one of your claims, with its list and a short-lived image URL.","security":[{"oauth2":["claims:read"]}],"x-confirmation":"none","parameters":[{"name":"claimId","in":"path","required":true,"description":"Your claim, from GET /claims.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimedGift"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/claims/{claimId}":{"post":{"operationId":"claims.lifecycle","summary":"Mark a claim bought, given, released, or returned","description":"Move one of your claims along: PURCHASE when bought, GIVE when given, RELEASE to give up a reserved claim, RETURN when a bought or given gift came back. Pass the version from GET /claims. Returns the claim.","security":[{"oauth2":["claims:write"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"claimId","in":"path","required":true,"description":"Your claim, from GET /claims.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","enum":["PURCHASE","GIVE","RELEASE","RETURN"],"description":"PURCHASE, GIVE, RELEASE, or RETURN."},"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The version from your last read. A stale version returns VERSION_CONFLICT."},"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["event","version","approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Claim"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include VERSION_CONFLICT, APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/invitations":{"get":{"operationId":"invitations.list","summary":"List invitations","description":"List the connected group's invitations with their state and email delivery status. Owner only.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InvitationsListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"post":{"operationId":"invitations.create","summary":"Invite a collaborator","description":"Invite someone by email to help plan gifts in the connected group. Owner only. Giftafari emails them the link right away; the result also carries the link to share another way. When the email fails, emailError says why and invitation.delivery_state is FAILED; use RESEND to try again. Expires in 7 days.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"none","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","minLength":3,"maxLength":320,"description":"The email address to invite."}},"required":["email"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InvitationResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), IDEMPOTENCY_KEY_REQUIRED, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/invitations/{invitationId}":{"post":{"operationId":"invitations.lifecycle","summary":"Resend or cancel an invitation","description":"RESEND emails a pending invitation again with one more link and moves its expiry 7 days out (once a minute at most). Links sent earlier keep working. REVOKE cancels it and every link; EXPIRE closes one past its expiry. Owner only. RESEND returns the new link; REVOKE and EXPIRE return null for token and inviteUrl.","security":[{"oauth2":["group:admin"]}],"x-confirmation":"none","parameters":[{"name":"invitationId","in":"path","required":true,"description":"The invitation, from GET /invitations.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","enum":["RESEND","REVOKE","EXPIRE"],"description":"RESEND, REVOKE, or EXPIRE."}},"required":["event"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InvitationResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/lists/{listId}/share":{"post":{"operationId":"shares.manage","summary":"Share a list by link","description":"Manage a list's public link. ENSURE returns the current link for an audience or makes one; ROTATE replaces it so the old link stops working; REVOKE (with shareId) turns it off. BUYER links let people claim gifts; RECIPIENT links never show claims.","security":[{"oauth2":["shares:write"]}],"x-confirmation":"none","parameters":[{"name":"listId","in":"path","required":true,"description":"The list to share, from GET /lists.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","enum":["ENSURE","ROTATE","REVOKE"],"description":"ENSURE, ROTATE, or REVOKE."},"audience":{"description":"Who the link is for. Required for ENSURE and ROTATE.","type":"string","enum":["BUYER","RECIPIENT"]},"shareId":{"description":"The share to turn off. Required for REVOKE.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"required":["event"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ShareResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_PATH_PARAMETER, INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/approvals":{"post":{"operationId":"approvals.prepare","summary":"Prepare a sensitive change","description":"Step one of every sensitive change. Pass the operation id and the exact arguments you will send; you get an approvalToken and a consequences sentence. Show the user the consequences, get a clear yes, then call the operation with the same arguments and approvalToken within five minutes.","security":[{"oauth2":["group:read"]}],"x-confirmation":"none","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operationId":{"type":"string","enum":["groups.transfer","groups.leave","memberships.remove","people.lifecycle","lists.lifecycle","gifts.lifecycle","claims.lifecycle","connections.revoke","account.revokeCredentials","account.delete"],"description":"The sensitive operation to approve, such as gifts.lifecycle."},"arguments":{"description":"Exactly the arguments you will send to that operation, without approvalToken. Omit for operations that take none.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["operationId"]}}}},"responses":{"201":{"description":"Approval prepared","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Approval"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/connections":{"get":{"operationId":"connections.list","summary":"List AI connections","description":"List the AI apps and CLIs you connected to this group, newest first, with their permissions and whether they are connected, pending, or revoked.","security":[{"oauth2":["connections:read"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConnectionsListResult"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"delete":{"operationId":"connections.revoke","summary":"Revoke an AI connection","description":"Sign one connected app out of this group right away. Revoking this connection's own id ends this session.","security":[{"oauth2":["connections:write"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The connection to revoke, from GET /connections."},"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["connectionId","approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RevokedConnection"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/account/notifications":{"get":{"operationId":"notifications.get","summary":"Get email preferences","description":"Read which Giftafari emails you get: collaboration, claim reminders, product news.","security":[{"oauth2":["notifications:read"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NotificationPreferences"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}},"patch":{"operationId":"notifications.update","summary":"Update email preferences","description":"Turn Giftafari emails on or off. Send at least one preference; the others stay as they are. Returns all three.","security":[{"oauth2":["notifications:write"]}],"x-confirmation":"none","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"collaborationEmail":{"description":"Emails about invitations and group changes.","type":"boolean"},"claimReminderEmail":{"description":"Reminders about gifts you claimed.","type":"boolean"},"productUpdateEmail":{"description":"Occasional Giftafari product news.","type":"boolean"}}}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NotificationPreferences"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/account/export":{"get":{"operationId":"account.export","summary":"Export my data","description":"Build a full export of your account: profile, preferences, every group's people, lists, and gifts, and your own claims. Each call records a new export.","security":[{"oauth2":["account:export"]}],"x-confirmation":"none","parameters":[],"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccountExport"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/account/connections":{"delete":{"operationId":"account.revokeCredentials","summary":"Revoke every AI connection","description":"Revoke every AI app and CLI connected to your account, in every group, including this connection.","security":[{"oauth2":["account:write"]}],"x-confirmation":"prepare-commit","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique per new request. Reuse it only to retry the same request. A retry with the same key returns the first result.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\x21-\\x7e]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CredentialsRevoked"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH, IDEMPOTENCY_CONFLICT, IDEMPOTENCY_IN_PROGRESS, IDEMPOTENCY_OUTCOME_UNKNOWN. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}},"/account":{"delete":{"operationId":"account.delete","summary":"Close my account","description":"Close your Giftafari account for good. Transfer ownership of your groups first, sign in again within the last 15 minutes, and send confirmation exactly as DELETE MY ACCOUNT.","security":[{"oauth2":["account:delete"]}],"x-confirmation":"prepare-commit","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"type":"string","const":"DELETE MY ACCOUNT","description":"Type DELETE MY ACCOUNT exactly."},"approvalToken":{"type":"string","minLength":20,"description":"The approvalToken from POST /approvals for exactly these arguments. Works once."}},"required":["confirmation","approvalToken"]}}}},"responses":{"200":{"description":"The operation result, in the data envelope","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccountDeletion"},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}}}},"400":{"description":"Invalid request. Error codes include INVALID_ID (a malformed id), INVALID_INPUT (a field that breaks the schema, named in the message), INVALID_JSON.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict. Error codes include APPROVAL_REQUIRED, APPROVAL_EXPIRED, APPROVAL_REPLAYED, APPROVAL_MISMATCH. A record in the wrong state also answers 409 with its own code, such as LIST_NOT_ACTIVE, GIFT_UNAVAILABLE, ALREADY_LINKED, or INVALID_TRANSITION.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"default":{"$ref":"#/components/responses/OtherError"}}}}},"components":{"responses":{"Unauthorized":{"description":"Bearer token missing, invalid, or revoked (BEARER_REQUIRED, INVALID_TOKEN, GRANT_REVOKED, RESOURCE_MISMATCH). WWW-Authenticate points to the protected-resource metadata.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Forbidden":{"description":"The token lacks the scope or the group (INSUFFICIENT_SCOPE, GROUP_FORBIDDEN).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"NotFound":{"description":"Not found (NOT_FOUND): the record does not exist or belongs to another group. An unknown path or method answers OPERATION_NOT_FOUND, and /approvals answers it for an operation that needs no approval.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"PayloadTooLarge":{"description":"Request body is larger than 64 KB (PAYLOAD_TOO_LARGE).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"TooManyRequests":{"description":"Too many requests. Wait the Retry-After seconds, then retry. RATE_LIMITED (past 120 calls a minute) and PREVIEW_LIMIT (past 60 product previews in a clock hour) report the spent window in RateLimit; PREVIEW_BUSY means previews are busy for a few seconds.","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"}}}},"InternalError":{"description":"The server failed: INTERNAL_ERROR, DATABASE_ERROR, or another stable UPPER_SNAKE code, with a generic message that never quotes the database. Quote meta.requestId when you report it.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"OtherError":{"description":"Any other failure, in the same envelope: for example 410 TRASH_EXPIRED or SHARE_REVOKED, 415 and 422 for a product link or image Giftafari cannot read, and 502, 503, or 504 when a retailer or a dependency fails.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"schemas":{"Profile":{"type":"object","properties":{"user_id":{"type":"string","description":"Your account id."},"first_name":{"type":"string","description":"First name."},"last_name":{"type":"string","description":"Last name, or an empty string."},"display_name":{"type":"string","description":"The name other members see."},"avatar_url":{"description":"Profile picture URL, or null.","type":["string","null"]},"active_group_id":{"description":"The group the app opens to, or null.","type":["string","null"]},"created_at":{"type":"string","description":"When the profile was created (ISO 8601)."},"updated_at":{"type":"string","description":"When the profile last changed (ISO 8601)."}},"required":["user_id","first_name","last_name","display_name","avatar_url","active_group_id","created_at","updated_at"],"additionalProperties":{},"description":"Your Giftafari profile."},"GroupSummary":{"type":"object","properties":{"id":{"type":"string","description":"Group id."},"name":{"type":"string","description":"Group name."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"role":{"type":"string","enum":["OWNER","COLLABORATOR"],"description":"OWNER manages the group; COLLABORATOR helps plan."}},"required":["id","name","version","role"],"additionalProperties":{},"description":"A group you belong to, with your role in it."},"Group":{"type":"object","properties":{"id":{"type":"string","description":"Group id."},"name":{"type":"string","description":"Group name, 1 to 80 characters."},"created_by_user_id":{"description":"Who created the group, or null.","type":["string","null"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"created_at":{"type":"string","description":"When the group was created (ISO 8601)."},"updated_at":{"type":"string","description":"When the group last changed (ISO 8601)."}},"required":["id","name","created_by_user_id","version","created_at","updated_at"],"additionalProperties":{},"description":"A gift group: the people, lists, and gifts one family or circle shares."},"Membership":{"type":"object","properties":{"id":{"type":"string","description":"Membership id. Pass it to memberships_remove."},"group_id":{"type":"string","description":"Group id."},"user_id":{"type":"string","description":"The member's account id."},"role":{"type":"string","enum":["OWNER","COLLABORATOR"],"description":"OWNER manages the group; COLLABORATOR helps plan."},"created_at":{"type":"string","description":"When they joined (ISO 8601)."}},"required":["id","group_id","user_id","role","created_at"],"additionalProperties":{},"description":"One member of the group."},"Person":{"type":"object","properties":{"id":{"type":"string","description":"Person id."},"group_id":{"type":"string","description":"Group id."},"name":{"type":"string","description":"Name, 1 to 160 characters."},"birth_date":{"description":"Birthday as YYYY-MM-DD, or null.","type":["string","null"]},"relationship":{"description":"How they relate to you, or null.","type":["string","null"]},"notes":{"description":"Gift notes: sizes, likes, dislikes. Null if empty.","type":["string","null"]},"gender":{"anyOf":[{"type":"string","enum":["female","male"]},{"type":"null"}],"description":"female, male, or null when not set."},"avatar_media_id":{"description":"Photo media id, or null.","type":["string","null"]},"account_user_id":{"description":"The Giftafari account linked to this person, or null.","type":["string","null"]},"state":{"type":"string","enum":["ACTIVE","ARCHIVED","DELETED"],"description":"ACTIVE, ARCHIVED, or DELETED."},"created_by_user_id":{"description":"Who added them, or null.","type":["string","null"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"created_at":{"type":"string","description":"When they were added (ISO 8601)."},"updated_at":{"type":"string","description":"When their details last changed (ISO 8601)."}},"required":["id","group_id","name","birth_date","relationship","notes","gender","avatar_media_id","account_user_id","state","created_by_user_id","version","created_at","updated_at"],"additionalProperties":{},"description":"Someone the group gives gifts to."},"List":{"type":"object","properties":{"id":{"type":"string","description":"List id."},"group_id":{"type":"string","description":"Group id."},"recipient_person_id":{"description":"The person the list is for, or null for a list with no recipient.","type":["string","null"]},"name":{"type":"string","description":"List name, 1 to 120 characters."},"timezone":{"type":"string","description":"IANA timezone the list's dates use, such as America/Chicago."},"state":{"type":"string","enum":["DRAFT","ACTIVE","ARCHIVED","TRASHED","DELETED"],"description":"DRAFT, ACTIVE, TRASHED, ARCHIVED, or DELETED."},"created_by_user_id":{"description":"Who created the list, or null.","type":["string","null"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"created_at":{"type":"string","description":"When the list was created (ISO 8601)."},"updated_at":{"type":"string","description":"When the list last changed (ISO 8601)."},"trashed_at":{"description":"When the list moved to trash (ISO 8601), or null.","type":["string","null"]}},"required":["id","group_id","recipient_person_id","name","timezone","state","created_by_user_id","version","created_at","updated_at","trashed_at"],"additionalProperties":{},"description":"A gift list, usually for one recipient."},"Gift":{"type":"object","properties":{"id":{"type":"string","description":"Gift id."},"group_id":{"type":"string","description":"Group id."},"list_id":{"type":"string","description":"The list the gift is on."},"title":{"type":"string","description":"What the gift is, 1 to 240 characters."},"description":{"type":"string","description":"Details, up to 5000 characters. Empty when not set."},"product_url":{"description":"Where to buy it, or null.","type":["string","null"]},"canonical_url":{"description":"The product page's canonical URL, or null.","type":["string","null"]},"retailer":{"description":"Store name, or null.","type":["string","null"]},"price_minor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Price in minor units (8500 means 85.00), or null."},"currency":{"description":"ISO 4217 currency code such as USD, or null.","type":["string","null"]},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many to give, 1 to 99."},"primary_media_id":{"description":"Main image media id, or null.","type":["string","null"]},"state":{"type":"string","enum":["DRAFT","ACTIVE","ARCHIVED","TRASHED","DELETED"],"description":"DRAFT, ACTIVE, TRASHED, ARCHIVED, or DELETED."},"duplicated_from_gift_id":{"description":"The gift this one was copied from, or null.","type":["string","null"]},"created_by_user_id":{"description":"Who added the gift, or null.","type":["string","null"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"created_at":{"type":"string","description":"When the gift was added (ISO 8601)."},"updated_at":{"type":"string","description":"When the gift last changed (ISO 8601)."},"trashed_at":{"description":"When the gift moved to trash (ISO 8601), or null.","type":["string","null"]}},"required":["id","group_id","list_id","title","description","product_url","canonical_url","retailer","price_minor","currency","quantity","primary_media_id","state","duplicated_from_gift_id","created_by_user_id","version","created_at","updated_at","trashed_at"],"additionalProperties":{},"description":"A gift idea on a list. Carries no claim information, so it is safe for recipients."},"GiftWithClaim":{"type":"object","properties":{"id":{"type":"string","description":"Gift id."},"group_id":{"type":"string","description":"Group id."},"list_id":{"type":"string","description":"The list the gift is on."},"title":{"type":"string","description":"What the gift is, 1 to 240 characters."},"description":{"type":"string","description":"Details, up to 5000 characters. Empty when not set."},"product_url":{"description":"Where to buy it, or null.","type":["string","null"]},"canonical_url":{"description":"The product page's canonical URL, or null.","type":["string","null"]},"retailer":{"description":"Store name, or null.","type":["string","null"]},"price_minor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Price in minor units (8500 means 85.00), or null."},"currency":{"description":"ISO 4217 currency code such as USD, or null.","type":["string","null"]},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many to give, 1 to 99."},"primary_media_id":{"description":"Main image media id, or null.","type":["string","null"]},"state":{"type":"string","enum":["DRAFT","ACTIVE","ARCHIVED","TRASHED","DELETED"],"description":"DRAFT, ACTIVE, TRASHED, ARCHIVED, or DELETED."},"duplicated_from_gift_id":{"description":"The gift this one was copied from, or null.","type":["string","null"]},"created_by_user_id":{"description":"Who added the gift, or null.","type":["string","null"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"created_at":{"type":"string","description":"When the gift was added (ISO 8601)."},"updated_at":{"type":"string","description":"When the gift last changed (ISO 8601)."},"trashed_at":{"description":"When the gift moved to trash (ISO 8601), or null.","type":["string","null"]},"claimed":{"type":"boolean","description":"true when the gift is marked claimed outside Giftafari after this call."}},"required":["id","group_id","list_id","title","description","product_url","canonical_url","retailer","price_minor","currency","quantity","primary_media_id","state","duplicated_from_gift_id","created_by_user_id","version","created_at","updated_at","trashed_at","claimed"],"additionalProperties":{},"description":"The gift, plus its manual claim state after the change."},"GiftDraft":{"type":"object","properties":{"title":{"type":"string","description":"Product title read from the page. Empty when none was found."},"description":{"type":"string","description":"Product description. Empty when none was found."},"priceMinor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Price in minor units, or null."},"currency":{"description":"ISO 4217 currency code, or null.","type":["string","null"]},"retailer":{"description":"Store name, or null.","type":["string","null"]},"canonicalUrl":{"type":"string","description":"The page's canonical URL. Pass it to gifts_create."},"imageCandidates":{"type":"array","items":{"type":"string"},"description":"Image URLs found on the page."},"sourceUrl":{"type":"string","description":"The URL you asked to preview."},"warning":{"description":"Why the page could not be read. Present only when the preview fell back.","type":"string"}},"required":["title","description","priceMinor","currency","retailer","canonicalUrl","imageCandidates","sourceUrl"],"additionalProperties":{},"description":"A gift draft read from a product page. Nothing is saved."},"Claim":{"type":"object","properties":{"id":{"type":"string","description":"Claim id."},"group_id":{"type":"string","description":"Group id."},"gift_id":{"type":"string","description":"The claimed gift."},"claimant_user_id":{"description":"The account that claimed it, or null.","type":["string","null"]},"claim_intent_id":{"description":"Id of the request that created the claim, or null.","type":["string","null"]},"state":{"type":"string","enum":["RESERVED","PURCHASED","GIVEN","RELEASED","RETURNED","EXPIRED"],"description":"RESERVED, PURCHASED, GIVEN, RELEASED, RETURNED, or EXPIRED."},"purchased_at":{"description":"When it was bought (ISO 8601), or null.","type":["string","null"]},"given_at":{"description":"When it was given (ISO 8601), or null.","type":["string","null"]},"released_at":{"description":"When the claim was released (ISO 8601), or null.","type":["string","null"]},"returned_at":{"description":"When it was returned (ISO 8601), or null.","type":["string","null"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"created_at":{"type":"string","description":"When you claimed it (ISO 8601)."},"updated_at":{"type":"string","description":"When the claim last changed (ISO 8601)."}},"required":["id","group_id","gift_id","claimant_user_id","claim_intent_id","state","purchased_at","given_at","released_at","returned_at","version","created_at","updated_at"],"additionalProperties":{},"description":"A gift you claimed. Never visible to the gift's recipient."},"ClaimedGift":{"type":"object","properties":{"claimId":{"type":"string","description":"Claim id."},"gift":{"type":"object","properties":{"id":{"type":"string","description":"Gift id."},"group_id":{"type":"string","description":"Group id."},"list_id":{"type":"string","description":"List id."},"title":{"type":"string","description":"What the gift is."},"description":{"type":"string","description":"Details. Empty when not set."},"product_url":{"description":"Where to buy it, or null.","type":["string","null"]},"retailer":{"description":"Store name, or null.","type":["string","null"]},"price_minor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Price in minor units (8500 means 85.00), or null."},"currency":{"description":"ISO 4217 currency code such as USD, or null.","type":["string","null"]},"primary_media_id":{"description":"Main image media id, or null.","type":["string","null"]}},"required":["id","group_id","list_id","title","description","product_url","retailer","price_minor","currency","primary_media_id"],"additionalProperties":{},"description":"The claimed gift."},"list":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"List id."},"name":{"type":"string","description":"List name."}},"required":["id","name"],"additionalProperties":{}},{"type":"null"}],"description":"The list it is on, or null."},"imageUrl":{"description":"A signed image URL valid for 5 minutes, or null.","type":["string","null"]}},"required":["claimId","gift","list","imageUrl"],"additionalProperties":{},"description":"A gift you claimed, with its list and image."},"Invitation":{"type":"object","properties":{"id":{"type":"string","description":"Invitation id."},"group_id":{"type":"string","description":"Group id."},"email_normalized":{"type":"string","description":"Invited email address, lowercased."},"role":{"type":"string","const":"COLLABORATOR","description":"Invitations always grant COLLABORATOR."},"state":{"type":"string","enum":["PENDING","ACCEPTED","DECLINED","EXPIRED","REVOKED"],"description":"PENDING until accepted, declined, expired, or revoked."},"expires_at":{"type":"string","description":"When the invitation stops working (ISO 8601)."},"accepted_by_user_id":{"description":"Who accepted it, or null.","type":["string","null"]},"created_by_user_id":{"description":"Who sent it, or null.","type":["string","null"]},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version number. Send it back unchanged with your next update; a stale number returns VERSION_CONFLICT."},"delivery_state":{"type":"string","enum":["QUEUED","SENT","FAILED"],"description":"Email delivery state."},"sent_at":{"description":"When the email was sent (ISO 8601), or null.","type":["string","null"]},"send_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many times the email was sent."},"last_delivery_error":{"description":"The last delivery failure, or null.","type":["string","null"]},"opened_at":{"description":"When the invitee first opened the invitation link (ISO 8601), or null.","type":["string","null"]},"status":{"type":"string","enum":["NOT_SENT","SENT","EMAIL_FAILED","OPENED","JOINED","EXPIRED","DECLINED","CANCELED"],"description":"Where the invitation stands for the owner: NOT_SENT, SENT, EMAIL_FAILED or OPENED while pending; JOINED, EXPIRED, DECLINED or CANCELED once closed. EXPIRED also covers a pending invitation past expires_at."},"updated_at":{"type":"string","description":"When the invitation last changed (ISO 8601)."}},"required":["id","group_id","email_normalized","role","state","expires_at","accepted_by_user_id","created_by_user_id","version","delivery_state","sent_at","send_count","last_delivery_error","opened_at","status","updated_at"],"additionalProperties":{},"description":"An invitation for someone to join the group as a collaborator."},"InvitationResult":{"type":"object","properties":{"invitation":{"$ref":"#/components/schemas/Invitation"},"token":{"description":"The invitation secret, or null when no new invitation was sent.","type":["string","null"]},"inviteUrl":{"description":"The link to share with the invitee, or null when no new invitation was sent.","type":["string","null"]},"emailError":{"description":"Why the invitation email could not be sent, or null when it was sent or not tried.","type":["string","null"]}},"required":["invitation","token","inviteUrl","emailError"],"additionalProperties":{},"description":"The invitation, plus its link when a new one was sent."},"Share":{"type":"object","properties":{"id":{"type":"string","description":"Share id. Pass it to shares_manage to revoke."},"group_id":{"type":"string","description":"Group id."},"list_id":{"type":"string","description":"The shared list."},"audience":{"type":"string","enum":["BUYER","RECIPIENT"],"description":"BUYER links let people claim gifts; RECIPIENT links show the list without claims."},"link_code":{"type":"string","description":"Stable part of the link."},"link_slug":{"type":"string","description":"Readable part of the link, from the list name."},"revoked_at":{"description":"When the link was turned off (ISO 8601), or null.","type":["string","null"]},"expires_at":{"description":"When the link stops working (ISO 8601), or null.","type":["string","null"]},"created_by_user_id":{"description":"Who created the link, or null.","type":["string","null"]}},"required":["id","group_id","list_id","audience","link_code","link_slug","revoked_at","expires_at","created_by_user_id"],"additionalProperties":{},"description":"A public link to a list."},"ShareResult":{"type":"object","properties":{"share":{"$ref":"#/components/schemas/Share"},"token":{"description":"The link token to put in the share URL, or null after REVOKE.","type":["string","null"]},"created":{"description":"For ENSURE: true when a new link was made. Null for ROTATE and REVOKE.","type":["boolean","null"]}},"required":["share","token","created"],"additionalProperties":{},"description":"The list's share link after the change."},"Approval":{"type":"object","properties":{"approvalToken":{"type":"string","description":"Pass this as approvalToken to the operation. Works once."},"actorUserId":{"type":"string","description":"Who approved."},"groupId":{"description":"The group it applies to, or null for account changes.","type":["string","null"]},"operationId":{"type":"string","description":"The operation this approves, such as gifts.lifecycle."},"arguments":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The exact arguments approved. Send the same ones."},"resourceVersion":{"description":"The version approved, or null.","type":["number","null"]},"consequences":{"type":"string","description":"What the change will do. Show this to the user first."},"expiresAt":{"type":"string","description":"When the approval expires, five minutes after it was made (ISO 8601)."}},"required":["approvalToken","actorUserId","groupId","operationId","arguments","resourceVersion","consequences","expiresAt"],"additionalProperties":{},"description":"A one-time approval for a sensitive change."},"Connection":{"type":"object","properties":{"id":{"type":"string","description":"Connection id. Pass it to connections_revoke."},"client_id":{"type":"string","description":"The connected app's OAuth client id."},"scopes":{"type":"array","items":{"type":"string"},"description":"Permissions the app holds."},"created_at":{"type":"string","description":"When the app was approved (ISO 8601)."},"revoked_at":{"description":"When access was revoked (ISO 8601), or null.","type":["string","null"]},"first_mcp_connected_at":{"description":"When the app first listed the MCP tools (ISO 8601), or null.","type":["string","null"]},"status":{"type":"string","enum":["revoked","connected","pending"],"description":"pending until the app first uses MCP, then connected; revoked once access is removed."}},"required":["id","client_id","scopes","created_at","revoked_at","first_mcp_connected_at","status"],"additionalProperties":{},"description":"An AI app or CLI connected to this group."},"NotificationPreferences":{"type":"object","properties":{"collaboration_email":{"type":"boolean","description":"Emails about invitations and group changes."},"claim_reminder_email":{"type":"boolean","description":"Reminders about gifts you claimed."},"product_update_email":{"type":"boolean","description":"Occasional Giftafari product news."}},"required":["collaboration_email","claim_reminder_email","product_update_email"],"additionalProperties":{},"description":"Your email preferences."},"AccountExport":{"type":"object","properties":{"id":{"type":"string","description":"Export id."},"archive":{"type":"object","properties":{"schemaVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Archive format version."},"generatedAt":{"type":"string","description":"When the archive was built (ISO 8601)."},"expiresAt":{"type":"string","description":"When the export record expires (ISO 8601)."},"profile":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Your profile, or null."},"notificationPreferences":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Your email preferences, or null if never set."},"groups":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"description":"Each group with its people, lists, gifts, media manifest, and members."},"myClaims":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"description":"Your own claims."}},"required":["schemaVersion","generatedAt","expiresAt","profile","notificationPreferences","groups","myClaims"],"additionalProperties":{},"description":"Your profile, preferences, groups with their people, lists, and gifts, and your claims."}},"required":["id","archive"],"additionalProperties":{},"description":"A full export of your account data."},"AccountDeletion":{"type":"object","properties":{"id":{"type":"string","description":"Deletion job id."},"user_id":{"type":"string","description":"The closed account."},"state":{"type":"string","description":"COMPLETED when the account is closed."},"phase":{"type":"string","description":"The last phase run."},"completed_phases":{"type":"array","items":{"type":"string"},"description":"Every phase that finished, in order."},"attempt_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many attempts it took."}},"required":["id","user_id","state","phase","completed_phases","attempt_count"],"additionalProperties":{},"description":"The finished account deletion."},"PersonLink":{"type":"object","properties":{"id":{"type":"string","description":"Link invitation id."},"expires_at":{"type":"string","description":"When the link stops working, 48 hours after it was made (ISO 8601)."},"token":{"type":"string","description":"The link secret. Share it only with that person."}},"required":["id","expires_at","token"],"additionalProperties":{},"description":"A one-time link that connects a person to their own Giftafari account."},"TransferResult":{"type":"object","properties":{"groupId":{"type":"string","description":"Group id."},"transferred":{"type":"boolean","const":true,"description":"Ownership moved."},"left":{"type":"boolean","description":"Whether you also left the group."}},"required":["groupId","transferred","left"],"additionalProperties":{},"description":"The ownership transfer result."},"LeaveResult":{"type":"object","properties":{"groupId":{"type":"string","description":"Group id."},"left":{"type":"boolean","const":true,"description":"You left."}},"required":["groupId","left"],"additionalProperties":{},"description":"You left the group."},"RemovedMembership":{"type":"object","properties":{"id":{"type":"string","description":"The removed membership id."}},"required":["id"],"additionalProperties":{},"description":"The collaborator was removed."},"ClaimCreated":{"type":"object","properties":{"claimId":{"type":"string","description":"The new claim id. Pass it to claims_gift or claims_lifecycle."}},"required":["claimId"],"additionalProperties":{},"description":"You claimed the gift."},"RevokedConnection":{"type":"object","properties":{"id":{"type":"string","description":"Connection id."},"revoked_at":{"type":"string","description":"When access was revoked (ISO 8601)."}},"required":["id","revoked_at"],"additionalProperties":{},"description":"The connection no longer has access."},"CredentialsRevoked":{"type":"object","properties":{"revoked":{"type":"boolean","const":true,"description":"Every connected app lost access."}},"required":["revoked"],"additionalProperties":{},"description":"All connected apps and CLIs were signed out."},"GroupsListResult":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}},"MembershipsListResult":{"type":"array","items":{"$ref":"#/components/schemas/Membership"}},"PeopleListResult":{"type":"array","items":{"$ref":"#/components/schemas/Person"}},"ListsListResult":{"type":"array","items":{"$ref":"#/components/schemas/List"}},"ListsTrashResult":{"type":"array","items":{"$ref":"#/components/schemas/List"}},"GiftsListResult":{"type":"array","items":{"$ref":"#/components/schemas/Gift"}},"GiftsTrashResult":{"type":"array","items":{"$ref":"#/components/schemas/Gift"}},"ClaimsListResult":{"type":"array","items":{"$ref":"#/components/schemas/Claim"}},"InvitationsListResult":{"type":"array","items":{"$ref":"#/components/schemas/Invitation"}},"ConnectionsListResult":{"type":"array","items":{"$ref":"#/components/schemas/Connection"}},"Meta":{"type":"object","properties":{"requestId":{"type":"string","description":"Quote this in support requests."}},"required":["requestId"]},"Error":{"type":"object","description":"A failed request. Branch on code, which never changes for a given failure; show message to a person.","properties":{"code":{"type":"string","description":"Stable, machine-readable error code, such as INVALID_ID.","examples":["INVALID_ID","NOT_FOUND","RATE_LIMITED"]},"message":{"type":"string","description":"What went wrong, for a person."}},"required":["code","message"]},"ErrorEnvelope":{"type":"object","description":"The body of every 4xx and 5xx response.","properties":{"data":{"type":"null"},"error":{"$ref":"#/components/schemas/Error"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","error","meta"]}},"headers":{"RateLimit":{"description":"Remaining quota in the current window, as an IETF RateLimit field: \"<policy>\";r=<remaining>;t=<seconds until reset>. The policy is usually the operationId (each operation has its own quota); GET /v1 reports api-root, an unknown path, method, or malformed path id reports unmatched, and the hourly preview quota reports product-previews. RateLimit-Remaining and RateLimit-Reset carry the same numbers.","schema":{"type":"string"}},"RateLimit-Policy":{"description":"The quota, as an IETF RateLimit-Policy field: \"<policy>\";q=<requests>;w=<window seconds>. RateLimit-Limit carries the same request count.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}},"WWW-Authenticate":{"description":"Bearer challenge with the protected-resource metadata URL (RFC 9728).","schema":{"type":"string"}}},"securitySchemes":{"oauth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://app.giftafari.com/oauth/authorize","tokenUrl":"https://app.giftafari.com/api/oauth/token","scopes":{"account:read":"account:read","account:write":"account:write","account:memberships":"account:memberships","group:read":"group:read","group:admin":"group:admin","people:read":"people:read","people:write":"people:write","lists:read":"lists:read","lists:write":"lists:write","gifts:read":"gifts:read","gifts:write":"gifts:write","claims:write":"claims:write","claims:read":"claims:read","shares:write":"shares:write","connections:read":"connections:read","connections:write":"connections:write","notifications:read":"notifications:read","notifications:write":"notifications:write","account:export":"account:export","account:delete":"account:delete"}}}}}}}