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

# API overview

> What the public API is for, how it authenticates, what a scope grants and what the versioning promise covers.

export const Screenshot = ({id, alt, caption, frame = 'browser', url, marks = [], lang = 'en', workspace = 'northwind-outbound'}) => {
  const src = `/images/screenshots/${lang}/${id}.png`;
  const chrome = url ? `app.pipelime.ai/${workspace}${url}` : 'app.pipelime.ai';
  return <figure className={`pl-shot pl-shot--${frame} not-prose`}>
      <div className="pl-shot__frame">
        {frame !== 'bare' && <div className="pl-shot__bar">
            <span className="pl-shot__dots">
              <span className="pl-shot__dot" />
              <span className="pl-shot__dot" />
              <span className="pl-shot__dot" />
            </span>
            <span className="pl-shot__url">{chrome}</span>
          </div>}
        <div className="pl-shot__media">
          <img src={src} alt={alt} loading="lazy" />
          {marks.map(mark => <span key={mark.n} className="pl-shot__mark" style={{
    left: `${mark.x}%`,
    top: `${mark.y}%`
  }} aria-hidden="true">
              {mark.n}
            </span>)}
        </div>
      </div>
      {caption && <figcaption className="pl-shot__caption">{caption}</figcaption>}
    </figure>;
};

The public API is one versioned contract, `/api/v1`, for getting a lead into a workspace
from your own systems, authenticated by a key instead of a signed-in session.

<div className="pl-availability">
  <div className="pl-availability__row">
    <div className="pl-availability__label">Where</div>
    <div className="pl-availability__value"><span className="pl-path">Settings<span className="pl-path__sep">→</span>API & Integrations</span></div>
  </div>

  <div className="pl-availability__row">
    <div className="pl-availability__label">Your role needs</div>
    <div className="pl-availability__value">Update access to Lead intake API <code>update-companies</code>. Admin have it by default.</div>
  </div>

  <div className="pl-availability__note">Authenticated by a workspace API key, not by a signed-in session. Creating a key needs the same permission as the rest of the API settings tab.</div>
</div>

## What's part of the contract

Two surfaces are stable enough to build on, and this help center documents both: the
versioned group at `/api/v1`, and the public endpoints under `/api/public/…`: the Web Forms
submissions endpoint, the website tracker beacon and the free tools. Those are the shapes
that cannot quietly change.

Nothing else is. The rest of `/api/` is the app talking to itself, and it can change without
notice however solid it looks in a network tab.

## Authenticating a request

Authenticate with an `Authorization: Bearer <key>` header, or `X-API-Key: <key>` if your HTTP
client reserves the first one for something else. There's no workspace parameter to pass: a
key is minted for one workspace, and every request resolves that workspace from the key
alone, so an integration can never address a workspace it wasn't issued a key for.

A key's prefix says which environment issued it. Keys look like `plk_test_a1B2c3D4_…`
everywhere except production, where they begin `plk_live_`. A key only works against the
environment that minted it, so one pasted into the wrong environment is rejected on the first
request rather than writing somewhere you didn't mean.

## Scopes

A key carries one or more scopes, chosen when it's created. The create-key dialog calls them
**Permissions**, and it won't let you create a key with none. There are three. `tags:read`
lists your tags, `leads:read` reads a lead back, and `leads:write` creates and updates them.
Each route checks its own scope, so granting one never grants another.

`leads:write` and `tags:read` are ticked for you when the dialog opens, which is enough to
send a lead in; `leads:read` is something you add on purpose. One route needs no scope at
all: `GET /me` is a health check any key can call, whatever it's scoped for, and it's the
fastest way to confirm a credential works before you build anything else on it. Call an
endpoint your key isn't scoped for and you get a `403` naming the exact scope that is
missing, not a blanket unauthorized.

## Rate limits, and never from a browser

Each key gets its own budget of 300 requests a minute. It is counted against the key, not
against the address the request came from, so an integration you run on shared or serverless
infrastructure is measured on its own traffic. A batch call counts as one request, however
many leads it carries.

