# Gate
URL: /docs/x1id/gate

> Gating-as-a-service — protect an endpoint, a Discord, a mint, or an airdrop with one call that answers "does this @handle (or wallet) hold a verified on-chain attestation matching my policy?" Define reusable policies and let agents pay per decision.

# Gate

<Pill tone="mainnet">Mainnet</Pill>

<LlmActions />

**Gate** answers one question over HTTP: *does this subject hold a verified on-chain attestation that satisfies my policy?* Point it at an `@handle` or a wallet, hand it a policy, and get back a decision with the attestations behind it. You reuse X1ID's verification oracle as your allowlist instead of running your own.

<Callout type="info">
  This is the **hosted** version of the SDK's gating primitive. If you'd rather read chain yourself (or gate **on-chain** from another program via a CPI), see [Attestation gating](/docs/x1id/gating) — same policy shapes, same staleness rules, no key needed.
</Callout>

## Check a subject

<Endpoint method="POST" path="/v1/gate/check" />

Body: exactly one of `handle` / `wallet`, plus a `policy`. A wallet subject is gated on its **primary** `@handle`.

```bash title="POST /v1/gate/check"
curl -X POST https://api.x1id.io/v1/gate/check \
  -H "X-API-Key: $X1ID_API_KEY" -H "content-type: application/json" \
  -d '{ "handle": "@jack", "policy": { "kind": 4 } }'
```

```json
{
  "passed": true,
  "subject": { "handle": "jack", "wallet": null },
  "policy": { "kind": 4 },
  "attestations": [
    { "platform": "github", "kind": 4, "attested_at": 1733270400 }
  ]
}
```

| field          | meaning                                                                                                                                                                                                  |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `passed`       | the decision.                                                                                                                                                                                            |
| `subject`      | who was evaluated. For a wallet subject, `handle` is its resolved primary (or `null`).                                                                                                                   |
| `policy`       | the policy that ran.                                                                                                                                                                                     |
| `attestations` | the live attestations that count — the *which* behind the decision.                                                                                                                                      |
| `reason`       | present only when `passed` is false for a structural reason: `no-primary-handle` (the wallet has no primary) or `handle-not-registered`. Lets you tell "no identity" from "identity, but doesn't match." |

A definitive "does not pass" — an unregistered handle, a wallet with no primary, or no matching attestation — is a real `200 { "passed": false }` decision (and is metered). Only malformed input (`400`) and infrastructure failure (`502`) are non-decisions.

## Policies

A policy is what the subject must prove. Three inline shapes, mirroring the SDK's `Gate` type exactly:

| Policy                | Passes when the handle holds…                                     |
| --------------------- | ----------------------------------------------------------------- |
| `"any-verified"`      | at least one non-stale attestation of **any** kind.               |
| `{ "kind": 4 }`       | a non-stale attestation of **exactly** that kind.                 |
| `{ "anyOf": [2, 4] }` | a non-stale attestation of **any** listed kind (X **or** GitHub). |

Attestation kinds: `0` dns · `1` social (legacy) · `2` x · `3` discord · `4` github · `5` telegram. A policy with an out-of-range kind is rejected at definition time (`400 BAD_GATE`), never silently never-matching.

### Named policies

Define a policy once and reference it by id — handy when the same door is checked from many places. Policy management is **keyed only** (a policy is scoped to your API key).

<Endpoint method="POST" path="/v1/gate/policies" />

```bash title="POST /v1/gate/policies"
curl -X POST https://api.x1id.io/v1/gate/policies \
  -H "X-API-Key: $X1ID_API_KEY" -H "content-type: application/json" \
  -d '{ "name": "github-verified", "gate": { "kind": 4 } }'
# → 201 { "id": "gp_…", "name": "github-verified", "gate": { "kind": 4 }, "created_at": "…" }
```

Then pass the `gp_…` id as the `policy` in a check:

```bash
curl -X POST https://api.x1id.io/v1/gate/check \
  -H "X-API-Key: $X1ID_API_KEY" -H "content-type: application/json" \
  -d '{ "wallet": "H8Fs…X1HiA", "policy": "gp_…" }'
```

`GET /v1/gate/policies/:id` reads one back (owner-scoped). A `gp_…` string is always treated as a stored-policy reference; any other value is an inline policy.

## Metering

A gate **decision** is metered exactly like a resolve: with a key it counts against your [rate limit](/docs/x1id/platform#tiers-and-rate-limits); with no key, each decision can be paid for per call via [x402](/docs/x1id/platform#pay-per-call-with-x402). Defining and reading named policies always requires a key.

## What a pass means — and what it doesn't

<Callout type="warn">
  **Trust in the gate = trust in the attestor**, exactly like the blue-tick.
</Callout>

* **`passed: true`** means the handle carries a live, attestor-signed attestation matching your policy. The attestor is X1ID's verification oracle.
* It is **"verified by x1id"**, not trustless proof and not legal personhood. The attestor key is admin-rotatable. Render the result as exactly that.
* **Staleness is enforced for you.** An attestation only counts for the *current* owner — one left from a previous owner (before a transfer, sale, or re-register) never counts.
* **Ownership changes**, so re-check per session. Pair a gate check with [Connect](/docs/x1id/connect) to first prove the visitor controls the handle, then gate on what it's verified.

## Next

<Cards>
  <Card href="/docs/x1id/connect" icon="LogIn" title="Sign in with X1ID" description="Prove control first, then gate — a complete verified-only door with no backend of your own." />

  <Card href="/docs/x1id/gating" icon="ShieldCheck" title="Attestation gating (SDK / CPI)" description="Gate off-chain in your own code, or on-chain from another program." />

  <Card href="/docs/x1id/verification" icon="BadgeCheck" title="Verified identity" description="How attestations and the blue-tick work." />
</Cards>
