# How Agent Account contacts work

Source: https://developer.nylas.com/docs/v3/agent-accounts/contacts/

Every Agent Account comes with its own contact store, the same address book surface that connected grants use. The agent reads, creates, updates, and deletes contacts through the standard [Contacts API](/docs/reference/api/contacts/) at `/v3/grants/{grant_id}/contacts`, with no extra setup beyond the `grant_id` you already have.

This page covers how contacts work on an Agent Account: where records live, how to list and filter them, how writes fire webhooks, and which parts of the Contacts API don't apply to this provider. For the complete endpoint list, see [Supported endpoints](/docs/v3/agent-accounts/supported-endpoints/#contacts).

## The contact list at a glance

An Agent Account's contacts live in a Nylas-hosted address book tied to the grant. You reach them through the same [Contacts](/docs/reference/api/contacts/) endpoints as any other grant, at `/v3/grants/{grant_id}/contacts`. The list endpoint filters by 3 fields, `email`, `phone_number`, and `source`, and every write fires a contact webhook.

- **A grant-scoped address book.** Contacts belong to the Agent Account, whether the agent creates them or captures them from inbound mail it processes.
- **Standard CRUD.** List, create, fetch, update, and delete run against `/v3/grants/{grant_id}/contacts` exactly as they do for connected grants.
- **Contact webhooks.** [`contact.updated`](/docs/reference/notifications/contacts/contact-updated/) fires on create and update, and [`contact.deleted`](/docs/reference/notifications/contacts/contact-deleted/) fires on delete, so the agent reacts without polling.

## Listing and filtering contacts

List the address book with [`GET /v3/grants/{grant_id}/contacts`](/docs/reference/api/contacts/list-contact/). Narrow the results with 3 fields, the `email`, `phone_number`, and `source` query parameters, and page through them with `limit` and `page_token`. The response uses the same contact schema connected grants return, so existing code paths work unchanged.

The request below lists up to 50 contacts and filters by a sender's address, which is how an agent checks whether it already has a record for someone who just emailed. Pass the `page_token` from each response to fetch the next page.

```bash
curl --request GET \
  --url "https://api.us.nylas.com/v3/grants/<GRANT_ID>/contacts?limit=50&email=alice@example.com" \
  --header "Authorization: Bearer <NYLAS_API_KEY>"
```

## Creating and updating contacts

Create a contact with [`POST /v3/grants/{grant_id}/contacts`](/docs/reference/api/contacts/post-contact/) and update one with [`PUT /v3/grants/{grant_id}/contacts/{contact_id}`](/docs/reference/api/contacts/put-contact/). Both accept the same body, so an agent can capture a new lead or revise an existing record with 1 request each. A successful write fires the `contact.updated` webhook.

The request below creates a contact from details an agent pulled out of an inbound message. The API stores structured fields like `given_name`, `surname`, `emails`, and `phone_numbers`, and returns the new record's `id` for later updates.

```bash
curl --request POST \
  --url "https://api.us.nylas.com/v3/grants/<GRANT_ID>/contacts" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "given_name": "Alice",
    "surname": "Nguyen",
    "emails": [{ "type": "work", "email": "alice@example.com" }]
  }'
```

To update, send a `PUT` to the same path with the `contact_id` and the fields you want to change. Like create, it fires `contact.updated`, so a downstream listener sees the new state without re-fetching the record.

## Reacting to contact changes

Subscribe to 2 events to track the address book in near real time: [`contact.updated`](/docs/reference/notifications/contacts/contact-updated/) fires on every create and update, and [`contact.deleted`](/docs/reference/notifications/contacts/contact-deleted/) fires on delete. The payloads match the contact webhooks for any other grant, so a single handler works across connected accounts and Agent Accounts.

This is the same pattern the agent uses for mail and calendar: drive logic off the webhook instead of polling. An agent that files every new correspondent as a contact, for example, can listen for `message.created`, create the contact, and confirm the write through the `contact.updated` event that follows.

## Keep in mind

- **No contact groups.** Agent Accounts don't implement the `/contacts/groups` resource, so group operations return an error. Plain contact records still support create, read, update, and delete.
- **No provider-specific search.** Because the account runs on Nylas-hosted infrastructure, the `email`, `phone_number`, and `source` query parameters are the only search surface. There's no Gmail-style native query.
- **Contacts and mail share the grant.** Each contact write counts as 1 request against your plan's rate limits, and the same `grant_id` reads the mailbox, calendar, and contacts together.

## What's next

- [How Agent Account mailboxes work](/docs/v3/agent-accounts/mailboxes/) for how inbound mail reaches the agent, the source of most new contacts
- [How Agent Account calendars work](/docs/v3/agent-accounts/calendars/) for events and RSVPs on the same grant
- [Supported endpoints](/docs/v3/agent-accounts/supported-endpoints/#contacts) for the full list of Contacts endpoints and webhooks that work with Agent Account grants
- [Contacts API reference](/docs/reference/api/contacts/) for request and response schemas on list, create, update, and delete