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

# Developer API Overview

> Authenticate, discover, and call Goliath developer API operations from your own code

## About

The Goliath developer API lets your own code — servers, scripts, AI agents,
or third-party tools — read and write the same data you work with in the app:
contacts, properties, deals and pipelines, workflow automations, forms, and
team settings.

There is **one HTTP endpoint**. You never send GraphQL or build queries —
instead you call a named operation from a fixed catalog (an `operationId`)
with its variables, and Goliath executes a pre-authored, pre-reviewed request
on your behalf. Every call runs **as the key's owning user**, so your real
organization permissions and visibility apply — the API can never see or touch
anything you couldn't see in the app yourself.

<Note>
  **Live in production**

  The developer API is live: create and scope a key in the app under
  **Settings → API Keys** and call the production endpoint below — no
  enrollment or approval step. The server also publishes its own always-current
  reference: `GET /api/v1/help` (no auth required) renders full documentation
  for every operation, generated from the running API.
</Note>

<Tip>
  **Looking for something simpler?**

  If all you need is programmatic skip tracing, the standalone
  [Skip Trace API](/skip-trace-api) is a single-purpose
  REST endpoint with its own key. To *receive* data from Goliath instead of
  calling in, see the [Contact Webhook Payload](/contact-webhook)
  reference.
</Tip>

## Generating an API key

1. **Open API Keys.** From the app, go to **Settings → API Keys** (also
   reachable from the API Keys card on the Integrations page).

2. **Create a key.** Keys are personal — each key belongs to your user and
   acts as you. Create one key per host or device so you can revoke them
   independently.

3. **Pick scopes.** Each key carries one or more scopes (see below). `ADMIN`
   can only be granted to a key whose owner is a team admin.

4. **Store the secret.** The key looks like `gsk_...`. Pass it as a Bearer
   token on every request and keep it in your secrets manager — never ship it
   in a browser, mobile app, or any client-side code.

## Scopes

| Scope   | Grants                                                                                                                                                                                                                                              |
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `READ`  | Read operations — fetch and list data.                                                                                                                                                                                                              |
| `WRITE` | Mutating operations — create and update records.                                                                                                                                                                                                    |
| `ADMIN` | Team management, analytics, and billing/credit-spending operations. Implies `READ` + `WRITE`. Only grantable to a team admin's key, and re-checked on every call — if the owner loses admin, the key's `ADMIN` operations stop working immediately. |

Scopes decide what *kind* of operation a key may run. Which specific records it
may touch is a separate check — see [Authorization](/developer-api/authorization)
for how organization ownership and the two kinds of `403` work.

## Making a request

```
POST https://server.goliathdata.com/api/v1/call
Authorization: Bearer gsk_...
Content-Type: application/json

{ "operationId": "getContact", "variables": { "contactId": "..." } }
```

```bash theme={null}
curl -X POST https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer gsk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "operationId": "findContacts", "variables": { "searchTerm": "smith" } }'
```

(`POST /api/v1/graphql` is the same endpoint under its original name and stays
supported — despite that path, it does not accept GraphQL queries either.)

A handled request always returns `200` with a GraphQL-style body:

```json theme={null}
{ "data": { ... }, "errors": [ ... ] }
```

Transport and authorization problems use HTTP status codes instead:

| Status | Code                  | Meaning                                                                                                                                                                                                                       |
| ------ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | `unauthorized`        | Missing bearer header, or invalid/revoked key                                                                                                                                                                                 |
| 400    | `raw_query_forbidden` | Body contained a `query` — raw GraphQL is never accepted                                                                                                                                                                      |
| 400    | `bad_request`         | Body missing a string `operationId`, or malformed `variables`                                                                                                                                                                 |
| 400    | `unknown_operation`   | `operationId` is not in the catalog                                                                                                                                                                                           |
| 400    | `unknown_variable`    | `variables` contained a name the operation doesn't declare. The message lists the accepted variables — undeclared names are rejected rather than silently ignored, so a typo'd filter can't quietly return unfiltered results |
| 403    | `insufficient_scope`  | Key lacks the scope the operation requires                                                                                                                                                                                    |
| 403    | `forbidden`           | Operation references a resource outside your organization                                                                                                                                                                     |
| 429    | `rate_limited`        | Too many calls to a rate-limited operation — retry after the `Retry-After` header                                                                                                                                             |
| 500    | `internal_error`      | Unexpected failure on our side                                                                                                                                                                                                |

