> ## 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.

# Authorization

> How the developer API decides what a key may do — scopes, organization access, and what a 403 means

## About

Every developer-API call runs **as the key's owning user**. Two things then
decide whether a call is allowed to proceed:

1. **Your scopes** — is the key permitted to run this *kind* of operation at all?
2. **Your organization's access** — does your org own (or have shared access to)
   the specific records the call references?

If either check fails, the request stops with a `403` before any data is read
or written. You never get back a record your organization can't see.

## The four checks

Under the hood, an authorized call passes four checks in order. They map to the
two questions above plus the always-on identity and visibility guarantees:

| Check                   | Question                                                                    | Failure                  |
| ----------------------- | --------------------------------------------------------------------------- | ------------------------ |
| **Authentication**      | Is the bearer key valid and un-revoked?                                     | `401 unauthorized`       |
| **Scope**               | Does the key carry the scope this operation requires?                       | `403 insufficient_scope` |
| **Organization access** | Does your org own or share every record id the call references?             | `403 forbidden`          |
| **Visibility**          | Runs *as you* — you only ever see the rows and fields you'd see in the app. | *(no error — filtered)*  |

The first two are transport-level and covered in the
[Overview](/developer-api/overview#scopes). This page is about the
third — **organization access** — which is what keeps one org's data invisible
and untouchable to another.

## Organization access

Each operation declares which of its variables are **resource ids** — the
`dealId`, `contactId`, `pipelineId`, or destination `stageId` it acts on. Those
are checked against your organization *before* the operation runs, at one of two
levels:

| Level      | Meaning                                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Owned**  | The record belongs to your organization.                                                                                                  |
| **Shared** | The record belongs to another org but is reachable by yours — for example a deal in a **pipeline shared with you through a partnership**. |

Most operations accept **owned or shared** access. A call that references an id
your org can neither own nor reach returns `403 forbidden`. Where an operation
guards a *list* of ids (for example the `userIds` and `contactIds` on
`createDeal` / `updateDeal`), one foreign id fails the whole call rather than
being partially applied.

<Note>
  **Not every id is a pre-checked resource id**

  The gateway pre-checks the ids an operation declares as resource ids — which
  varies by operation. A secondary id an operation *doesn't* declare (for
  example a tag id on a contact write) isn't a preflight `403`; it's validated
  by the operation as it runs and surfaces its own error (an unknown tag comes
  back as `NOT_FOUND`, not `forbidden`). Each area's page notes what it guards.
</Note>

<Note>
  **Structure edits require ownership**

  A few operations require **owned** access, not just shared — editing the
  structure of a pipeline (renaming or reordering its stages, deleting it) is
  the pipeline owner's prerogative, so those calls return `403 forbidden` on a
  pipeline that's merely *shared* with you. Reading and moving deals within a
  shared pipeline works normally.
</Note>

## What a 403 means

There are two distinct `403`s — the code tells you which check failed:

| Code                 | Cause                                                                                                                                   | Fix                                                                                            |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `insufficient_scope` | The key lacks the scope the operation requires (e.g. a `READ`-only key calling a `WRITE` op, or a non-admin key calling an `ADMIN` op). | Recreate the key with the needed scope. `ADMIN` requires the owner to be a team admin.         |
| `forbidden`          | The operation referenced a record outside your organization's access.                                                                   | Check the ids — one of them belongs to another org (or a pipeline that isn't shared with you). |

A malformed id (not a valid identifier) is a `400 bad_request`, not a `403` —
it never leaks whether the id exists.

## Where this applies today

The organization-access model above is enforced for the **[Deals](/developer-api/deals)**,
**[Pipelines](/developer-api/pipelines)**, and **[Contacts](/developer-api/contacts)**
operations — the deal / pipeline / stage / contact ids those operations act on
are org-guarded (deals additionally guard their forwarded stage, user, and
contact ids). Coverage is being extended — both to more domains and to more of
each operation's secondary ids — as the developer API moves toward general
availability; each area's page notes what it guards today. The identity and
scope checks (authentication, `READ` / `WRITE` / `ADMIN`) apply to **every**
operation already.
