# Contact Lists

### Contact Lists

Contact Lists let you capture a snapshot of people at a company who match specific criteria — job titles, keywords, and/or countries — using LinkedIn Sales Navigator.

**Typical workflow:**

1. `POST /v1/contacts/lists` — provide a company LinkedIn URL and at least one filter; the API runs a live Sales Navigator search and stores the results as a snapshot
2. `GET /v1/contacts/lists/{listId}/contacts` — page through the stored contacts at any time, no new Sales Navigator call needed
3. `GET /v1/contacts/lists` — list all your saved contact lists
4. `PUT /v1/contacts/lists/{listId}` — rename a list
5. `DELETE /v1/contacts/lists/{listId}` — remove a list and its contacts

**What gets stored:** Each contact in the list is stored as a point-in-time snapshot including name, role, company, location, headline, seniority, positions, avatar, and Sales Navigator profile URL. The snapshot reflects what Sales Navigator returned at creation time and is not updated automatically.

**Sales Navigator requirement:** Creating a list requires a LinkedIn Sales Navigator connection on your account. If Sales Navigator is not connected, the `POST` returns a connector error and no list is created. Reading existing lists (`GET`) works regardless of connector status.

## GET /v1/contacts/lists

> List contact lists

```json
{"openapi":"3.2.0","info":{"title":"Saber Platform API","version":"1.0.0"},"tags":[{"name":"Contact Lists","summary":"Contact Lists","kind":"nav","description":"## Contact Lists\n\nContact Lists let you capture a snapshot of people at a company who match specific criteria — job titles, keywords, and/or countries — using LinkedIn Sales Navigator.\n\n**Typical workflow:**\n1. `POST /v1/contacts/lists` — provide a company LinkedIn URL and at least one filter; the API runs a live Sales Navigator search and stores the results as a snapshot\n2. `GET /v1/contacts/lists/{listId}/contacts` — page through the stored contacts at any time, no new Sales Navigator call needed\n3. `GET /v1/contacts/lists` — list all your saved contact lists\n4. `PUT /v1/contacts/lists/{listId}` — rename a list\n5. `DELETE /v1/contacts/lists/{listId}` — remove a list and its contacts\n\n**What gets stored:**\nEach contact in the list is stored as a point-in-time snapshot including name, role, company, location, headline, seniority, positions, avatar, and Sales Navigator profile URL. The snapshot reflects what Sales Navigator returned at creation time and is not updated automatically.\n\n**Sales Navigator requirement:**\nCreating a list requires a LinkedIn Sales Navigator connection on your account. If Sales Navigator is not connected, the `POST` returns a connector error and no list is created. Reading existing lists (`GET`) works regardless of connector status.\n"}],"servers":[{"url":"https://api.saber.app","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key authentication using Bearer token. Format: sk_live_ followed by a secure random string."}},"schemas":{"ContactListsResponse":{"type":"object","description":"Paginated list of contact lists","required":["items","total","limit","offset","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ContactList"}},"total":{"type":"integer","description":"Total number of contact lists for this organization"},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}}},"ContactList":{"type":"object","description":"A contact list with metadata and stored search filters","required":["id","name","filters","contactCount","createdAt","updatedAt"],"properties":{"id":{"type":"string","description":"Unique identifier for the contact list"},"name":{"type":"string","description":"Display name for the contact list"},"filters":{"$ref":"#/components/schemas/ContactListFilters"},"contactCount":{"type":"integer","minimum":0,"description":"Number of contacts stored in this list"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ContactListFilters":{"type":"object","description":"Search filters stored on a contact list","properties":{"companyLinkedInUrls":{"type":"array","items":{"type":"string","format":"uri"},"description":"LinkedIn company URLs to scope the search. Supports multiple companies. Omit to search across all companies."},"jobTitles":{"type":"array","items":{"type":"string"},"description":"Job titles to filter contacts by"},"keywords":{"type":"string","description":"Keywords to search for in contact profiles"},"countries":{"type":"array","items":{"type":"string"},"description":"Countries to filter by (ISO 3166-1 alpha-2 codes)"}}},"ErrorResponse":{"type":"object","description":"Standard error envelope returned by every endpoint that flows through the global error handler. Note: the global rate-limit middleware (HTTP 429 from per-API-key throttling) returns a different, flat shape — see `RateLimitErrorResponse`.\n","required":["error"],"properties":{"error":{"type":"object","required":["type","code","requestId"],"properties":{"type":{"type":"string","description":"Error category. Maps 1:1 to HTTP status (e.g. VALIDATION → 422, UNAUTHORIZED → 401).","enum":["BAD_REQUEST","VALIDATION","UNPROCESSABLE_ENTITY","NOT_FOUND","CONFLICT","UNAUTHORIZED","FORBIDDEN","PAYMENT_REQUIRED","PAYLOAD_TOO_LARGE","INTERNAL","EXTERNAL","TIMEOUT"]},"code":{"type":"string","description":"Stable machine-readable error code. Safe to switch on in client code."},"message":{"type":"string","description":"Human-readable error message. Wording may change; do not match against this string."},"errorCode":{"type":"string","description":"Optional public error code propagated from a downstream service (e.g. NestJS, LinkedIn)."},"errorAction":{"type":"string","description":"Optional user action guidance (e.g. \"reconnect Sales Navigator\")."},"details":{"type":"object","additionalProperties":true,"description":"Optional structured fields forwarded from a downstream service. Shape depends on the source."},"requestId":{"type":"string","format":"uuid","description":"Correlation ID for this request. Include when reporting issues."},"fields":{"type":"array","description":"Per-field validation errors (populated when `type` is `VALIDATION` and the cause is a struct-tag validator).","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"debug":{"type":"object","description":"Debug information. Only present in development environments.","properties":{"cause":{"type":"string"}}}}}}}}},"paths":{"/v1/contacts/lists":{"get":{"summary":"List contact lists","operationId":"listContactLists","tags":["Contact Lists"],"parameters":[{"name":"limit","in":"query","description":"Maximum number of lists to return (1–100, default 20)","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","description":"Number of lists to skip for pagination (default 0)","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Contact lists retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactListsResponse"}}}},"401":{"description":"Unauthorized — invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Create a contact list

> Creates a named contact list by running a live LinkedIn Sales Navigator search for the given company and filters, then storing the results as a persistent snapshot.\
> \
> The request is synchronous — it waits for the search to complete before returning. The response includes the list metadata with an accurate \`contactCount\`.\
> \
> \*\*Requirements:\*\*\
> \- A valid company LinkedIn URL is required\
> \- At least one filter (\`jobTitles\`, \`keywords\`, or \`countries\`) must be provided\
> \- LinkedIn Sales Navigator must be connected on the API key owner's account\
> \
> \*\*Notes:\*\*\
> \- Up to \~125 contacts are captured (5 pages × 25 results per page)\
> \- Contacts are stored as a point-in-time snapshot; the list is not automatically updated when profiles change\
> \- The list and all its contacts are committed atomically — if the request fails, no partial data is stored<br>

```json
{"openapi":"3.2.0","info":{"title":"Saber Platform API","version":"1.0.0"},"tags":[{"name":"Contact Lists","summary":"Contact Lists","kind":"nav","description":"## Contact Lists\n\nContact Lists let you capture a snapshot of people at a company who match specific criteria — job titles, keywords, and/or countries — using LinkedIn Sales Navigator.\n\n**Typical workflow:**\n1. `POST /v1/contacts/lists` — provide a company LinkedIn URL and at least one filter; the API runs a live Sales Navigator search and stores the results as a snapshot\n2. `GET /v1/contacts/lists/{listId}/contacts` — page through the stored contacts at any time, no new Sales Navigator call needed\n3. `GET /v1/contacts/lists` — list all your saved contact lists\n4. `PUT /v1/contacts/lists/{listId}` — rename a list\n5. `DELETE /v1/contacts/lists/{listId}` — remove a list and its contacts\n\n**What gets stored:**\nEach contact in the list is stored as a point-in-time snapshot including name, role, company, location, headline, seniority, positions, avatar, and Sales Navigator profile URL. The snapshot reflects what Sales Navigator returned at creation time and is not updated automatically.\n\n**Sales Navigator requirement:**\nCreating a list requires a LinkedIn Sales Navigator connection on your account. If Sales Navigator is not connected, the `POST` returns a connector error and no list is created. Reading existing lists (`GET`) works regardless of connector status.\n"}],"servers":[{"url":"https://api.saber.app","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key authentication using Bearer token. Format: sk_live_ followed by a secure random string."}},"schemas":{"CreateContactListRequest":{"type":"object","description":"Request body for creating a contact list","required":["name","filters"],"properties":{"name":{"type":"string","maxLength":200,"description":"Display name for the contact list"},"filters":{"$ref":"#/components/schemas/ContactListFilters"}}},"ContactListFilters":{"type":"object","description":"Search filters stored on a contact list","properties":{"companyLinkedInUrls":{"type":"array","items":{"type":"string","format":"uri"},"description":"LinkedIn company URLs to scope the search. Supports multiple companies. Omit to search across all companies."},"jobTitles":{"type":"array","items":{"type":"string"},"description":"Job titles to filter contacts by"},"keywords":{"type":"string","description":"Keywords to search for in contact profiles"},"countries":{"type":"array","items":{"type":"string"},"description":"Countries to filter by (ISO 3166-1 alpha-2 codes)"}}},"ContactList":{"type":"object","description":"A contact list with metadata and stored search filters","required":["id","name","filters","contactCount","createdAt","updatedAt"],"properties":{"id":{"type":"string","description":"Unique identifier for the contact list"},"name":{"type":"string","description":"Display name for the contact list"},"filters":{"$ref":"#/components/schemas/ContactListFilters"},"contactCount":{"type":"integer","minimum":0,"description":"Number of contacts stored in this list"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ErrorResponse":{"type":"object","description":"Standard error envelope returned by every endpoint that flows through the global error handler. Note: the global rate-limit middleware (HTTP 429 from per-API-key throttling) returns a different, flat shape — see `RateLimitErrorResponse`.\n","required":["error"],"properties":{"error":{"type":"object","required":["type","code","requestId"],"properties":{"type":{"type":"string","description":"Error category. Maps 1:1 to HTTP status (e.g. VALIDATION → 422, UNAUTHORIZED → 401).","enum":["BAD_REQUEST","VALIDATION","UNPROCESSABLE_ENTITY","NOT_FOUND","CONFLICT","UNAUTHORIZED","FORBIDDEN","PAYMENT_REQUIRED","PAYLOAD_TOO_LARGE","INTERNAL","EXTERNAL","TIMEOUT"]},"code":{"type":"string","description":"Stable machine-readable error code. Safe to switch on in client code."},"message":{"type":"string","description":"Human-readable error message. Wording may change; do not match against this string."},"errorCode":{"type":"string","description":"Optional public error code propagated from a downstream service (e.g. NestJS, LinkedIn)."},"errorAction":{"type":"string","description":"Optional user action guidance (e.g. \"reconnect Sales Navigator\")."},"details":{"type":"object","additionalProperties":true,"description":"Optional structured fields forwarded from a downstream service. Shape depends on the source."},"requestId":{"type":"string","format":"uuid","description":"Correlation ID for this request. Include when reporting issues."},"fields":{"type":"array","description":"Per-field validation errors (populated when `type` is `VALIDATION` and the cause is a struct-tag validator).","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"debug":{"type":"object","description":"Debug information. Only present in development environments.","properties":{"cause":{"type":"string"}}}}}}}}},"paths":{"/v1/contacts/lists":{"post":{"summary":"Create a contact list","description":"Creates a named contact list by running a live LinkedIn Sales Navigator search for the given company and filters, then storing the results as a persistent snapshot.\n\nThe request is synchronous — it waits for the search to complete before returning. The response includes the list metadata with an accurate `contactCount`.\n\n**Requirements:**\n- A valid company LinkedIn URL is required\n- At least one filter (`jobTitles`, `keywords`, or `countries`) must be provided\n- LinkedIn Sales Navigator must be connected on the API key owner's account\n\n**Notes:**\n- Up to ~125 contacts are captured (5 pages × 25 results per page)\n- Contacts are stored as a point-in-time snapshot; the list is not automatically updated when profiles change\n- The list and all its contacts are committed atomically — if the request fails, no partial data is stored\n","operationId":"createContactList","tags":["Contact Lists"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactListRequest"}}}},"responses":{"201":{"description":"Contact list created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"}}}},"400":{"description":"Bad Request — missing required filter or invalid URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests — rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"504":{"description":"Gateway Timeout — Sales Navigator search exceeded the request timeout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## GET /v1/contacts/lists/{listId}

> Get a contact list by ID

```json
{"openapi":"3.2.0","info":{"title":"Saber Platform API","version":"1.0.0"},"tags":[{"name":"Contact Lists","summary":"Contact Lists","kind":"nav","description":"## Contact Lists\n\nContact Lists let you capture a snapshot of people at a company who match specific criteria — job titles, keywords, and/or countries — using LinkedIn Sales Navigator.\n\n**Typical workflow:**\n1. `POST /v1/contacts/lists` — provide a company LinkedIn URL and at least one filter; the API runs a live Sales Navigator search and stores the results as a snapshot\n2. `GET /v1/contacts/lists/{listId}/contacts` — page through the stored contacts at any time, no new Sales Navigator call needed\n3. `GET /v1/contacts/lists` — list all your saved contact lists\n4. `PUT /v1/contacts/lists/{listId}` — rename a list\n5. `DELETE /v1/contacts/lists/{listId}` — remove a list and its contacts\n\n**What gets stored:**\nEach contact in the list is stored as a point-in-time snapshot including name, role, company, location, headline, seniority, positions, avatar, and Sales Navigator profile URL. The snapshot reflects what Sales Navigator returned at creation time and is not updated automatically.\n\n**Sales Navigator requirement:**\nCreating a list requires a LinkedIn Sales Navigator connection on your account. If Sales Navigator is not connected, the `POST` returns a connector error and no list is created. Reading existing lists (`GET`) works regardless of connector status.\n"}],"servers":[{"url":"https://api.saber.app","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key authentication using Bearer token. Format: sk_live_ followed by a secure random string."}},"schemas":{"ContactList":{"type":"object","description":"A contact list with metadata and stored search filters","required":["id","name","filters","contactCount","createdAt","updatedAt"],"properties":{"id":{"type":"string","description":"Unique identifier for the contact list"},"name":{"type":"string","description":"Display name for the contact list"},"filters":{"$ref":"#/components/schemas/ContactListFilters"},"contactCount":{"type":"integer","minimum":0,"description":"Number of contacts stored in this list"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ContactListFilters":{"type":"object","description":"Search filters stored on a contact list","properties":{"companyLinkedInUrls":{"type":"array","items":{"type":"string","format":"uri"},"description":"LinkedIn company URLs to scope the search. Supports multiple companies. Omit to search across all companies."},"jobTitles":{"type":"array","items":{"type":"string"},"description":"Job titles to filter contacts by"},"keywords":{"type":"string","description":"Keywords to search for in contact profiles"},"countries":{"type":"array","items":{"type":"string"},"description":"Countries to filter by (ISO 3166-1 alpha-2 codes)"}}},"ErrorResponse":{"type":"object","description":"Standard error envelope returned by every endpoint that flows through the global error handler. Note: the global rate-limit middleware (HTTP 429 from per-API-key throttling) returns a different, flat shape — see `RateLimitErrorResponse`.\n","required":["error"],"properties":{"error":{"type":"object","required":["type","code","requestId"],"properties":{"type":{"type":"string","description":"Error category. Maps 1:1 to HTTP status (e.g. VALIDATION → 422, UNAUTHORIZED → 401).","enum":["BAD_REQUEST","VALIDATION","UNPROCESSABLE_ENTITY","NOT_FOUND","CONFLICT","UNAUTHORIZED","FORBIDDEN","PAYMENT_REQUIRED","PAYLOAD_TOO_LARGE","INTERNAL","EXTERNAL","TIMEOUT"]},"code":{"type":"string","description":"Stable machine-readable error code. Safe to switch on in client code."},"message":{"type":"string","description":"Human-readable error message. Wording may change; do not match against this string."},"errorCode":{"type":"string","description":"Optional public error code propagated from a downstream service (e.g. NestJS, LinkedIn)."},"errorAction":{"type":"string","description":"Optional user action guidance (e.g. \"reconnect Sales Navigator\")."},"details":{"type":"object","additionalProperties":true,"description":"Optional structured fields forwarded from a downstream service. Shape depends on the source."},"requestId":{"type":"string","format":"uuid","description":"Correlation ID for this request. Include when reporting issues."},"fields":{"type":"array","description":"Per-field validation errors (populated when `type` is `VALIDATION` and the cause is a struct-tag validator).","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"debug":{"type":"object","description":"Debug information. Only present in development environments.","properties":{"cause":{"type":"string"}}}}}}}}},"paths":{"/v1/contacts/lists/{listId}":{"get":{"summary":"Get a contact list by ID","operationId":"getContactList","tags":["Contact Lists"],"parameters":[{"name":"listId","in":"path","required":true,"description":"The unique identifier of the contact list","schema":{"type":"string"}}],"responses":{"200":{"description":"Contact list retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"}}}},"401":{"description":"Unauthorized — invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Contact list not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## PUT /v1/contacts/lists/{listId}

> Rename a contact list

```json
{"openapi":"3.2.0","info":{"title":"Saber Platform API","version":"1.0.0"},"tags":[{"name":"Contact Lists","summary":"Contact Lists","kind":"nav","description":"## Contact Lists\n\nContact Lists let you capture a snapshot of people at a company who match specific criteria — job titles, keywords, and/or countries — using LinkedIn Sales Navigator.\n\n**Typical workflow:**\n1. `POST /v1/contacts/lists` — provide a company LinkedIn URL and at least one filter; the API runs a live Sales Navigator search and stores the results as a snapshot\n2. `GET /v1/contacts/lists/{listId}/contacts` — page through the stored contacts at any time, no new Sales Navigator call needed\n3. `GET /v1/contacts/lists` — list all your saved contact lists\n4. `PUT /v1/contacts/lists/{listId}` — rename a list\n5. `DELETE /v1/contacts/lists/{listId}` — remove a list and its contacts\n\n**What gets stored:**\nEach contact in the list is stored as a point-in-time snapshot including name, role, company, location, headline, seniority, positions, avatar, and Sales Navigator profile URL. The snapshot reflects what Sales Navigator returned at creation time and is not updated automatically.\n\n**Sales Navigator requirement:**\nCreating a list requires a LinkedIn Sales Navigator connection on your account. If Sales Navigator is not connected, the `POST` returns a connector error and no list is created. Reading existing lists (`GET`) works regardless of connector status.\n"}],"servers":[{"url":"https://api.saber.app","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key authentication using Bearer token. Format: sk_live_ followed by a secure random string."}},"schemas":{"UpdateContactListRequest":{"type":"object","description":"Request body for renaming a contact list","required":["name"],"properties":{"name":{"type":"string","maxLength":200,"description":"New display name for the contact list"}}},"ContactList":{"type":"object","description":"A contact list with metadata and stored search filters","required":["id","name","filters","contactCount","createdAt","updatedAt"],"properties":{"id":{"type":"string","description":"Unique identifier for the contact list"},"name":{"type":"string","description":"Display name for the contact list"},"filters":{"$ref":"#/components/schemas/ContactListFilters"},"contactCount":{"type":"integer","minimum":0,"description":"Number of contacts stored in this list"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ContactListFilters":{"type":"object","description":"Search filters stored on a contact list","properties":{"companyLinkedInUrls":{"type":"array","items":{"type":"string","format":"uri"},"description":"LinkedIn company URLs to scope the search. Supports multiple companies. Omit to search across all companies."},"jobTitles":{"type":"array","items":{"type":"string"},"description":"Job titles to filter contacts by"},"keywords":{"type":"string","description":"Keywords to search for in contact profiles"},"countries":{"type":"array","items":{"type":"string"},"description":"Countries to filter by (ISO 3166-1 alpha-2 codes)"}}},"ErrorResponse":{"type":"object","description":"Standard error envelope returned by every endpoint that flows through the global error handler. Note: the global rate-limit middleware (HTTP 429 from per-API-key throttling) returns a different, flat shape — see `RateLimitErrorResponse`.\n","required":["error"],"properties":{"error":{"type":"object","required":["type","code","requestId"],"properties":{"type":{"type":"string","description":"Error category. Maps 1:1 to HTTP status (e.g. VALIDATION → 422, UNAUTHORIZED → 401).","enum":["BAD_REQUEST","VALIDATION","UNPROCESSABLE_ENTITY","NOT_FOUND","CONFLICT","UNAUTHORIZED","FORBIDDEN","PAYMENT_REQUIRED","PAYLOAD_TOO_LARGE","INTERNAL","EXTERNAL","TIMEOUT"]},"code":{"type":"string","description":"Stable machine-readable error code. Safe to switch on in client code."},"message":{"type":"string","description":"Human-readable error message. Wording may change; do not match against this string."},"errorCode":{"type":"string","description":"Optional public error code propagated from a downstream service (e.g. NestJS, LinkedIn)."},"errorAction":{"type":"string","description":"Optional user action guidance (e.g. \"reconnect Sales Navigator\")."},"details":{"type":"object","additionalProperties":true,"description":"Optional structured fields forwarded from a downstream service. Shape depends on the source."},"requestId":{"type":"string","format":"uuid","description":"Correlation ID for this request. Include when reporting issues."},"fields":{"type":"array","description":"Per-field validation errors (populated when `type` is `VALIDATION` and the cause is a struct-tag validator).","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"debug":{"type":"object","description":"Debug information. Only present in development environments.","properties":{"cause":{"type":"string"}}}}}}}}},"paths":{"/v1/contacts/lists/{listId}":{"put":{"summary":"Rename a contact list","operationId":"updateContactList","tags":["Contact Lists"],"parameters":[{"name":"listId","in":"path","required":true,"description":"The unique identifier of the contact list","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactListRequest"}}}},"responses":{"200":{"description":"Contact list updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"}}}},"400":{"description":"Bad Request — invalid name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Contact list not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Delete a contact list and all its stored contacts

> Permanently deletes the contact list and all its stored contact snapshots.<br>

```json
{"openapi":"3.2.0","info":{"title":"Saber Platform API","version":"1.0.0"},"tags":[{"name":"Contact Lists","summary":"Contact Lists","kind":"nav","description":"## Contact Lists\n\nContact Lists let you capture a snapshot of people at a company who match specific criteria — job titles, keywords, and/or countries — using LinkedIn Sales Navigator.\n\n**Typical workflow:**\n1. `POST /v1/contacts/lists` — provide a company LinkedIn URL and at least one filter; the API runs a live Sales Navigator search and stores the results as a snapshot\n2. `GET /v1/contacts/lists/{listId}/contacts` — page through the stored contacts at any time, no new Sales Navigator call needed\n3. `GET /v1/contacts/lists` — list all your saved contact lists\n4. `PUT /v1/contacts/lists/{listId}` — rename a list\n5. `DELETE /v1/contacts/lists/{listId}` — remove a list and its contacts\n\n**What gets stored:**\nEach contact in the list is stored as a point-in-time snapshot including name, role, company, location, headline, seniority, positions, avatar, and Sales Navigator profile URL. The snapshot reflects what Sales Navigator returned at creation time and is not updated automatically.\n\n**Sales Navigator requirement:**\nCreating a list requires a LinkedIn Sales Navigator connection on your account. If Sales Navigator is not connected, the `POST` returns a connector error and no list is created. Reading existing lists (`GET`) works regardless of connector status.\n"}],"servers":[{"url":"https://api.saber.app","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key authentication using Bearer token. Format: sk_live_ followed by a secure random string."}},"schemas":{"ErrorResponse":{"type":"object","description":"Standard error envelope returned by every endpoint that flows through the global error handler. Note: the global rate-limit middleware (HTTP 429 from per-API-key throttling) returns a different, flat shape — see `RateLimitErrorResponse`.\n","required":["error"],"properties":{"error":{"type":"object","required":["type","code","requestId"],"properties":{"type":{"type":"string","description":"Error category. Maps 1:1 to HTTP status (e.g. VALIDATION → 422, UNAUTHORIZED → 401).","enum":["BAD_REQUEST","VALIDATION","UNPROCESSABLE_ENTITY","NOT_FOUND","CONFLICT","UNAUTHORIZED","FORBIDDEN","PAYMENT_REQUIRED","PAYLOAD_TOO_LARGE","INTERNAL","EXTERNAL","TIMEOUT"]},"code":{"type":"string","description":"Stable machine-readable error code. Safe to switch on in client code."},"message":{"type":"string","description":"Human-readable error message. Wording may change; do not match against this string."},"errorCode":{"type":"string","description":"Optional public error code propagated from a downstream service (e.g. NestJS, LinkedIn)."},"errorAction":{"type":"string","description":"Optional user action guidance (e.g. \"reconnect Sales Navigator\")."},"details":{"type":"object","additionalProperties":true,"description":"Optional structured fields forwarded from a downstream service. Shape depends on the source."},"requestId":{"type":"string","format":"uuid","description":"Correlation ID for this request. Include when reporting issues."},"fields":{"type":"array","description":"Per-field validation errors (populated when `type` is `VALIDATION` and the cause is a struct-tag validator).","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"debug":{"type":"object","description":"Debug information. Only present in development environments.","properties":{"cause":{"type":"string"}}}}}}}}},"paths":{"/v1/contacts/lists/{listId}":{"delete":{"summary":"Delete a contact list and all its stored contacts","description":"Permanently deletes the contact list and all its stored contact snapshots.\n","operationId":"deleteContactList","tags":["Contact Lists"],"parameters":[{"name":"listId","in":"path","required":true,"description":"The unique identifier of the contact list","schema":{"type":"string"}}],"responses":{"204":{"description":"Contact list deleted successfully"},"401":{"description":"Unauthorized — invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Contact list not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get contacts in a contact list

> Returns the stored contact snapshot for the given list, paginated. Reads directly from the database — no Sales Navigator API call is made, so this is always fast and does not consume credits.\
> \
> Contacts are returned in the order they were stored at list creation time.<br>

```json
{"openapi":"3.2.0","info":{"title":"Saber Platform API","version":"1.0.0"},"tags":[{"name":"Contact Lists","summary":"Contact Lists","kind":"nav","description":"## Contact Lists\n\nContact Lists let you capture a snapshot of people at a company who match specific criteria — job titles, keywords, and/or countries — using LinkedIn Sales Navigator.\n\n**Typical workflow:**\n1. `POST /v1/contacts/lists` — provide a company LinkedIn URL and at least one filter; the API runs a live Sales Navigator search and stores the results as a snapshot\n2. `GET /v1/contacts/lists/{listId}/contacts` — page through the stored contacts at any time, no new Sales Navigator call needed\n3. `GET /v1/contacts/lists` — list all your saved contact lists\n4. `PUT /v1/contacts/lists/{listId}` — rename a list\n5. `DELETE /v1/contacts/lists/{listId}` — remove a list and its contacts\n\n**What gets stored:**\nEach contact in the list is stored as a point-in-time snapshot including name, role, company, location, headline, seniority, positions, avatar, and Sales Navigator profile URL. The snapshot reflects what Sales Navigator returned at creation time and is not updated automatically.\n\n**Sales Navigator requirement:**\nCreating a list requires a LinkedIn Sales Navigator connection on your account. If Sales Navigator is not connected, the `POST` returns a connector error and no list is created. Reading existing lists (`GET`) works regardless of connector status.\n"}],"servers":[{"url":"https://api.saber.app","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key authentication using Bearer token. Format: sk_live_ followed by a secure random string."}},"schemas":{"ContactListContactsResponse":{"type":"object","description":"Paginated list of contacts within a contact list","required":["items","total","limit","offset","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ContactListItem"}},"total":{"type":"integer","description":"Total number of contacts in this list"},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}}},"ContactListItem":{"type":"object","description":"Point-in-time snapshot of a contact's data as returned by Sales Navigator at list creation","required":["id","listId","baseContactId","createdAt"],"properties":{"id":{"type":"string","description":"Unique identifier for this list item"},"listId":{"type":"string","description":"ID of the parent contact list"},"baseContactId":{"type":"string","description":"ID of the underlying base_contacts identity record"},"firstName":{"type":"string"},"lastName":{"type":"string"},"fullName":{"type":"string"},"headline":{"type":"string","description":"LinkedIn headline"},"role":{"type":"string","description":"Current job title (from the contact's most recent position)"},"companyName":{"type":"string","description":"Current company name (from the contact's most recent position)"},"location":{"type":"string"},"avatar":{"type":"string","format":"uri","description":"URL to the contact's profile photo"},"seniority":{"type":"array","items":{"type":"string"},"description":"Seniority levels assigned by Sales Navigator (e.g. MANAGER, DIRECTOR, VP)"},"positions":{"type":"array","description":"Full position history returned by Sales Navigator","items":{"type":"object","properties":{"title":{"type":"string"},"companyName":{"type":"string"},"companyUrl":{"type":"string","format":"uri"},"tenureInMonths":{"type":"integer"},"location":{"type":"string"}}}},"linkedInSalesNavigatorProfileUrl":{"type":"string","format":"uri","description":"Direct link to the contact's Sales Navigator profile"},"createdAt":{"type":"string","format":"date-time"}}},"ErrorResponse":{"type":"object","description":"Standard error envelope returned by every endpoint that flows through the global error handler. Note: the global rate-limit middleware (HTTP 429 from per-API-key throttling) returns a different, flat shape — see `RateLimitErrorResponse`.\n","required":["error"],"properties":{"error":{"type":"object","required":["type","code","requestId"],"properties":{"type":{"type":"string","description":"Error category. Maps 1:1 to HTTP status (e.g. VALIDATION → 422, UNAUTHORIZED → 401).","enum":["BAD_REQUEST","VALIDATION","UNPROCESSABLE_ENTITY","NOT_FOUND","CONFLICT","UNAUTHORIZED","FORBIDDEN","PAYMENT_REQUIRED","PAYLOAD_TOO_LARGE","INTERNAL","EXTERNAL","TIMEOUT"]},"code":{"type":"string","description":"Stable machine-readable error code. Safe to switch on in client code."},"message":{"type":"string","description":"Human-readable error message. Wording may change; do not match against this string."},"errorCode":{"type":"string","description":"Optional public error code propagated from a downstream service (e.g. NestJS, LinkedIn)."},"errorAction":{"type":"string","description":"Optional user action guidance (e.g. \"reconnect Sales Navigator\")."},"details":{"type":"object","additionalProperties":true,"description":"Optional structured fields forwarded from a downstream service. Shape depends on the source."},"requestId":{"type":"string","format":"uuid","description":"Correlation ID for this request. Include when reporting issues."},"fields":{"type":"array","description":"Per-field validation errors (populated when `type` is `VALIDATION` and the cause is a struct-tag validator).","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"debug":{"type":"object","description":"Debug information. Only present in development environments.","properties":{"cause":{"type":"string"}}}}}}}}},"paths":{"/v1/contacts/lists/{listId}/contacts":{"get":{"summary":"Get contacts in a contact list","description":"Returns the stored contact snapshot for the given list, paginated. Reads directly from the database — no Sales Navigator API call is made, so this is always fast and does not consume credits.\n\nContacts are returned in the order they were stored at list creation time.\n","operationId":"getContactListContacts","tags":["Contact Lists"],"parameters":[{"name":"listId","in":"path","required":true,"description":"The unique identifier of the contact list","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of contacts to return (1–100, default 25)","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"offset","in":"query","description":"Number of contacts to skip for pagination (default 0)","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Contacts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactListContactsResponse"}}}},"401":{"description":"Unauthorized — invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Contact list not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.saber.app/contact-lists.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
