# People

Source: https://swapcard.dev/content-api/examples/people


Find, list, create, update and delete the people of an event. People are everyone who takes part in an event in any form: visitors, attendees, speakers, moderators, organizer staff, exhibitor and partner members.

Reference: [`EventPerson` object](../graphql-event-api-schema/objects/event-person.mdx)

On this page you can:

- [Find people](#fetch-people-on-an-event) by email, ID or text search.
- [List all people](#list-all-people) of an event, 100 at a time.
- [Create people](#create-a-basic-people-profile), [update people](#update-a-basic-people-profile), or [create or update](#create-or-update-a-people) them in one call.
- [Assign groups, codes, sessions and exhibitors](#perform-different-actions-on-a-people) to people.
- [Delete people](#delete-people).

## How people profiles work

### Users and non-users

A people profile can be a **user** (a person with an account) or a **non-user** (a person without an account):

- A **user** has a personal account to log in and access the event through the Swapcard web and mobile apps.
- A **non-user** has a profile without an account and can't sign in. Use it for people who don't want to use the app but should be listed in it (for example a VIP speaker), or whose badge needs to be scanned for lead retrieval.

In Studio, non-users are listed as **People without account**.

### Required and recommended fields

To create a profile, you need:

| Field | When |
| --- | --- |
| `clientId`, `firstName`, `lastName` | Always. |
| `email` | For users only (`isUser: true`). It must be unique within the community, and you can't update it through the API after the profile is created. |
| A group ID | Always. Set it with the `updateGroups` action. |

We recommend that you also fill in `jobTitle`, `organization` and custom fields, to improve matchmaking results and networking opportunities. For speakers, also fill in `biography` and `photoUrl`. If the profile needs to work with Lead Capture, Session Scanning or Check-in, add a barcode with the `updateBarcodes` action.

### Visibility

By default, people are visible to every other user. All fields are public except contact details: email address, phone numbers and postal address. These are never shown to other participants, whatever the visibility settings. To hide a group of people from another group, set up a visibility right in Swapcard Studio.

To hide someone from everybody, set `isVisible` to `false`. The person can still access the event, but other participants can't see them. Users can change their own visibility at any time from the web or mobile app.

:::danger[Unique clientId at community level]
A user profile is unique to a community. The `clientId` field is the unique identifier of a person and must be unique inside a community.
:::

:::danger[Phone numbers format]
Specify phone numbers in the [E.164](http://en.wikipedia.org/wiki/E.164) format, prefixed with `+`. For example, the US phone number 415 555 0101 becomes `+14155550101`: the `+` prefix, then the US country code `1`, then the local subscriber number.
:::

## Before you begin

- An API key, sent in the `Authorization` header. The key acts with the roles and permissions of the user who created it. See [Authentication](/organizer/authentication).
- The ID of your event (`eventId`). See [Events](./graphql-event-api-examples-event.md).
- To create people, the ID of at least one group. See [Groups](./graphql-event-api-examples-groups.md#fetch-all-event-groups-by-event-id).

## Find people
Use the `eventPerson` query to find one or more people on an event, either with filters or with a text search.

### Filter people
Use `filters` to find people by exact values, such as a list of email addresses.

| Argument | Type | Description |
| --- | --- | --- |
| `eventId` | `ID!` | The ID of the event. |
| `filters.emails` | `[String!]` | One or more email addresses. |

Other useful filters include `eventPeopleIds`, `clientIds` and `lastUpdatedSince`. See [`EventPersonFilter`](../graphql-event-api-schema/inputs/event-person-filter.mdx) for the full list.

```graphql title="Query"
query eventPerson($eventId: ID!, $filters: [EventPersonFilter!]) {
  eventPerson(eventId: $eventId, filters: $filters) {
    nodes {
      createdAt
      firstName
      id
      lastName
      jobTitle
      organization
      userId
    }
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "filters": {
    "emails": [
      "test@test.fr",
      "test1@test1.com"
    ]
  }
}
```

### Search people by text

Use `search` to look up a single profile with a free-text string, such as an email address.

| Argument | Type | Description |
| --- | --- | --- |
| `eventId` | `ID!` | The ID of the event. |
| `search` | `String` | The text to search for. Matches across name, email, organization and other indexed fields. |

```graphql title="Query"
query eventPerson($eventId: ID!, $search: String!) {
  eventPerson(eventId: $eventId, search: $search) {
    nodes {
      createdAt
      firstName
      id
      lastName
      jobTitle
      organization
      userId
    }
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "search": "test@test.fr"
}
```

## List all people

Use `cursor` to paginate through all the people of an event.

:::warning
For all queries that support pagination, we recommend that you **don't request more than 100** items per page.
:::

### Get the first page
Set `cursor.first` to `100` to fetch the first 100 people of the event.

```graphql title="Query"
query eventPerson($eventId: ID!, $cursor: CursorPaginationInput) {
  eventPerson(eventId: $eventId, cursor: $cursor) {
    pageInfo {
      hasNextPage
      endCursor
      totalItems
      startCursor
      lastPage
      hasPreviousPage
      currentPage
    }
    totalCount
    nodes {
      id
      clientIds
      email
      firstName
      lastName
      jobTitle
      organization
      photoUrl
      websiteUrl
      biography
      address {
        street
        city
        zipCode
        state
        country
      }
      phoneNumbers {
        formattedNumber
        type
        number
      }
      socialNetworks {
        profile
        type
      }
      groups {
        id
        name
      }
      source
      updatedAt
      createdAt
      withEvent(eventId: $eventId) {
        fields {
          ... on SelectField {
            translations {
              value
              language
            }
            definition {
              id
              translations {
                name
                language
              }
            }
          }
        }
        badges {
          ... on BadgeBarcode {
            __typename
            barcode
            createdAt
          }
        }
      }
    }
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "cursor": {
    "first": 100
  }
}
```

### Get the next page
To fetch the next 100 people, pass the `pageInfo.endCursor` value from the previous response as `cursor.after`. Repeat until `hasNextPage` is `false`.

```graphql title="Query"
query eventPerson($eventId: ID!, $cursor: CursorPaginationInput) {
  eventPerson(eventId: $eventId, cursor: $cursor) {
    pageInfo {
      hasNextPage
      endCursor
      totalItems
      startCursor
      lastPage
      hasPreviousPage
      currentPage
    }
    totalCount
    nodes {
      id
      clientIds
      email
      firstName
      lastName
      jobTitle
      photoUrl
      organization
      websiteUrl
      biography
      address {
        state
        street
        city
        country
        zipCode
        place
      }
      phoneNumbers {
        formattedNumber
        type
        number
      }
      socialNetworks {
        profile
        type
      }
      groups {
        id
        name
      }
      source
      updatedAt
      createdAt
    }
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "cursor": {
    "first": 100,
    "after": "cursorId"
  }
}
```

## Create people
Use the `importEventPeople` mutation with a `create` object to create basic profiles, for users and non-users. In this example, John Doe is a user and Dummy User is a non-user. Both are added to a group.

| Argument | Type | Description |
| --- | --- | --- |
| `clientId` | `ID` | Your unique identifier for the profile. Any alphanumeric value, unique within the community. You can't change it after the profile is created. |
| `create.firstName` | `String!` | The person's first name. |
| `create.lastName` | `String!` | The person's last name. |
| `create.email` | `String` | The person's email address. Required for users only, and unique for each profile. You can't update it through the API after the profile is created. |
| `create.isUser` | `Boolean!` | `true` creates a user account for this profile. `false` creates the profile only. |
| `actions.updateGroups` | `EventPersonUpdateGroupsActionInput` | The groups to add the person to. |

```graphql title="Mutation"
mutation importEventPeople($eventId: ID!, $data: [ImportEventPersonInput!]!) {
  importEventPeople(eventId: $eventId, validateOnly: false, data: $data) {
    errors {
      inputId
      errorCode
      message
    }
    results {
      inputId
      eventPerson {
        id
        email
      }
    }
    eventPeopleCreated
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "data": [
    {
      "clientId": "9876543210",
      "create": {
        "isUser": true,
        "isVisible": true,
        "email": "test@test.com",
        "firstName": "John",
        "lastName": "Doe"
      },
      "actions": {
        "updateGroups": {
          "action": "ADD",
          "groupIds": [
            "RXZlbnR8xNjcyMjI="
          ]
        }
      }
    },
    {
      "clientId": "1234567890",
      "create": {
        "isUser": false,
        "isVisible": false,
        "firstName": "Dummy",
        "lastName": "User"
      },
      "actions": {
        "updateGroups": {
          "action": "ADD",
          "groupIds": [
            "RXZlbnR8xNjcyMjI="
          ]
        }
      }
    }
  ]
}
```

## Update people
Use the `importEventPeople` mutation with an `update` object to update existing profiles, for users and non-users.

| Argument | Type | Description |
| --- | --- | --- |
| `clientId` | `ID` | The same value you used when you created the profile. |
| `update.email` | `String` | The same email address you used when you created the profile. Required for users only. |

```graphql title="Mutation"
mutation importEventPeople($eventId: ID!, $data: [ImportEventPersonInput!]!) {
  importEventPeople(eventId: $eventId, validateOnly: false, data: $data) {
    errors {
      inputId
      errorCode
      message
    }
    results {
      inputId
      eventPerson {
        id
        email
      }
    }
    eventPeopleUpdated
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "data": [
    {
      "clientId": "987654321",
      "update": {
        "isUser": true,
        "isVisible": true,
        "email": "test@test.com",
        "firstName": "UpdateJohn",
        "lastName": "UpdateDoe"
      }
    },
    {
      "clientId": "1234567890",
      "update": {
        "isUser": false,
        "isVisible": false,
        "firstName": "UpdateDummy",
        "lastName": "UpdateUser"
      }
    }
  ]
}
```

## Create or update people
Use the `importEventPeople` mutation with both a `create` and an `update` object to create or update a detailed profile in one call. This example also sets the job, address, social networks and custom fields, and adds the person to a group.

| Argument | Type | Description |
| --- | --- | --- |
| `clientId` | `ID` | Your unique identifier for the profile. Any alphanumeric value, unique for each profile. You can't change it after the profile is created. |
| `firstName` | `String` | The person's first name. |
| `lastName` | `String` | The person's last name. |
| `email` | `String` | The person's email address. |

```graphql title="Mutation"
mutation importEventPeople($eventId: ID!, $data: [ImportEventPersonInput!]!) {
  importEventPeople(eventId: $eventId, validateOnly: false, data: $data) {
    errors {
      inputId
      errorCode
      message
    }
    results {
      inputId
      eventPerson {
        id
        email
      }
    }
    eventPeopleCreated
    eventPeopleUpdated
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "data": [
    {
      "clientId": "987654321",
      "create": {
        "isUser": true,
        "email": "test@test.com",
        "firstName": "John",
        "lastName": "Doe",
        "jobTitle": "CEO",
        "organization": "Tesla",
        "biography": "Lorem ipsum dolor sit amet, odio prima pri te, id sanctus recteque deterruisset vel. Dico tractatos eam eu, dolor inciderint in est.",
        "websiteUrl": "https://www.tesla.com",
        "photoUrl": "https://fakeimg.pl/300/picture.jpg",
        "mobilePhone": "+1-541-754-3010",
        "address": {
          "city": "Paris",
          "country": "France",
          "zipCode": "75010",
          "street": "6 rue de Paradis"
        },
        "socialNetworks": [
          {
            "type": "LINKEDIN",
            "profile": "johndoe"
          }
        ],
        "customFields": [
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMA==",
            "action": "SET_VALUE",
            "value": "Research & Development"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMQ==",
            "action": "SET_VALUE",
            "value": "France"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMg==",
            "action": "SET_VALUE",
            "value": "Robotics"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMg==",
            "action": "SET_VALUE",
            "value": "Blockchain"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMg==",
            "action": "SET_VALUE",
            "value": "AI"
          }
        ]
      },
      "update": {
        "isUser": true,
        "email": "test@test.com",
        "firstName": "UpdateJohn",
        "lastName": "UpdateDoe",
        "jobTitle": "CTO",
        "organization": "Tesla New",
        "biography": "Lorem ipsum dolor sit amet, odio prima pri te, id sanctus recteque deterruisset vel. Dico tractatos eam eu, dolor inciderint in est.",
        "websiteUrl": "https://www.teslanew.com",
        "photoUrl": "https://fakeimg.pl/300/picture.jpg",
        "mobilePhone": "+1-541-754-3010",
        "address": {
          "city": "Paris",
          "country": "France",
          "zipCode": "75010",
          "street": "6 rue de Paradis"
        },
        "socialNetworks": [
          {
            "type": "LINKEDIN",
            "profile": "updatejohndoe"
          }
        ],
        "customFields": [
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMA==",
            "action": "SET_VALUE",
            "value": "Research & Development 1"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMQ==",
            "action": "SET_VALUE",
            "value": "France 1"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMg==",
            "action": "SET_VALUE",
            "value": "Robotics 1"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMg==",
            "action": "SET_VALUE",
            "value": "Blockchain 1"
          },
          {
            "groupId": "RXZlbnRQZW9wZEdyb3VwXzExMg==",
            "action": "SET_VALUE",
            "value": "AI 1"
          }
        ]
      },
      "actions": {
        "updateGroups": {
          "action": "ADD",
          "groupIds": [
            "RXZlbnR8xNjcyMjI="
          ]
        }
      }
    }
  ]
}
```

## Assign groups, codes, sessions and exhibitors
Use the `actions` object of `importEventPeople` to create a profile and link it to the rest of the event in the same call. The example below runs these steps in order:

1. Create or update the profile details.
2. Add or update the person's groups (`updateGroups`).
3. Add or update the person's codes, QR code or barcode (`updateBarcodes`).
4. Add or update the person as a speaker of sessions, `plannings` in the API (`isSpeakerOnPlannings`).
5. Add or update the person as an attendee of sessions (`isAttendeeOnPlannings`).
6. Add or update the person as a member of exhibitors (`isMemberOnExhibitors`).

| Argument | Type | Description |
| --- | --- | --- |
| `clientId` | `ID` | Your unique identifier for the profile. Any alphanumeric value, unique for each profile. You can't change it after the profile is created. |
| `firstName` | `String` | The person's first name. |
| `lastName` | `String` | The person's last name. |
| `email` | `String` | The person's email address. |
| `actions.*.action` | `ListAction` | `ADD` appends the items to the existing list, `REMOVE` removes them from it, and `REPLACE` replaces the whole list. |
| `force` | `Boolean` | Optional. Bypasses some validation checks. See [Force an import](#additional-optional-arguments). |

Keep in mind:

- The groups **must already exist**. Create them in Swapcard Studio or with the [`createEventGroup` mutation](./graphql-event-api-examples-groups.md#create-a-new-group-on-an-event) before you add them to a profile.
- You **can't update the email address** of a user through the API.
- You can add several codes to a profile. They all work for scanning, but the app shows **only the latest one** in the ticket button.

```graphql title="Mutation"
mutation importEventPeople($eventId: ID!, $data: [ImportEventPersonInput!]!) {
  importEventPeople(eventId: $eventId, validateOnly: false, data: $data) {
    errors {
      inputId
      errorCode
      message
    }
    results {
      inputId
      eventPerson {
        id
        email
        updatedAt
        speakerOnPlannings {
          id
          title
        }
        userId
        memberOnExhibitors {
          id
          name
        }
      }
    }
    eventPeopleUpdated
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "data": [
    {
      "clientId": "987654321",
      "create": {
        "isUser": true,
        "email": "test@test.com",
        "firstName": "John",
        "lastName": "Doe"
      },
      "actions": {
        "updateGroups": {
          "action": "ADD",
          "groupIds": [
            "RXZlbnR8xNjcyMjI="
          ]
        },
        "updateBarcodes": {
          "action": "ADD",
          "barcodes": [
            {
              "type": "QR_CODE",
              "value": "1234567890"
            },
            {
              "type": "QR_CODE",
              "value": "9876543210"
            },
            {
              "type": "FILE",
              "value": "https://www.test.com/badge.pdf"
            }
          ]
        },
        "isSpeakerOnPlannings": {
          "action": "ADD",
          "planningIds": [
            "UGxhbmODAwMzk1"
          ]
        },
        "isAttendeeOnPlannings": {
          "action": "ADD",
          "planningIds": [
            "UGxhbmwMzk1"
          ]
        },
        "isMemberOnExhibitors": {
          "action": "ADD",
          "exhibitorIds": [
            "RXhoaWJzk2Nw=="
          ]
        }
      },
      "force": true
    }
  ]
}
```

### Force an import
Set `force` to `true` to bypass the `CLIENT_ID_CONFLICT` security checks. A forced import allows you to:

- **Switch the user of a community profile.** An email is associated with a user, a user with a community profile, and a `clientId` with a community profile. By default, the API checks that the email and `clientId` pair matches: the user associated with the email must be the user of the community profile found by the `clientId`. A forced import skips this check, so you can switch any user from the community profile found by the `clientId`.
- **Use more than one `clientId` per community profile.** By default, the API makes sure you use the same `clientId` to refer to a user's community profile. A forced import allows several `clientId` values per community profile, and adds the `clientId` if it doesn't exist yet. Every `clientId` must still be unique inside the community.

Force the import when:

- your community is new and no event has taken place yet, **or**
- the people you are importing are new to Swapcard (they don't have an account yet), **or**
- you don't need people to keep their data (contacts, bookmarks, meetings, profile data, etc.) from previous events,
- **and** you don't have several events running at the same time in your community.

Don't force the import when:

- you have several events running at the same time in your community, **or**
- some users already have an account in your community and you want them to keep their data (contacts, bookmarks, meetings, profile data, etc.) from previous events.

## Delete people

Use the `deleteEventPeople` mutation to delete one or more profiles from an event.

| Argument | Type | Description |
| --- | --- | --- |
| `eventId` | `ID!` | The ID of the event to delete the profiles from. |
| `eventPeopleIds` | `[ID!]!` | The IDs of the profiles to delete. |

```graphql title="Mutation"
mutation deleteEventPeople($eventId: ID!, $eventPeopleIds: [ID!]!) {
  deleteEventPeople(eventId: $eventId, eventPeopleIds: $eventPeopleIds) {
    eventPeopleDeleted
  }
}
```

```json title="Variables"
{
  "eventId": "RXZlbnDY1Nc4",
  "eventPeopleIds": [
    "RXZlbnRQZW9wI5NjI3Nzg=",
    "RXZlbnRQZW9wM5NjI3ODA="
  ]
}
```
