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

# API reference

> Authenticate to the Gecko v1 API, understand the response envelope, pagination, idempotency, and tier-aware rate limits.

<Info>
  Gecko's `v1` API lets you trigger scans, read scan, repository, and
  vulnerability data, triage findings, manage scan schedules, and receive
  [webhook events](/docs/api-reference/webhooks), all scoped to the team attached
  to your API key.
</Info>

The API is self-describing. These surfaces are always in sync with the
running service:

| Surface                    | URL                                              |
| -------------------------- | ------------------------------------------------ |
| OpenAPI 3.1 spec           | `https://app.gecko.security/api/v1/openapi.json` |
| Interactive docs           | `https://app.gecko.security/api/v1/docs`         |
| Machine-readable changelog | `https://app.gecko.security/api/v1/changelog`    |
| Health check (public)      | `https://app.gecko.security/api/v1/health`       |

## Authentication

Create a key under **Settings** > **API Keys** ([details](/docs/admin/api-keys)).
Keys start with `gk_` and are shown in full only once, at creation.

Send the key either way; both are equivalent:

* `Authorization: Bearer gk_…`
* `X-API-Key: gk_…`

Every response is scoped to the team the key belongs to, and every request is
checked against the key owner's current role permissions (for example
`scans.read` to list scans, `scans.run` to trigger one).

## Send your first request

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://app.gecko.security/api/v1/scans?limit=10" \
    -H "Authorization: Bearer $GECKO_API_KEY"
  ```

  ```python Python theme={null}
  import requests

  res = requests.get(
      "https://app.gecko.security/api/v1/scans",
      params={"limit": 10},
      headers={"Authorization": "Bearer YOUR_API_KEY"},
  )
  res.raise_for_status()
  print(res.json())
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://app.gecko.security/api/v1/scans?limit=10",
    { headers: { Authorization: `Bearer ${process.env.GECKO_API_KEY}` } },
  );
  const data = await res.json();
  console.log(data);
  ```
</CodeGroup>

## Response envelope

Every response has one of three shapes. Single resources carry an `object`
type discriminator:

```json theme={null}
{ "object": "scan", "id": "…", "status": "completed", "…": "…" }
```

Lists wrap their items and carry cursor pagination:

```json theme={null}
{
  "object": "list",
  "data": [ { "object": "scan", "…": "…" } ],
  "pagination": { "has_more": true, "next_cursor": "…" }
}
```

Errors are structured and self-identifying:

```json theme={null}
{
  "error": {
    "type": "…",
    "code": "…",
    "message": "Human-readable explanation",
    "param": "the offending parameter, when applicable",
    "request_id": "…"
  }
}
```

Every response carries an `X-Request-Id` header; include it when reporting
issues.

## Pagination

Every list endpoint is cursor-based:

* `?limit=`, page size, default `25`, max `250`
* `?cursor=`, opaque cursor from the previous page's `next_cursor`
* `?sort=` and `?order=`, sorting

Keep requesting with the returned `next_cursor` until `has_more` is `false`.

## Rate limits

Limits are per key and depend on your plan:

| Plan       | Requests per hour |
| ---------- | ----------------- |
| Free       | 100               |
| Pro        | 1,000             |
| Enterprise | 5,000             |

Responses include `X-RateLimit-*` headers; Gecko returns
`429 Too Many Requests` when a key reaches its limit. MCP traffic from
[connected AI tools](/docs/ai-tools/overview) shares the same budget.

## Idempotency

Send an `Idempotency-Key` header on any `POST` or `PATCH` to make retries
safe. Replays return the originally stored response with an
`Idempotent-Replayed: true` header.

## Generate a client

There's no hand-written SDK to install; generate types or a full client from
the live spec:

<CodeGroup>
  ```bash TypeScript types theme={null}
  npx openapi-typescript https://app.gecko.security/api/v1/openapi.json -o gecko-api.d.ts
  ```

  ```bash Full TypeScript client theme={null}
  npx @hey-api/openapi-ts -i https://app.gecko.security/api/v1/openapi.json -o src/client
  ```
</CodeGroup>

Postman, Insomnia, and Bruno import OpenAPI 3.1 natively; use **Import** >
**Link** with the spec URL.

## What you can do

<CardGroup cols={2}>
  <Card title="Scans" icon="radar">
    List and trigger scans, fetch a scan's vulnerabilities, discovered API
    endpoints, and generated wiki.
  </Card>

  <Card title="Repositories" icon="folder">
    List repositories, update repository settings, and read per-repository
    scans and vulnerabilities.
  </Card>

  <Card title="Vulnerabilities" icon="shield-halved">
    Read findings with full evidence and triage them (confirm, dismiss,
    accept risk, reopen).
  </Card>

  <Card title="Schedules" icon="clock">
    Create and manage recurring scan schedules.
  </Card>

  <Card title="Webhooks" icon="webhook">
    Subscribe to scan and vulnerability events with signed deliveries.
  </Card>

  <Card title="Releases" icon="box">
    For hybrid deployments: fetch digest-pinned scanner image releases per
    channel.
  </Card>
</CardGroup>

<Check>
  Need request and response details? Open any endpoint page in the sidebar;
  they're generated from the same spec the API serves.
</Check>
