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

# Envelopes and errors

> One response wrapper for every success, one error format with a closed 16-code taxonomy.

Every endpoint in every service answers with one of two envelopes. You write the parsing code once.

## The success envelope

A success body always carries `success: true`, the `operation` that names the payload shape, the payload itself, and a `meta` block.

| `operation` | Payload | Returned by |
| - | - | - |
| `search` | `items[]`, `counts`, `pagination`, `applied_filters`, `includes` | `POST /api/{entity}/search` |
| `get` | `item`, `included` | `GET /api/{entity}/{sid}` |
| `create` | `item`, plus flags such as `already_exists` where relevant | `POST /api/{entity}` |
| `update` | `item`, `changed_fields` | `PATCH /api/{entity}/{sid}` |
| `delete` | deletion report | `DELETE /api/{entity}/{sid}` |
| `metrics` | period-bound aggregates | `POST /api/{entity}/metrics` |
| `action` | `action` name plus a verb-specific result | verb endpoints like `POST /api/mass-actions/{sid}/pause` |

A `search` response in full:

```json theme={null}
{
  "success": true,
  "operation": "search",
  "items": [
    {
      "item": { "sid": "wh_hk_Jk2mP9nR4qW1", "status": "active" },
      "included": {}
    }
  ],
  "counts": {
    "total_count": 247,
    "groups": { "status": { "active": 240, "disabled": 7 } }
  },
  "pagination": {
    "next_cursor": "eyJpZCI6MTAwfQ==",
    "has_more": true,
    "total_count": 247
  },
  "applied_filters": { "status": { "eq": "active" } },
  "includes": [],
  "meta": {
    "trace_id": "0198f2ab-7c11-7e32-9a41-d2b64f2a91c3",
    "span_id": "9a41d2b64f2a91c3",
    "timestamp": "2026-07-28T12:00:00Z",
    "duration_ms": 42
  }
}
```

Points worth knowing:

* **`items[]` splits `item` from `included`.** The `item` is always the same typed shape; relations you request via `include` arrive next to it under `included`, never mixed into it.
* **`counts` covers the full filter scope, not the page.** With 50 rows shown out of 1,000 matching, `counts.total_count` is 1000.
* **`applied_filters` echoes what the server actually applied**, so a client (or an AI agent) can confirm the query it asked for is the query that ran.
* **`meta.trace_id` is the support handle.** It is a UUID v7, identical to the `X-Trace-Id` response header. Quote it when reporting an issue.

## The error envelope

Every failure, from any service, is the same shape:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "URL does not match the Sales Navigator format",
    "recoverable": true,
    "suggestion": "Make sure the URL starts with linkedin.com/sales/ and contains search parameters",
    "field_errors": {
      "source_url": [
        { "rule": "regex", "message": "Expected URL like linkedin.com/sales/search/*" }
      ]
    }
  }
}
```

* `code` is always one of the 16 values below, never an arbitrary string.
* `recoverable` says whether retrying with corrected input can succeed (`true`) or the state itself is the problem (`false`).
* `field_errors` appears only on `validation_failed`, keyed by field. Each entry's `rule` is the machine reason (`ln_member_id_not_numeric`, `resend_not_available`) and its `message` the sentence for it; the same reason appears as `error.context.reason` on a `conflict`, `rate_limited` or `service_unavailable`. Every reason and its sentence is listed on the [Reasons](/concepts/reasons) page, generated from the backends' own catalogs.
* `delete_blocked` errors additionally carry `error.blockers[]`: each blocker names its `type`, a `hard` or `soft` severity, and the `resolution` that clears it.

## Send endpoints name their outcome

An error from an endpoint that sends something to LinkedIn (a message, an InMail, a voice note, a connection request, a comment, a post, a repost, a reaction) also carries `error.context.send_outcome`. It is `not_sent` when nothing went out, `in_flight` while the send is running, `unknown` when it may have gone out, or `sent`. Read it before you retry. Anything but `not_sent` is handled by sending the same request again under the same `client_reference` or by asking check-sent, never by sending it as a new one. A reaction is the exception: it takes no key, and the same reaction sent again changes nothing on LinkedIn. [Sending once](/concepts/sending-once) has the whole rule.

## The 16 error codes

| Code | HTTP | Meaning |
| - | - | - |
| `validation_failed` | 422 | Invalid input; details in `field_errors` |
| `nothing_to_update` | 422 | PATCH with no real changes |
| `not_found` | 404 | The sid does not exist in this team's scope |
| `relation_not_found` | 422 | A referenced entity (for example a `*_sid` field) does not exist |
| `invalid_transition` | 409 | The state machine forbids this move |
| `limit_exceeded` | 429 | A business limit was hit (daily budgets, plan caps) |
| `payment_required` | 402 | The plan does not include this |
| `duplicate_rejected` | 409 | An entity with the same natural key already exists |
| `conflict` | 409 | The request conflicts with current state; editing fields will not fix it |
| `delete_blocked` | 409 | Blockers exist; see `error.blockers[]` |
| `unauthorized` | 401 | Missing or invalid token |
| `forbidden` | 403 | No rights on this team or resource |
| `rate_limited` | 429 | Throttled; slow down and retry |
| `not_implemented` | 501 | Contract is final, capability not shipped; do not retry |
| `internal_error` | 500 | A bug on our side; report the `trace_id` |
| `service_unavailable` | 503 | A downstream dependency is down; retry with backoff |

A practical mapping: retry `rate_limited` and `service_unavailable` with backoff, fix and resend `validation_failed` and `relation_not_found`, treat the 409 family as "re-read the current state first", and never auto-retry `not_implemented` or `internal_error`. On a send endpoint, read `error.context.send_outcome` before any of these.


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