> ## Documentation Index
> Fetch the complete documentation index at: https://docs.salesfinity.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Build on Salesfinity

> Get an API key, make your first call in five minutes, and pick the right way to connect your systems and AI tools to Salesfinity.

export const Status = ({kind = "early-access", children}) => {
  const labels = {
    "early-access": "Early access",
    "coming-soon": "Coming soon",
    beta: "Beta"
  };
  const key = labels[kind] ? kind : "early-access";
  return <span className={`sf-status sf-status-${key}`}>{children || labels[key]}</span>;
};

export const Cover = ({title, eyebrow, description, img, alt = ""}) => <div className="sf-cover not-prose">
    {img ? <img className="sf-cover-img" src={img} alt={alt} loading="eager" decoding="async" /> : null}
    <div className="sf-cover-shade" aria-hidden="true" />
    <div className="sf-cover-text">
      {eyebrow ? <div className="sf-cover-eyebrow">{eyebrow}</div> : null}
      {title ? <div className="sf-cover-title">{title}</div> : null}
      {description ? <div className="sf-cover-desc">{description}</div> : null}
    </div>
  </div>;

<Cover eyebrow="Developers" title="Build on Salesfinity." description="Lists, calls, sequences and enrichment, over a REST API and an MCP server." img="https://mintcdn.com/salesfinity/YBsYR5N3Fg_u90-H/images/covers/developers.jpg?fit=max&auto=format&n=YBsYR5N3Fg_u90-H&q=85&s=e7bd1257c2799372eb48f7c5a1043339" width="1600" height="560" data-path="images/covers/developers.jpg" />

Connect Salesfinity to your own systems: push lists in, pull call outcomes out, and run sequences
from your code. Your first call takes about five minutes and needs only an API key.

If you want an AI assistant to do the work instead of writing code, use the
[MCP server](/mcp/overview). It gives Claude and other assistants the same abilities as the API.

## Choose how you connect

<CardGroup cols={3}>
  <Card title="REST API" icon="code" href="/api-reference/introduction">
    JSON over HTTPS. Best for backend jobs, data sync and your own product.
  </Card>

  <Card title="MCP server" icon="bolt" href="/mcp/overview">
    Ask Claude or another assistant to read and change your Salesfinity data.
  </Card>

  <Card title="OpenAPI description" icon="file-code" href="/api-reference/openapi.json">
    Every operation, typed. Generate a client or feed it to your tools.
  </Card>
</CardGroup>

## Quickstart: make your first call