## Result limits & truncation

Every list/search operation has a **result cap** — a maximum number of rows it
returns per call. If you send a `limit` larger than the cap, it is **silently
clamped** to the cap: you get the cap's worth of rows, no error.

Most list operations are **fully pageable** — they take an `offset` (or a cursor)
and return a `totalCount` and/or `hasMore`, so you can walk the whole result set a
page at a time. Prefer these when you need everything:

```
# page through all matches
{ "operationId": "findContacts", "variables": { "searchTerm": "smith", "limit": 50, "offset": 0 } }
{ "operationId": "findContacts", "variables": { "searchTerm": "smith", "limit": 50, "offset": 50 } }
```

<Warning>
  **Two operations still cap without pagination**

  These have **no `offset`/cursor**, so rows beyond the cap can't be retrieved:

  * `listAppointments` (cap 50) — returns a `total`, so **if it exceeds the rows you
    got back, narrow the date range** rather than expecting more pages.
  * `listFormActivityLocations` (cap 500) — returns no total; treat a full page
    (exactly the cap) as "possibly more, narrow it."

  Wider pagination on these two is on the roadmap.
</Warning>

## Discovering operations

The full operation catalog is machine-readable — ideal for AI agents and for
keeping your integration in sync:

```
GET https://server.goliathdata.com/api/v1/operations
Authorization: Bearer gsk_...
→ 200 { "operations": [{ "operationId", "operationType", "requiredScope", "summary", "authorized" }] }

GET https://server.goliathdata.com/api/v1/operations/:operationId
→ 200 { variables, responseShape, example, notes, ... }
```

* The **list** returns one-line summaries of every operation.
* The **detail** view returns the full variable schema, the exact response
  shape, and a copy-pasteable example for one operation.
* `authorized` reflects *your key's* scopes, so a caller sees exactly what it
  is allowed to run.

## Operation reference by area

The catalog is documented alongside each feature's user guides:

* [Properties API](/developer-api/properties) — look up and search properties, run saved filters, manage tags and lists
* [Contacts API](/developer-api/contacts) — read, create, update, and enrich contacts
* [Deals API](/developer-api/deals) — read, create, update, and archive deals
* [Pipelines API](/developer-api/pipelines) — manage pipeline structure and read pipeline analytics
* [Workflows API](/developer-api/workflows) — manage workflow automations and runs
* [Content Templates API](/developer-api/content-templates) — manage message templates and folders
* [Forms API](/developer-api/forms) — manage lead-capture forms and read form analytics
* [Communications API](/developer-api/communications) — read inbox threads, recordings and transcripts, manage suppressions, and render templates
* [Notifications API](/developer-api/notifications) — read your notification feed and mark items read
* [Appointments API](/developer-api/appointments) — schedule appointments and manage your availability
* [Tasks API](/developer-api/tasks) — create, reschedule, and complete CRM to-do tasks
* [Skip Trace API](/skip-trace-api) — run skip traces from your own systems
* [Bulk Tasks API](/developer-api/bulk-tasks) — poll the status of long-running bulk jobs
* [Team API](/developer-api/team) — teammates, invites, and team analytics
* [Account API](/developer-api/account) — your profile and integration setup links
* [Billing API](/developer-api/billing) — plan, credit balances, and credit prices

## Not yet available

A few capabilities on the developer-API roadmap aren't exposed yet — use the
app for these until they ship:

* **File uploads** — importing contacts, properties, or skip-trace lists from a CSV.
* **Signal coverage** — querying data-coverage by county/ZIP/state.

<Note>
  The [discovery endpoint](#discovering-operations) is always the source of
  truth for what your key can call right now — if an operation isn't listed
  there, it isn't available yet.
</Note>