<Warning>
  Cross-origin requests are not restricted by domain, so a browser can call this API directly.
  That is exactly why a key must never ship in client-side code. Anyone who opens your
  page's network tab or reads its JavaScript can read the key and use it exactly as you can,
  including to write into your workspace. Call the API from a server, a serverless function
  or an automation tool, never from a script that runs in a visitor's browser. If you need a
  browser to send you leads, use Web Forms or the tracker beacon: those carry a public
  per-form or per-tracker token instead of a key, and check the domain calling them.
</Warning>

Most of this also lives inside the product, on the same settings tab as your keys and
directly below them: a **Send a lead** card pre-filled with your workspace's own tags, a
**Try it** panel that runs that exact request against your workspace once you paste a key
into it, and a **Fields** table. **Dry run** is on when the panel loads, so the first request
you send validates and previews without saving anything. Every topic below has its own page
here; the panel is the same material without leaving the app.

<Screenshot id="api/overview--docs-panel" url="/settings/api" alt="The Send a lead card on the API and Integrations settings tab: a row of tag chips with one selected, a language tab strip, and a generated request below it built for this workspace" caption="The snippet updates the moment you pick a different tag, so what you copy already matches this workspace." />

## Where each part is explained

<CardGroup cols={2}>
  <Card title="Authentication" icon="key-round" href="/en/developers/authentication">
    Every header and failure mode for a request, and what each one means.
  </Card>

  <Card title="POST /leads" icon="send" href="/en/developers/post-leads">
    The request body, duplicate handling, dry run, and every field the response returns.
  </Card>

  <Card title="POST /leads/batch" icon="layers" href="/en/developers/post-leads-batch">
    Send many leads in one call and read the outcome of each row on its own.
  </Card>

  <Card title="Lead fields reference" icon="list" href="/en/developers/lead-fields-reference">
    Every field POST /leads accepts, grouped, with the limits on the repeating ones.
  </Card>

  <Card title="GET /me, GET /tags and GET /leads/{id}" icon="search" href="/en/developers/get-me-tags-and-leads">
    Confirm which workspace a key belongs to, list the tags you can apply, and read a lead back.
  </Card>

  <Card title="Idempotency, deduplication and rate limits" icon="repeat" href="/en/developers/idempotency-deduplication-and-rate-limits">
    Retry safely, how an existing lead gets recognized, and what happens when you send too fast.
  </Card>

  <Card title="Code samples" icon="code" href="/en/developers/code-samples">
    Ready-to-paste requests in cURL, JavaScript, Python and PHP, plus the raw JSON body.
  </Card>

  <Card title="Web Forms: capture script and submissions endpoint" icon="clipboard-list" href="/en/developers/web-forms-capture-endpoint">
    Install the embed snippet, or post submissions to the endpoint yourself.
  </Card>

  <Card title="Website tracker beacon" icon="radar" href="/en/developers/website-tracker-beacon">
    What the tracking snippet sends, and what its errors mean.
  </Card>

  <Card title="Outbound webhooks" icon="webhook" href="/en/developers/outbound-webhooks">
    How a lead leaves the platform: a connector and a workflow block, not a subscribable event feed.
  </Card>

  <Card title="Free tools" icon="wrench" href="/en/developers/free-tools">
    Public tools anyone can use without a key, and how they differ from the API.
  </Card>
</CardGroup>

## Related

<CardGroup cols={2}>
  <Card title="Create, roll and revoke API keys" icon="key" href="/en/developers/api-keys">
    Where a key actually comes from, and what changes the moment you revoke one.
  </Card>

  <Card title="Quickstart: send your first lead" icon="rocket" href="/en/developers/quickstart-send-a-lead">
    Check the key, post a lead as a dry run, then send it for real.
  </Card>

  <Card title="Errors reference" icon="octagon-alert" href="/en/developers/errors">
    Every status the API returns and what to change before you retry.
  </Card>
</CardGroup>
