> For the complete documentation index, see [llms.txt](https://eventx-hq.gitbook.io/knowledge-base/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://eventx-hq.gitbook.io/knowledge-base/api-v2/attendees.md).

# Attendees

Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert

## List attendees in an event

> Returns paginated attendees for an event. Requires organizer\_api\_token with scope org (any event in org) or event (this event only). Pure token-level, not user. Supports limit/offset and optional externalId/email/addOnId filter (addOnId returns only attendees who have selected that addon — exists in attendee\_add\_on). Token read permission suffices.

```json
{"openapi":"3.1.0","info":{"title":"EventX Public API v2","version":"v2"},"tags":[{"name":"attendees","description":"Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert"}],"servers":[{"url":"https://api.eventx.io","description":"EventX Public API server"}],"security":[{"organizerApiToken":[]}],"components":{"securitySchemes":{"organizerApiToken":{"type":"http","scheme":"bearer","description":"Organizer API token — Authorization: Bearer evtx_live_… (Org/Event scoped, read/write)."}}},"paths":{"/v2/events/{eventId}/attendees":{"get":{"tags":["attendees"],"summary":"List attendees in an event","description":"Returns paginated attendees for an event. Requires organizer_api_token with scope org (any event in org) or event (this event only). Pure token-level, not user. Supports limit/offset and optional externalId/email/addOnId filter (addOnId returns only attendees who have selected that addon — exists in attendee_add_on). Token read permission suffices.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Event UUID"},"required":true,"name":"eventId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Limit 1-100, default 50"},"required":false,"name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0,"description":"Offset"},"required":false,"name":"offset","in":"query"},{"schema":{"type":"string","description":"Filter by externalId (provider ID)"},"required":false,"name":"externalId","in":"query"},{"schema":{"type":"string","description":"Filter by email"},"required":false,"name":"email","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Filter by addon ID — returns only attendees who have selected this addon (exists in attendee_add_on for this event)"},"required":false,"name":"addOnId","in":"query"},{"schema":{"type":"string","description":"Free-text search across firstName, lastName, email, name, organization, externalId (case-insensitive substring)"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","enum":["pending","confirmed","cancelled"],"description":"Filter by registration status"},"required":false,"name":"registrationStatus","in":"query"},{"schema":{"type":"string","enum":["waitlisted","approved","rejected"],"description":"Filter by approval status"},"required":false,"name":"approvalStatus","in":"query"},{"schema":{"type":"string","enum":["none","suspended"],"description":"Filter by suspend status"},"required":false,"name":"suspendStatus","in":"query"},{"schema":{"type":"string","description":"Comma-separated role tags — matches attendees with ANY of the listed tags (OR)"},"required":false,"name":"roleTags","in":"query"},{"schema":{"type":"string","description":"Custom field key to search within"},"required":false,"name":"customFieldKey","in":"query"},{"schema":{"type":"string","description":"Substring to match within the custom field value (case-insensitive)"},"required":false,"name":"customFieldContains","in":"query"},{"schema":{"type":"string","enum":["createdAt","name","email"],"description":"Sort field (default: createdAt)"},"required":false,"name":"sortBy","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction (default: desc)"},"required":false,"name":"sortDirection","in":"query"}],"responses":{"200":{"description":"Paginated list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Attendee ID, UUID"},"eventId":{"type":"string","format":"uuid","description":"Event ID"},"externalId":{"type":["string","null"],"description":"Provider external ID, scoped by event (UNIQUE(event_id, externalId))"},"email":{"type":["string","null"],"description":"Contact email (maps to invitation_email, optional)"},"customQrString":{"type":["string","null"],"description":"Custom QR string (maps to customCheckInToken, writable)"},"checkInToken":{"type":["string","null"],"description":"System check-in token, read-only (from check_in_token, ignored on write)"},"name":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"jobTitle":{"type":["string","null"]},"organization":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"areaCode":{"type":["string","null"]},"contactNo":{"type":["string","null"]},"roleTags":{},"customFields":{},"approvalStatus":{"type":["string","null"]},"registrationStatus":{"type":["string","null"]},"suspendStatus":{"type":"string"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]},"addOns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Add-on row ID"},"addOnId":{"type":["string","null"],"description":"FK to ticket_class_add_on"},"qty":{"type":"integer","description":"Quantity"},"selectionStatus":{"type":["string","null"],"description":"Selection status (regular/waitlisted/confirmed)"},"confirmedAt":{"type":["string","null"],"description":"Confirmation timestamp"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]}},"required":["id","addOnId","qty","selectionStatus","confirmedAt","createdAt","updatedAt"],"description":"Attendee add-on record"},"description":"Associated add-on records"}},"required":["id","eventId","externalId","email","customQrString","checkInToken","name","firstName","lastName","jobTitle","organization","city","country","areaCode","contactNo","approvalStatus","registrationStatus","suspendStatus","createdAt","updatedAt","addOns"],"description":"Attendee row — scoped by organizer_api_token (Org or Event, not user). Token permissions: read allows GET, write allows all. See info.description for full token scope."}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["data","total","limit","offset"]}}}},"400":{"description":"Validation error (invalid sortBy, registrationStatus, approvalStatus, suspendStatus, sortDirection)","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"401":{"description":"Unauthorized — missing or invalid organizer token","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"403":{"description":"Forbidden — token scope mismatch or read required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}}}}}}}
```

## Create an attendee

> Creates attendee — supply externalId at creation to enable later provider-based update (ext\_123). Email optional (no unique per event). Custom QR string writable (customCheckInToken), checkInToken read-only ignored. Requires organizer\_api\_token write, org/event scoped.

```json
{"openapi":"3.1.0","info":{"title":"EventX Public API v2","version":"v2"},"tags":[{"name":"attendees","description":"Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert"}],"servers":[{"url":"https://api.eventx.io","description":"EventX Public API server"}],"security":[{"organizerApiToken":[]}],"components":{"securitySchemes":{"organizerApiToken":{"type":"http","scheme":"bearer","description":"Organizer API token — Authorization: Bearer evtx_live_… (Org/Event scoped, read/write)."}}},"paths":{"/v2/events/{eventId}/attendees":{"post":{"tags":["attendees"],"summary":"Create an attendee","description":"Creates attendee — supply externalId at creation to enable later provider-based update (ext_123). Email optional (no unique per event). Custom QR string writable (customCheckInToken), checkInToken read-only ignored. Requires organizer_api_token write, org/event scoped.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Event UUID"},"required":true,"name":"eventId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","maxLength":100,"description":"Provider external ID, scoped by event, optional but recommended for upsert"},"email":{"type":"string","maxLength":254,"format":"email","description":"Contact email (maps to invitation_email, optional, no unique)"},"customQrString":{"type":"string","maxLength":500,"description":"Custom QR string (maps to customCheckInToken, writable)"},"name":{"type":"string","maxLength":500},"firstName":{"type":"string","maxLength":500},"lastName":{"type":"string","maxLength":500},"jobTitle":{"type":"string","maxLength":500},"organization":{"type":"string","maxLength":500},"city":{"type":"string","maxLength":50},"country":{"type":"string","maxLength":50},"areaCode":{"type":"string","maxLength":50},"contactNo":{"type":"string","maxLength":50},"customFields":{"type":"object","additionalProperties":{},"description":"Custom fields keyed by custom-field id (GET /custom-fields). Values are wrapped as {value: string|string[]|boolean} (or {value, mediaValues} for fileUpload). Flat string/boolean/array values are auto-wrapped server-side. Unknown field ids → 400."},"roleTags":{"type":"array","items":{"type":"string"},"description":"Visible role tags (visitor/organizer/host/speaker/exhibitor/booth-rep). Defaults to [\"visitor\"] when omitted — tag-less attendees are hidden from the portal people list."}},"description":"Create attendee — supply externalId at creation to enable later update by provider ID (ext_123). Email optional. Custom QR string writable; checkInToken read-only ignored. customFields must use custom-field ids from GET /custom-fields, wrapped as {value: ...}."}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Attendee ID, UUID"},"eventId":{"type":"string","format":"uuid","description":"Event ID"},"externalId":{"type":["string","null"],"description":"Provider external ID, scoped by event (UNIQUE(event_id, externalId))"},"email":{"type":["string","null"],"description":"Contact email (maps to invitation_email, optional)"},"customQrString":{"type":["string","null"],"description":"Custom QR string (maps to customCheckInToken, writable)"},"checkInToken":{"type":["string","null"],"description":"System check-in token, read-only (from check_in_token, ignored on write)"},"name":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"jobTitle":{"type":["string","null"]},"organization":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"areaCode":{"type":["string","null"]},"contactNo":{"type":["string","null"]},"roleTags":{},"customFields":{},"approvalStatus":{"type":["string","null"]},"registrationStatus":{"type":["string","null"]},"suspendStatus":{"type":"string"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]},"addOns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Add-on row ID"},"addOnId":{"type":["string","null"],"description":"FK to ticket_class_add_on"},"qty":{"type":"integer","description":"Quantity"},"selectionStatus":{"type":["string","null"],"description":"Selection status (regular/waitlisted/confirmed)"},"confirmedAt":{"type":["string","null"],"description":"Confirmation timestamp"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]}},"required":["id","addOnId","qty","selectionStatus","confirmedAt","createdAt","updatedAt"],"description":"Attendee add-on record"},"description":"Associated add-on records"}},"required":["id","eventId","externalId","email","customQrString","checkInToken","name","firstName","lastName","jobTitle","organization","city","country","areaCode","contactNo","approvalStatus","registrationStatus","suspendStatus","createdAt","updatedAt","addOns"],"description":"Attendee row — scoped by organizer_api_token (Org or Event, not user). Token permissions: read allows GET, write allows all. See info.description for full token scope."}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}}}}}}}
```

## Get attendee by ID

> Get single attendee by UUID — token must be scoped to its event/org.

```json
{"openapi":"3.1.0","info":{"title":"EventX Public API v2","version":"v2"},"tags":[{"name":"attendees","description":"Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert"}],"servers":[{"url":"https://api.eventx.io","description":"EventX Public API server"}],"security":[{"organizerApiToken":[]}],"components":{"securitySchemes":{"organizerApiToken":{"type":"http","scheme":"bearer","description":"Organizer API token — Authorization: Bearer evtx_live_… (Org/Event scoped, read/write)."}}},"paths":{"/v2/events/{eventId}/attendees/{attendeeId}":{"get":{"tags":["attendees"],"summary":"Get attendee by ID","description":"Get single attendee by UUID — token must be scoped to its event/org.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Event UUID"},"required":true,"name":"eventId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Attendee UUID"},"required":true,"name":"attendeeId","in":"path"}],"responses":{"200":{"description":"Attendee","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Attendee ID, UUID"},"eventId":{"type":"string","format":"uuid","description":"Event ID"},"externalId":{"type":["string","null"],"description":"Provider external ID, scoped by event (UNIQUE(event_id, externalId))"},"email":{"type":["string","null"],"description":"Contact email (maps to invitation_email, optional)"},"customQrString":{"type":["string","null"],"description":"Custom QR string (maps to customCheckInToken, writable)"},"checkInToken":{"type":["string","null"],"description":"System check-in token, read-only (from check_in_token, ignored on write)"},"name":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"jobTitle":{"type":["string","null"]},"organization":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"areaCode":{"type":["string","null"]},"contactNo":{"type":["string","null"]},"roleTags":{},"customFields":{},"approvalStatus":{"type":["string","null"]},"registrationStatus":{"type":["string","null"]},"suspendStatus":{"type":"string"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]},"addOns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Add-on row ID"},"addOnId":{"type":["string","null"],"description":"FK to ticket_class_add_on"},"qty":{"type":"integer","description":"Quantity"},"selectionStatus":{"type":["string","null"],"description":"Selection status (regular/waitlisted/confirmed)"},"confirmedAt":{"type":["string","null"],"description":"Confirmation timestamp"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]}},"required":["id","addOnId","qty","selectionStatus","confirmedAt","createdAt","updatedAt"],"description":"Attendee add-on record"},"description":"Associated add-on records"}},"required":["id","eventId","externalId","email","customQrString","checkInToken","name","firstName","lastName","jobTitle","organization","city","country","areaCode","contactNo","approvalStatus","registrationStatus","suspendStatus","createdAt","updatedAt","addOns"],"description":"Attendee row — scoped by organizer_api_token (Org or Event, not user). Token permissions: read allows GET, write allows all. See info.description for full token scope."}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}}}}}}}
```

## Update attendee

> Update attendee — identified by either attendeeId (this route) or externalId (via the by-external route); one of the two is required. Supply externalId/customQrString/email etc. checkInToken ignored (read-only). Requires write permission.

```json
{"openapi":"3.1.0","info":{"title":"EventX Public API v2","version":"v2"},"tags":[{"name":"attendees","description":"Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert"}],"servers":[{"url":"https://api.eventx.io","description":"EventX Public API server"}],"security":[{"organizerApiToken":[]}],"components":{"securitySchemes":{"organizerApiToken":{"type":"http","scheme":"bearer","description":"Organizer API token — Authorization: Bearer evtx_live_… (Org/Event scoped, read/write)."}}},"paths":{"/v2/events/{eventId}/attendees/{attendeeId}":{"patch":{"tags":["attendees"],"summary":"Update attendee","description":"Update attendee — identified by either attendeeId (this route) or externalId (via the by-external route); one of the two is required. Supply externalId/customQrString/email etc. checkInToken ignored (read-only). Requires write permission.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Event UUID"},"required":true,"name":"eventId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Attendee UUID"},"required":true,"name":"attendeeId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","maxLength":100},"email":{"type":"string","maxLength":254,"format":"email"},"customQrString":{"type":"string","maxLength":500},"name":{"type":"string","maxLength":500},"firstName":{"type":"string","maxLength":500},"lastName":{"type":"string","maxLength":500},"jobTitle":{"type":"string","maxLength":500},"organization":{"type":"string","maxLength":500},"city":{"type":"string","maxLength":50},"country":{"type":"string","maxLength":50},"areaCode":{"type":"string","maxLength":50},"contactNo":{"type":"string","maxLength":50},"customFields":{"type":"object","additionalProperties":{},"description":"Custom fields merge — provided keys are merged into existing, wrapped as {value}. Unknown field ids → 400. Use null value to delete a key."},"roleTags":{"type":"array","items":{"type":"string"},"description":"Replaces visible role tags. Defaults to [\"visitor\"] on create when omitted; omitted on PATCH leaves tags unchanged."}},"description":"Partial update — at least one field, checkInToken ignored (read-only). customFields are merged, not replaced."}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Attendee ID, UUID"},"eventId":{"type":"string","format":"uuid","description":"Event ID"},"externalId":{"type":["string","null"],"description":"Provider external ID, scoped by event (UNIQUE(event_id, externalId))"},"email":{"type":["string","null"],"description":"Contact email (maps to invitation_email, optional)"},"customQrString":{"type":["string","null"],"description":"Custom QR string (maps to customCheckInToken, writable)"},"checkInToken":{"type":["string","null"],"description":"System check-in token, read-only (from check_in_token, ignored on write)"},"name":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"jobTitle":{"type":["string","null"]},"organization":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"areaCode":{"type":["string","null"]},"contactNo":{"type":["string","null"]},"roleTags":{},"customFields":{},"approvalStatus":{"type":["string","null"]},"registrationStatus":{"type":["string","null"]},"suspendStatus":{"type":"string"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]},"addOns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Add-on row ID"},"addOnId":{"type":["string","null"],"description":"FK to ticket_class_add_on"},"qty":{"type":"integer","description":"Quantity"},"selectionStatus":{"type":["string","null"],"description":"Selection status (regular/waitlisted/confirmed)"},"confirmedAt":{"type":["string","null"],"description":"Confirmation timestamp"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]}},"required":["id","addOnId","qty","selectionStatus","confirmedAt","createdAt","updatedAt"],"description":"Attendee add-on record"},"description":"Associated add-on records"}},"required":["id","eventId","externalId","email","customQrString","checkInToken","name","firstName","lastName","jobTitle","organization","city","country","areaCode","contactNo","approvalStatus","registrationStatus","suspendStatus","createdAt","updatedAt","addOns"],"description":"Attendee row — scoped by organizer_api_token (Org or Event, not user). Token permissions: read allows GET, write allows all. See info.description for full token scope."}}}},"400":{"description":"Validation","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}}}}}}}
```

## Get attendee by externalId

> Get attendee by provider externalId scoped by event — use after creating with externalId (ext\_123). Token must be scoped to event/org.

```json
{"openapi":"3.1.0","info":{"title":"EventX Public API v2","version":"v2"},"tags":[{"name":"attendees","description":"Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert"}],"servers":[{"url":"https://api.eventx.io","description":"EventX Public API server"}],"security":[{"organizerApiToken":[]}],"components":{"securitySchemes":{"organizerApiToken":{"type":"http","scheme":"bearer","description":"Organizer API token — Authorization: Bearer evtx_live_… (Org/Event scoped, read/write)."}}},"paths":{"/v2/events/{eventId}/attendees/by-external/{externalId}":{"get":{"tags":["attendees"],"summary":"Get attendee by externalId","description":"Get attendee by provider externalId scoped by event — use after creating with externalId (ext_123). Token must be scoped to event/org.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Event UUID"},"required":true,"name":"eventId","in":"path"},{"schema":{"type":"string","description":"Provider external ID, scoped by event"},"required":true,"name":"externalId","in":"path"}],"responses":{"200":{"description":"Attendee","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Attendee ID, UUID"},"eventId":{"type":"string","format":"uuid","description":"Event ID"},"externalId":{"type":["string","null"],"description":"Provider external ID, scoped by event (UNIQUE(event_id, externalId))"},"email":{"type":["string","null"],"description":"Contact email (maps to invitation_email, optional)"},"customQrString":{"type":["string","null"],"description":"Custom QR string (maps to customCheckInToken, writable)"},"checkInToken":{"type":["string","null"],"description":"System check-in token, read-only (from check_in_token, ignored on write)"},"name":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"jobTitle":{"type":["string","null"]},"organization":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"areaCode":{"type":["string","null"]},"contactNo":{"type":["string","null"]},"roleTags":{},"customFields":{},"approvalStatus":{"type":["string","null"]},"registrationStatus":{"type":["string","null"]},"suspendStatus":{"type":"string"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]},"addOns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Add-on row ID"},"addOnId":{"type":["string","null"],"description":"FK to ticket_class_add_on"},"qty":{"type":"integer","description":"Quantity"},"selectionStatus":{"type":["string","null"],"description":"Selection status (regular/waitlisted/confirmed)"},"confirmedAt":{"type":["string","null"],"description":"Confirmation timestamp"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]}},"required":["id","addOnId","qty","selectionStatus","confirmedAt","createdAt","updatedAt"],"description":"Attendee add-on record"},"description":"Associated add-on records"}},"required":["id","eventId","externalId","email","customQrString","checkInToken","name","firstName","lastName","jobTitle","organization","city","country","areaCode","contactNo","approvalStatus","registrationStatus","suspendStatus","createdAt","updatedAt","addOns"],"description":"Attendee row — scoped by organizer_api_token (Org or Event, not user). Token permissions: read allows GET, write allows all. See info.description for full token scope."}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}}}}}}}
```

## Update attendee by externalId

> Update attendee by externalId — identified by either externalId (this route) or attendeeId (via the by-attendee-id route); one of the two is required. Idempotent. Supply customQrString/email etc. checkInToken ignored. Use after creation with externalId.

```json
{"openapi":"3.1.0","info":{"title":"EventX Public API v2","version":"v2"},"tags":[{"name":"attendees","description":"Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert"}],"servers":[{"url":"https://api.eventx.io","description":"EventX Public API server"}],"security":[{"organizerApiToken":[]}],"components":{"securitySchemes":{"organizerApiToken":{"type":"http","scheme":"bearer","description":"Organizer API token — Authorization: Bearer evtx_live_… (Org/Event scoped, read/write)."}}},"paths":{"/v2/events/{eventId}/attendees/by-external/{externalId}":{"patch":{"tags":["attendees"],"summary":"Update attendee by externalId","description":"Update attendee by externalId — identified by either externalId (this route) or attendeeId (via the by-attendee-id route); one of the two is required. Idempotent. Supply customQrString/email etc. checkInToken ignored. Use after creation with externalId.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Event UUID"},"required":true,"name":"eventId","in":"path"},{"schema":{"type":"string","description":"Provider external ID, scoped by event"},"required":true,"name":"externalId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","maxLength":100},"email":{"type":"string","maxLength":254,"format":"email"},"customQrString":{"type":"string","maxLength":500},"name":{"type":"string","maxLength":500},"firstName":{"type":"string","maxLength":500},"lastName":{"type":"string","maxLength":500},"jobTitle":{"type":"string","maxLength":500},"organization":{"type":"string","maxLength":500},"city":{"type":"string","maxLength":50},"country":{"type":"string","maxLength":50},"areaCode":{"type":"string","maxLength":50},"contactNo":{"type":"string","maxLength":50},"customFields":{"type":"object","additionalProperties":{},"description":"Custom fields merge — provided keys are merged into existing, wrapped as {value}. Unknown field ids → 400. Use null value to delete a key."},"roleTags":{"type":"array","items":{"type":"string"},"description":"Replaces visible role tags. Defaults to [\"visitor\"] on create when omitted; omitted on PATCH leaves tags unchanged."}},"description":"Partial update — at least one field, checkInToken ignored (read-only). customFields are merged, not replaced."}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Attendee ID, UUID"},"eventId":{"type":"string","format":"uuid","description":"Event ID"},"externalId":{"type":["string","null"],"description":"Provider external ID, scoped by event (UNIQUE(event_id, externalId))"},"email":{"type":["string","null"],"description":"Contact email (maps to invitation_email, optional)"},"customQrString":{"type":["string","null"],"description":"Custom QR string (maps to customCheckInToken, writable)"},"checkInToken":{"type":["string","null"],"description":"System check-in token, read-only (from check_in_token, ignored on write)"},"name":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"jobTitle":{"type":["string","null"]},"organization":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"areaCode":{"type":["string","null"]},"contactNo":{"type":["string","null"]},"roleTags":{},"customFields":{},"approvalStatus":{"type":["string","null"]},"registrationStatus":{"type":["string","null"]},"suspendStatus":{"type":"string"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]},"addOns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Add-on row ID"},"addOnId":{"type":["string","null"],"description":"FK to ticket_class_add_on"},"qty":{"type":"integer","description":"Quantity"},"selectionStatus":{"type":["string","null"],"description":"Selection status (regular/waitlisted/confirmed)"},"confirmedAt":{"type":["string","null"],"description":"Confirmation timestamp"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]}},"required":["id","addOnId","qty","selectionStatus","confirmedAt","createdAt","updatedAt"],"description":"Attendee add-on record"},"description":"Associated add-on records"}},"required":["id","eventId","externalId","email","customQrString","checkInToken","name","firstName","lastName","jobTitle","organization","city","country","areaCode","contactNo","approvalStatus","registrationStatus","suspendStatus","createdAt","updatedAt","addOns"],"description":"Attendee row — scoped by organizer_api_token (Org or Event, not user). Token permissions: read allows GET, write allows all. See info.description for full token scope."}}}},"400":{"description":"Validation","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}}}}}}}
```

## Bulk upsert attendees

> Bulk upsert 1-50 attendees — upsert key externalId if present else email (no unique on email, app-level fallback). Each item independent, partial success allowed. Requires organizer\_api\_token write, org/event scoped. Fits bodyLimit 1MB and rateLimit 60/60s. Per-item autonomous, idempotent via UNIQUE(event\_id, externalId).

```json
{"openapi":"3.1.0","info":{"title":"EventX Public API v2","version":"v2"},"tags":[{"name":"attendees","description":"Event attendee management — externalId scoped by event, email optional, customQrString writable, checkInToken read-only, bulk upsert"}],"servers":[{"url":"https://api.eventx.io","description":"EventX Public API server"}],"security":[{"organizerApiToken":[]}],"components":{"securitySchemes":{"organizerApiToken":{"type":"http","scheme":"bearer","description":"Organizer API token — Authorization: Bearer evtx_live_… (Org/Event scoped, read/write)."}}},"paths":{"/v2/events/{eventId}/attendees/bulk-upsert":{"post":{"tags":["attendees"],"summary":"Bulk upsert attendees","description":"Bulk upsert 1-50 attendees — upsert key externalId if present else email (no unique on email, app-level fallback). Each item independent, partial success allowed. Requires organizer_api_token write, org/event scoped. Fits bodyLimit 1MB and rateLimit 60/60s. Per-item autonomous, idempotent via UNIQUE(event_id, externalId).","parameters":[{"schema":{"type":"string","format":"uuid","description":"Event UUID"},"required":true,"name":"eventId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"attendees":{"type":"array","items":{"type":"object","properties":{"externalId":{"type":"string","maxLength":100},"email":{"type":"string","maxLength":254,"format":"email"},"customQrString":{"type":"string","maxLength":500},"name":{"type":"string","maxLength":500},"firstName":{"type":"string","maxLength":500},"lastName":{"type":"string","maxLength":500},"customFields":{"type":"object","additionalProperties":{},"description":"Wrapped {value: ...} keyed by custom-field id; flat values auto-wrapped."}},"description":"Attendee upsert item — externalId if present else email is key, no unique on email"},"minItems":1,"maxItems":50,"description":"Batch max 50, per-item autonomous, partial success allowed. Fits bodyLimit 1MB and rateLimit 60/60s."}},"required":["attendees"],"description":"Bulk upsert — upsert key externalId if present else email. Each item independent, idempotent. Requires organizer_api_token write, org/event scoped."}}}},"responses":{"200":{"description":"Per-item results","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"index":{"type":"number"},"attendeeId":{"type":["string","null"]},"externalId":{"type":["string","null"]},"status":{"type":"string","enum":["created","updated","failed"]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["index","attendeeId","externalId","status"]}}},"required":["results"]}}}},"400":{"description":"Validation","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"number"},"meta":{}},"required":["code","message","status"]}}}}}}}}}
```
