# Contacts Create, read, update, and delete contacts in your team's books. These are the core endpoints of the RelayBook API. All contact endpoints require the `Authorization` header. Most also require the `X-Book-ID` header to specify which book to operate on. --- ## List Contacts Retrieve a paginated list of contacts from a book. ``` GET /api/v1/contacts ``` ### Headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | `Bearer rlb_your_key` | | `X-Book-ID` | Yes | UUID of the book | ### Query Parameters | Parameter | Type | Default | Max | Description | |-----------|------|---------|-----|-------------| | `limit` | integer | 50 | 200 | Number of contacts to return | | `offset` | integer | 0 | — | Number of contacts to skip | ### Example Request ```bash curl -X GET "https://app.relaybook.io/api/v1/contacts?limit=10&offset=0" \ -H "Authorization: Bearer rlb_your_key" \ -H "X-Book-ID: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" ``` ### Response ``` HTTP/1.1 200 OK ``` ```json { "data": [ { "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "book_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "first_name": "Jane", "last_name": "Cooper", "company": "Acme Corp", "job_title": "Head of Partnerships", "emails": [ { "address": "[email protected]", "label": "work", "primary": true }, { "address": "[email protected]", "label": "personal" } ], "phones": [ { "number": "+1 555-0123", "label": "mobile", "primary": true } ], "custom_fields": null, "notes": "", "photo_url": null, "starred": true, "birthday": "1990-03-15", "website": "https://acme.com", "addresses": [ { "label": "office", "street": "123 Main St", "city": "San Francisco", "state": "CA", "zip": "94105", "country": "US" } ], "dates": [], "socials": [ { "label": "linkedin", "value": "https://linkedin.com/in/janecooper" } ], "relationships": [], "created_by": "5e1c820d-b605-4f9e-ae4f-47be164176ca", "created_at": "2026-01-15T09:30:00Z", "updated_at": "2026-02-10T14:22:00Z" } ], "meta": { "page": 1, "limit": 10, "total": 47 } } ``` ### Errors | Status | Code | Cause | |--------|------|-------| | 400 | `MISSING_BOOK` | `X-Book-ID` header is missing | | 403 | `FORBIDDEN` | Book doesn't belong to your team | | 500 | `SERVER_ERROR` | Database error | --- ## Get Contact Retrieve a single contact by its ID. ``` GET /api/v1/contacts/{id} ``` ### Path Parameters | Parameter | Type | Description | |-----------|------|-------------| | `id` | UUID | The contact's unique ID | ### Headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | `Bearer rlb_your_key` | ### Example Request ```bash curl -X GET "https://app.relaybook.io/api/v1/contacts/f47ac10b-58cc-4372-a567-0e02b2c3d479" \ -H "Authorization: Bearer rlb_your_key" ``` ### Response ``` HTTP/1.1 200 OK ``` ```json { "data": { "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "book_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "first_name": "Jane", "last_name": "Cooper", "company": "Acme Corp", "job_title": "Head of Partnerships", "emails": [ { "address": "[email protected]", "label": "work", "primary": true } ], "phones": [ { "number": "+1 555-0123", "label": "mobile", "primary": true } ], "custom_fields": null, "notes": "Met at SaaStr 2025. Interested in partnership.", "photo_url": null, "starred": true, "birthday": "1990-03-15", "website": "https://acme.com", "addresses": [], "dates": [], "socials": [], "relationships": [], "created_by": "5e1c820d-b605-4f9e-ae4f-47be164176ca", "created_at": "2026-01-15T09:30:00Z", "updated_at": "2026-02-10T14:22:00Z" } } ``` ### Errors | Status | Code | Cause | |--------|------|-------| | 404 | `NOT_FOUND` | Contact doesn't exist or doesn't belong to your team | --- ## Create Contact Add a new contact to a book. ``` POST /api/v1/contacts ``` ### Headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | `Bearer rlb_your_key` | | `Content-Type` | Yes | `application/json` | | `X-Book-ID` | Yes | UUID of the book to add the contact to | ### Request Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `first_name` | string | Conditional | Contact's first name | | `last_name` | string | Conditional | Contact's last name | | `company` | string | Conditional | Company or organization | | `job_title` | string | No | Role or position | | `emails` | array | No | Email addresses (see format below) | | `phones` | array | No | Phone numbers (see format below) | | `notes` | string | No | Free-text notes | | `birthday` | string | No | Date in `YYYY-MM-DD` format | | `website` | string | No | URL | | `addresses` | array | No | Postal addresses (see format below) | | `socials` | array | No | Social media profiles (see format below) | > [!note] Required fields > At least one of `first_name`, `last_name`, or `company` must be provided. A contact needs a name or company to be identifiable. > [!warning] Custom fields, labels, and photo_url > The create endpoint does not accept `custom_fields`, `labels`, or `photo_url`. To set these after creating a contact: > - **Custom fields**: Use [[Bulk Operations#Bulk Update Custom Field]] with the returned contact `id` > - **Labels**: Use `POST /api/v1/contacts/{id}/labels` (see [[Books & Labels]]) > - **photo_url**: Not currently supported via API ### Array Field Formats **Emails:** ```json [ { "address": "[email protected]", "label": "work", "primary": true }, { "address": "[email protected]", "label": "personal" } ] ``` Supported email labels: `work`, `personal`, `other` **Phones:** ```json [ { "number": "+1 555-0123", "label": "mobile", "primary": true }, { "number": "+1 555-0456", "label": "work" } ] ``` Supported phone labels: `mobile`, `work`, `other` **Addresses:** ```json [ { "label": "work", "street": "123 Main St", "city": "San Francisco", "state": "CA", "zip": "94105", "country": "US" } ] ``` Supported address labels: `home`, `work`, `other` **Social profiles:** ```json [ { "label": "linkedin", "value": "https://linkedin.com/in/janecooper" }, { "label": "x", "value": "https://x.com/janecooper" }, { "label": "facebook", "value": "https://facebook.com/janecooper" }, { "label": "instagram", "value": "https://instagram.com/janecooper" } ] ``` **Supported label values:** | Label | Display Name | | ----------- | ------------ | | `linkedin` | LinkedIn | | `x` | X | | `instagram` | Instagram | | `facebook` | Facebook | | `github` | GitHub | | `youtube` | YouTube | | `other` | Other | Only include entries that have a non-empty value - omit any social platform with no data. ### Example Request ```bash curl -X POST "https://app.relaybook.io/api/v1/contacts" \ -H "Authorization: Bearer rlb_your_key" \ -H "Content-Type: application/json" \ -H "X-Book-ID: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \ -d '{ "first_name": "Marcus", "last_name": "Chen", "company": "Bright Studios", "job_title": "Creative Director", "emails": [ { "address": "[email protected]", "label": "work", "primary": true } ], "phones": [ { "number": "+1 555-0456", "label": "mobile", "primary": true } ], "notes": "Referred by Jane Cooper", "website": "https://brightstudios.com" }' ``` ### Response ``` HTTP/1.1 201 Created ``` ```json { "data": { "id": "b23dc4e5-6789-4abc-def0-123456789abc", "book_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "first_name": "Marcus", "last_name": "Chen", "company": "Bright Studios", "job_title": "Creative Director", "emails": [ { "address": "[email protected]", "label": "work", "primary": true } ], "phones": [ { "number": "+1 555-0456", "label": "mobile", "primary": true } ], "custom_fields": null, "notes": "Referred by Jane Cooper", "photo_url": null, "starred": false, "birthday": null, "website": "https://brightstudios.com", "addresses": [], "dates": [], "socials": [], "relationships": [], "created_by": "5e1c820d-b605-4f9e-ae4f-47be164176ca", "created_at": "2026-02-18T16:52:56Z", "updated_at": "2026-02-18T16:52:56Z" } } ``` > [!tip] Webhook event > Creating a contact fires a `contact.created` [[Webhooks|webhook event]] if webhooks are configured for your team. ### Errors | Status | Code | Cause | |--------|------|-------| | 400 | `MISSING_BOOK` | `X-Book-ID` header is missing | | 400 | `INVALID_INPUT` | Request body is not valid JSON | | 403 | `FORBIDDEN` | Book doesn't belong to your team | | 422 | `VALIDATION_ERROR` | Missing required fields (name or company) | | 500 | `SERVER_ERROR` | Database error | --- ## Update Contact Update one or more fields on an existing contact. Only include the fields you want to change — omitted fields are left unchanged. ``` PATCH /api/v1/contacts/{id} ``` ### Path Parameters | Parameter | Type | Description | |-----------|------|-------------| | `id` | UUID | The contact's unique ID | ### Headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | `Bearer rlb_your_key` | | `Content-Type` | Yes | `application/json` | ### Request Body All fields are optional. Only provided fields are updated. | Field | Type | Description | |-------|------|-------------| | `first_name` | string | Contact's first name | | `last_name` | string | Contact's last name | | `company` | string | Company or organization | | `job_title` | string | Role or position | | `emails` | array | Replaces all email addresses | | `phones` | array | Replaces all phone numbers | | `notes` | string | Free-text notes | | `birthday` | string or null | Date (`YYYY-MM-DD`) or `null` to clear | | `website` | string | URL | | `addresses` | array | Replaces all addresses | | `socials` | array | Replaces all social profiles | | `starred` | boolean | Star or unstar the contact | > [!note] Array fields are replaced, not merged > When you update `emails`, `phones`, `addresses`, or `socials`, the entire array is replaced. Include all values you want to keep, not just the new ones. ### Example Request ```bash curl -X PATCH "https://app.relaybook.io/api/v1/contacts/f47ac10b-58cc-4372-a567-0e02b2c3d479" \ -H "Authorization: Bearer rlb_your_key" \ -H "Content-Type: application/json" \ -d '{ "company": "Acme Global", "job_title": "VP of Partnerships", "starred": true }' ``` ### Response ``` HTTP/1.1 200 OK ``` ```json { "data": { "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "book_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "first_name": "Jane", "last_name": "Cooper", "company": "Acme Global", "job_title": "VP of Partnerships", "emails": [ { "address": "[email protected]", "label": "work", "primary": true } ], "phones": [ { "number": "+1 555-0123", "label": "mobile", "primary": true } ], "custom_fields": null, "notes": "Met at SaaStr 2025. Interested in partnership.", "photo_url": null, "starred": true, "birthday": "1990-03-15", "website": "https://acme.com", "addresses": [], "dates": [], "socials": [], "relationships": [], "created_by": "5e1c820d-b605-4f9e-ae4f-47be164176ca", "created_at": "2026-01-15T09:30:00Z", "updated_at": "2026-02-18T17:05:00Z" } } ``` > [!tip] Webhook event > Updating a contact fires a `contact.updated` [[Webhooks|webhook event]] with the full updated contact in the payload. ### Errors | Status | Code | Cause | |--------|------|-------| | 400 | `INVALID_INPUT` | Request body is not valid JSON | | 404 | `NOT_FOUND` | Contact doesn't exist or doesn't belong to your team | | 500 | `SERVER_ERROR` | Database error | --- ## Delete Contact Permanently remove a contact from a book. ``` DELETE /api/v1/contacts/{id} ``` ### Path Parameters | Parameter | Type | Description | |-----------|------|-------------| | `id` | UUID | The contact's unique ID | ### Headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | `Bearer rlb_your_key` | ### Example Request ```bash curl -X DELETE "https://app.relaybook.io/api/v1/contacts/f47ac10b-58cc-4372-a567-0e02b2c3d479" \ -H "Authorization: Bearer rlb_your_key" ``` ### Response ``` HTTP/1.1 204 No Content ``` No response body is returned. > [!tip] Webhook event > Deleting a contact fires a `contact.deleted` [[Webhooks|webhook event]]. The payload contains the contact's `id` since the full record is no longer available. ### Errors | Status | Code | Cause | |--------|------|-------| | 404 | `NOT_FOUND` | Contact doesn't exist or doesn't belong to your team | | 500 | `SERVER_ERROR` | Database error | --- ## Contact Object The full contact object returned by the API: | Field | Type | Description | |-------|------|-------------| | `id` | UUID | Unique contact identifier | | `book_id` | UUID | The book this contact belongs to | | `first_name` | string | First/given name | | `last_name` | string | Last/family name | | `company` | string | Company or organization | | `job_title` | string | Role or position | | `emails` | array | List of `{ address, label, primary }` objects | | `phones` | array | List of `{ number, label, primary }` objects | | `custom_fields` | object or null | Custom key-value data | | `notes` | string | Free-text notes | | `photo_url` | string or null | URL to the contact's photo | | `starred` | boolean | Whether the contact is starred | | `birthday` | string or null | Date in `YYYY-MM-DD` format | | `website` | string | URL to the contact's website | | `addresses` | array | List of structured address objects | | `dates` | array | List of `{ label, value }` date objects | | `socials` | array | List of `{ label, value }` social profiles | | `relationships` | array | List of relationship objects | | `created_by` | UUID or empty | User ID of the contact creator | | `created_at` | timestamp | When the contact was created | | `updated_at` | timestamp | When the contact was last modified | --- **Next:** Work with [[Books & Labels]] to manage books and organize contacts with labels.