<Steps>
  <Step title="Get an API key">
    1. In Salesfinity, open
       [Settings → Connections](https://web.salesfinity.co/dashboard/settings?tab=connections), then
       the **API & Webhooks** tab.
    2. Click **Create New API Key**.
    3. Copy the key and store it in your secret manager. Treat it like a password: the dashboard
       shows it only once. If you lose it, create a new one.

    A key belongs to **one team**. Every request made with it sees only that team's lists, calls
    and analytics. There is no account-wide key, so an integration that serves several teams
    needs one key per team.
  </Step>

  <Step title="Make your first call">
    Every request sends the key in the `x-api-key` header. The cheapest way to test a key is to
    read the team it belongs to.

    <CodeGroup>
      ```bash cURL theme={"system"}
      curl https://client-api.salesfinity.co/v1/team \
        --header 'x-api-key: YOUR_API_KEY'
      ```

      ```js Node.js theme={"system"}
      const res = await fetch("https://client-api.salesfinity.co/v1/team", {
        headers: { "x-api-key": process.env.SALESFINITY_API_KEY },
      });

      if (!res.ok) {
        // Errors are always JSON, never an HTML page.
        const { message, error, statusCode, request_id } = await res.json();
        throw new Error(`Salesfinity ${statusCode} ${error}: ${message} (request ${request_id})`);
      }

      // The team is under `data`; its members' user IDs are what writes take as `user_id`.
      const { data: team } = await res.json();
      ```

      ```python Python theme={"system"}
      import os, requests

      res = requests.get(
          "https://client-api.salesfinity.co/v1/team",
          headers={"x-api-key": os.environ["SALESFINITY_API_KEY"]},
          timeout=30,
      )

      if not res.ok:
          body = res.json()
          raise RuntimeError(
              f"Salesfinity {body['statusCode']} {body['error']}: {body['message']}"
              f" (request {body['request_id']})"
          )

      # The team is under "data"; its members' user IDs are what writes take as user_id.
      team = res.json()["data"]
      ```
    </CodeGroup>
  </Step>

  <Step title="Check the response">
    A working key returns your team under `data`, with each member's user record. Keep the member
    `user._id` values: writes that act as a person, such as creating a list or writing a note,
    take one as `user_id`.

    A missing or wrong key returns **403** with a JSON body, not an HTML page:

    ```json theme={"system"}
    {
      "message": "Forbidden resource",
      "error": "Forbidden",
      "statusCode": 403,
      "request_id": "0f6d3c52-9f3e-4c1a-a4b8-2b1f7e5d9c10"
    }
    ```
  </Step>
</Steps>

<Check>
  You're done when `GET /v1/team` returns your team name and its members. Next, list your contact
  lists with
  [`GET /v1/contact-lists/csv`](/api-reference/endpoint/get-contact-lists-csv).
</Check>

<Note>
  Keys are long-lived and do not expire on a schedule. Rotate a key from the same settings screen
  when someone with access leaves, or if a key is ever committed to source control.
</Note>

## What you can build

Each card links to the operation or guide that does the job.

<CardGroup cols={2}>
  <Card title="Load lists from your own data" icon="address-book" href="/api-reference/endpoint/create-list">
    Create a contact list from your warehouse or CRM export. Creating it also fills its dialing queue.
  </Card>

  <Card title="Sync call outcomes to your warehouse" icon="phone" href="/api-reference/endpoint/call-log">
    Page through call logs with date and rep filters, and keep your reporting up to date.
  </Card>

  <Card title="Get calls and replies pushed to you" icon="bell" href="/api-reference/introduction#webhooks">
    Webhooks POST call, snooze and Sequencer events to your server as they happen.
  </Card>

  <Card title="Find a phone or email from your app" icon="magnifying-glass" href="/api-reference/endpoint/enrich-email">
    Start a lookup for a LinkedIn profile and get the result by callback or by polling.
  </Card>

  <Card title="Run sequences from your system" icon="list-check" href="/sequencer/api-quickstart">
    Build a cadence, enroll people and work the task queue end to end. Sequencer is in early access.
  </Card>

  <Card title="Report on your team in Claude" icon="chart-line" href="/mcp/use-cases/overview">
    Connect the MCP server and ask questions about calls, reps and lists in plain language.
  </Card>
</CardGroup>

## Build the client

There is no official Salesfinity SDK. The API is fully described by an OpenAPI document, so you
can write a thin client by hand or generate one.

### Generate a client from the OpenAPI description

The description is at [`/api-reference/openapi.json`](/api-reference/openapi.json). Every operation
has a unique `operationId`, which becomes the method name in most generators.

```bash theme={"system"}
# TypeScript, using openapi-typescript
npx openapi-typescript https://docs.salesfinity.ai/api-reference/openapi.json -o salesfinity.d.ts

# Any language, using openapi-generator
openapi-generator-cli generate \
  -i https://docs.salesfinity.ai/api-reference/openapi.json \
  -g python \
  -o ./salesfinity-client
```

### Conventions worth encoding once

| Concern | Convention |
| - | - |
| Base URL | `https://client-api.salesfinity.co` |
| Auth | `x-api-key` header on every request |
| Auth failure | **403**, never 401 — a "refresh on 401" branch will never fire |
| Acting as a person | Writes that record a person take `user_id`, a member's user ID from `GET /v1/team` |
| Unknown fields | A body field the operation does not define is rejected with **400** |
| Request size | 10 MB on `/v1/contact-lists` and `/v2/sequencer`, 1 MB elsewhere; larger gets **413** |
| Pagination | `page` (1-based) and `limit`. Defaults and the response envelope differ by endpoint family; see [Pagination](/api-reference/introduction#pagination) |
| Sorting | `sort=field` ascending, `sort=-field` descending, on the v1 lists that take `sort` |
| Filtering | Bracketed parameters such as `filters[start_date]` on call logs and CSV contact lists; plain query parameters everywhere else |
| Errors | Always JSON, always `{ message, error, statusCode, request_id }` |
| Request IDs | `X-Request-Id` on every response; send your own to trace a request |
| Rate limits | Per team and per minute, reported in `X-RateLimit-*` headers on every authenticated response |
| IDs | Most are 24-character hexadecimal strings; see [Conventions](/api-reference/introduction#conventions) for the exceptions |

### Retries

Retry on **429** and **5xx** with exponential backoff and jitter. On a 429, wait at least the number
of seconds in the `Retry-After` header. Do not retry **400**, **402**, **403**, **404**, **413** or
**422** — none of them succeed on a second identical attempt. Allow at least 60 seconds before
timing out a request: a Sequencer call can take up to 55 seconds before the API answers **504**.

Outside the Sequencer, `POST` endpoints are not idempotent, so cap retries and confirm state with a
`GET` before retrying a create. Sequencer writes (`POST /v2/sequencer/*`, except the `/preview`
endpoints) accept an `Idempotency-Key` header that makes a retry safe. A write that fails frees its
key, so after a 5xx on a create, check with a `GET` before retrying. See
[Retrying writes safely](/api-reference/errors#retrying-writes-safely).

### Rate limits

Limits are per team: every API key on the team shares them. Per minute, the Sequencer allows 600
reads and 300 writes, the heavy reporting reads (the call-log and scored-call lists, analytics,
and CRM sequences) allow 120, and everything else allows 1200. Every authenticated response carries
`X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`, so a bulk job can pace itself
instead of waiting for a 429. See [Rate limits](/api-reference/rate-limits) for the
routes in each bucket.

## Test safely

There is no separate sandbox host. `https://client-api.salesfinity.co` is the only public API
host, and it works on live data. Build your test plan around that.

<AccordionGroup>
  <Accordion title="Start read-only" icon="eye">
    `GET /v1/team`, `GET /v1/dispositions`, `GET /v1/custom-fields` and the analytics endpoints
    have no side effects. They still count toward the [rate limits](/api-reference/rate-limits),
    and analytics shares the 120-per-minute heavy-reads budget.
  </Accordion>

  <Accordion title="Use a test team and a throwaway list" icon="flask">
    Generate a key for a team that is not actively dialing, so writes cannot disturb a live queue.
    [Creating a contact list](/api-reference/endpoint/create-list) gives you an isolated target for
    add, remove and merge calls that you can
    [delete](/api-reference/endpoint/delete-contact-list) afterwards.
  </Accordion>

  <Accordion title="Know which writes reach the dialer" icon="phone-volume">
    Creating a list also creates its dialing queue with the contacts you send.
    [Reimporting a list](/api-reference/endpoint/reimport-contacts) replaces its dialing queue with
    its saved contacts. Deleting a list deletes its dialing queue, and so does merging with
    `delete_sources` for each source list. Adding, removing and merging contacts change only the
    saved list, which reaches the dialing queue at the next reimport.
  </Accordion>

  <Accordion title="Know which writes send email" icon="envelope">
    A Sequencer sequence is created disabled. Enabling it starts the cadence for everyone enrolled,
    and its email steps send real email from your team's mailboxes. The three `/preview` endpoints
    change nothing, so use them to check an enrollment, a rule set or a template first.
  </Accordion>

  <Accordion title="Point enrichment callbacks somewhere disposable" icon="link">
    Set the enrichment `callback_url` to a test endpoint while developing, so results are not
    POSTed at a production handler. It must be a public `http` or `https` URL: `localhost` and
    private, loopback or link-local IP addresses are rejected with **400**. Expose a local handler
    through a tunnel or use a request-inspection service.
  </Accordion>
</AccordionGroup>

<Warning>
  Enrichment endpoints spend real credits. `POST /v1/api/enrichment/email` and
  `POST /v1/api/enrichment/phone` each cost one credit when the lookup returns a result, drawn
  from the team enrichment credits, which are separate from the SmartEnrich credits members spend
  in the dialer. A lookup that finds nothing costs nothing. Both return
  **402 Payment Required** once the team's balance reaches zero. Check the
  [credit balance](/api-reference/endpoint/get-enrichment-credits) before a bulk run.
</Warning>

## Receive events

Webhooks push call, snooze and Sequencer events to your server as they happen, so you do not
have to poll. Create a subscription in the dashboard under **Settings → Connections →
API & Webhooks**. Every delivery carries an `x-salesfinity-event-id` that stays the same across
retries, so make your receiver skip IDs it has already processed. The events, payload shape and
delivery rules are in [Webhooks](/api-reference/introduction#webhooks).

## Build with the Sequencer API <Status kind="early-access" />

The Sequencer API runs outreach end to end: sequences, steps, templates, enrollments, tasks,
suppression and rules of engagement. The Sequencer is in early access, so check the
[changelog](/changelog) for changes that can affect an integration. Start with
[Run a sequence over the API](/sequencer/api-quickstart).

## Machine-readable resources

| Resource | URL | Format |
| - | - | - |
| OpenAPI description | [`/api-reference/openapi.json`](/api-reference/openapi.json) | OpenAPI 3.0.1 JSON |
| Documentation index | [`/llms.txt`](/llms.txt) | Plain text |
| Full documentation | [`/llms-full.txt`](/llms-full.txt) | Plain text |
| Sitemap | [`/sitemap.xml`](/sitemap.xml) | XML |
| Agent card | [`/.well-known/agent-card.json`](/.well-known/agent-card.json) | JSON |
| Docs search MCP server card | [`/.well-known/mcp/server-card.json`](/.well-known/mcp/server-card.json) | JSON |
| Agent skills index | [`/.well-known/agent-skills/index.json`](/.well-known/agent-skills/index.json) | JSON |

The server card describes a server for searching these docs. The Salesfinity MCP server, which
works with your team's data, is at `https://mcp.salesfinity.ai/mcp`; its tools are listed in the
[MCP tool reference](/mcp/tools).

Every documentation page is also available as Markdown. Append `.md` to the URL, or send an
`Accept: text/markdown` request header:

```bash theme={"system"}
curl -H 'Accept: text/markdown' https://docs.salesfinity.ai/developers
curl https://docs.salesfinity.ai/developers.md
```

## Get help

Email [hello@salesfinity.co](mailto:hello@salesfinity.co) or visit the
[help center](https://support.salesfinity.ai). When you report an API problem, include the
`request_id` from the error body (or the `X-Request-Id` response header), the request path, the
timestamp, and the `error` and `statusCode`. Never include your API key.

## Next steps

<CardGroup cols={2}>
  <Card title="Read the API reference" icon="book" href="/api-reference/introduction">
    Authentication, pagination, webhooks and every operation in one place.
  </Card>

  <Card title="Handle errors and retries" icon="triangle-exclamation" href="/api-reference/errors">
    What each status means and what your client should do about it.
  </Card>

  <Card title="Connect Claude to Salesfinity" icon="bolt" href="/mcp/overview">
    Let an assistant read and change your data through the MCP server.
  </Card>

  <Card title="Run a sequence over the API" icon="list-check" href="/sequencer/api-quickstart">
    Create a cadence, enroll people and work the tasks it makes.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.