> For the complete documentation index, see [llms.txt](https://docs.antivamp.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.antivamp.io/developers/sdk-setup.md).

# SDK Setup

Install @antivamp\_io/sdk, configure it for sandbox and production, and verify the install works before you write any integration code.

Fifteen minutes from `npm install` to a verified client. Every snippet here is copy-pasteable and run against the live API — if one fails for you, it is a real problem, not a typo in the docs.

For what each method does, see [SDK Reference](/developers/sdk.md). For the endpoints behind them, see [API Reference](/developers/api-reference.md) — the SDK is a client for the public REST API, and **every endpoint stays available if you would rather call it directly**.

## 01 — Install

```bash
npm install @antivamp_io/sdk
```

Node.js ≥ 18, ESM, zero runtime dependencies. **Server-side only** — the client takes an API key, so bundling it into browser code leaks that key to anyone who opens devtools.

{% hint style="warning" %}
The package is **`@antivamp_io/sdk`**, with the underscore. It matches our npm org. There is no `@antivamp/sdk` — an install of that name will 404.
{% endhint %}

Require **0.2.4 or newer** — the current release. It rolls up keeper-token handling for production event reports (0.2.0), `Retry-After` rate-limit handling (0.2.1, see [Rate Limits](/developers/rate-limits.md)), wrong-environment decision rejection (0.2.2), alias-aware registry resolution (0.2.3), and payer split / launcher delegation (0.2.4). Confirm what you have:

```bash
npm ls @antivamp_io/sdk
```

On 0.1.0, production `reportBond` and `reportMilestone` were refused by the server because the client did not send the keeper attestation. It failed quietly — a rejected event report does not fail a launch, so the only symptom was a copycat lock that never landed. See [Changelog](#changelog).

## 02 — Set your environment

```bash
# Sandbox — safe to experiment, seeded scenarios, no real protection
ANTIVAMP_API_KEY=av_sbx_…

# Production — issued manually after review
# ANTIVAMP_API_KEY=av_live_…
# ANTIVAMP_KEEPER_TOKEN=…      # required for production bond/milestone reports
```

Get a sandbox key from the [partner portal](https://antivamp.io/partners) or `POST /v1/sandbox/keys`. Sandbox keys are self-serve; production keys are issued after review. See [Environments](/developers/environments.md).

## 03 — Initialize the client

```ts
import { AntiVampClient } from "@antivamp_io/sdk";

export const antivamp = new AntiVampClient({
  apiKey: process.env.ANTIVAMP_API_KEY,
  // Picked up from ANTIVAMP_KEEPER_TOKEN automatically; shown for clarity.
  keeperToken: process.env.ANTIVAMP_KEEPER_TOKEN,
});
```

Create it once and reuse it. It caches decision-verification keys and the chain registry for five minutes each, so a fresh client per request throws that away and adds a round trip.

`baseUrl` defaults to `https://antivamp.io`. `https://api.antivamp.io` and `https://sandbox-api.antivamp.io` also work if you prefer an explicit host.

## 04 — Verify the install

Save as `verify-antivamp.mjs` and run it. It touches only public endpoints, so it works before your key is provisioned.

```js
import { AntiVampClient, normalizeIdentity } from "@antivamp_io/sdk";

const antivamp = new AntiVampClient({ apiKey: process.env.ANTIVAMP_API_KEY });

// 1. Offline normalization — must match the server and the on-chain fold.
const id = normalizeIdentity("Green Robin", "$R0BIN");
console.log("identityKey:", id.identityKey); // GREENROBIN::SROBIN

// 2. Public identity check — no key required, but sent when configured.
const free = await antivamp.checkIdentity({ name: "Setup Check Demo", ticker: "SETUPQ" });
console.log("free:     ", free.status, free.decision);

// 3. A protected identity, so you see the case that actually matters.
const taken = await antivamp.checkIdentity({ name: "Green Robin", ticker: "ROBIN" });
console.log("protected:", taken.status, taken.decision, `(enforcement: ${taken.enforcement})`);

// 4. Live chain registry — resolve addresses instead of hardcoding them.
for (const c of await antivamp.getChains()) {
  if (c.status === "live") console.log(c.id.padEnd(12), c.reservationRegistry ?? "(program)");
}
```

Output when this was last run against production:

```
identityKey: GREENROBIN::SROBIN
free:      available allow
protected: protected allow_authorized_only (enforcement: network)
solana       (program)
base         0x33A4221c9c6C9fD63b770E512C515Fed53e6931D
bnb          0xC8A42B434e3bF2fAbe7fE88c3d83B0C21bda8597
robinhood    0x33A4221c9c6C9fD63b770E512C515Fed53e6931D
ethereum     0xC8A42B434e3bF2fAbe7fE88c3d83B0C21bda8597
hyperliquid  0x60C1960656C594a49CF3D0d83FBBD9077fa89f10
```

Two things to read from that rather than skim past.

`allow_authorized_only` is **not** permission to launch. It means the identity is protected and the launcher you sent is not the authorized one. `enforceLaunch` blocks it; only a verified `allow` proceeds.

The addresses are read live, which is the entire point — do not copy them out of this page. Registries get cut over, and a launchpad holding a stale address does not degrade gracefully. See [EVM wiring](#evm-resolve-addresses-do-not-hardcode-them).

## 05 — Gate a launch

The one call that has to be right. `enforceLaunch` validates, verifies the Ed25519 signature and expiry, then maps every decision exhaustively.

```ts
import { AntiVampFailClosedError } from "@antivamp_io/sdk";

try {
  const gate = await antivamp.enforceLaunch({
    chain: "solana",
    launchpad: "your-launchpad",
    name: creator.tokenName,
    ticker: creator.tokenTicker,
    launcher: creator.wallet, // the wallet that will actually deploy
  });

  if (gate.block) return reject(gate.reason);
  await deploy();
} catch (err) {
  // Outage, timeout, or an unverifiable decision. Do NOT launch.
  if (err instanceof AntiVampFailClosedError) return reject("validation unavailable");
  throw err;
}
```

Send the wallet that will actually deploy. `allow_authorized_only` means the identity is protected and your launcher is not the authorized one — `enforceLaunch` blocks it, and you must re-validate with the connected wallet rather than treating it as permission. See [Validate every launch](/for-launchpads/validate-every-launch.md).

## 06 — Run the conformance suite

Before requesting production access, prove the integration end to end:

```bash
ANTIVAMP_API_KEY=av_sbx_… npx antivamp-conformance
```

It exercises normalization, a blocked launch, signature verification, and webhook HMAC against seeded sandbox scenarios, and exits non-zero on any failure. See [Production checklist](/for-launchpads/production-checklist.md).

## Production event reporting needs a keeper token

`reportBond` and `reportMilestone` extend on-chain locks, so production requires a keeper attestation on top of your partner key — otherwise any partner key could forge a lock extension. Sandbox does not need one.

```ts
const antivamp = new AntiVampClient({
  apiKey: process.env.ANTIVAMP_API_KEY,      // av_live_…
  keeperToken: process.env.ANTIVAMP_KEEPER_TOKEN,
});
```

The SDK sends it as `X-AntiVamp-Keeper: Bearer …` on those two calls only, since that token authorizes protection mutations and should not travel with unrelated requests. A production key with no keeper token throws **before** the request is sent, rather than letting the server return `403 keeper_required` into a log nobody reads.

Calling the endpoints directly? Send the header yourself:

```bash
curl -X POST https://api.antivamp.io/api/v1/events/bonded \
  -H "Authorization: Bearer $ANTIVAMP_API_KEY" \
  -H "X-AntiVamp-Keeper: Bearer $ANTIVAMP_KEEPER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"chain":"base","launchpad":"your-launchpad","name":"Green Robin","ticker":"ROBIN","wasReserved":true}'
```

## EVM: resolve addresses, do not hardcode them

On EVM chains the reservation gate is a contract, and your factory must be the one that registry trusts. Two things have to agree: your factory's `reservationRegistry()` must be AntiVamp's registry, and that registry's `factory()` must be your factory.

If either drifts, `markLaunched` reverts `NotFactory` and **every launch fails**. There is no soft failure. This has happened twice in production, both times because an address was copied into a launchpad's `.env` and a later cutover moved on without it.

```ts
const registry = await antivamp.getReservationRegistry("base");
```

Point your reserve UI, your indexer and your factory at that address. Cache it with a TTL and re-read on boot; never bake it into a build. Then assert the loop closes in both directions before calling the integration live.

## Troubleshooting

| Symptom                                                             | Cause                                                       | Fix                                                                                                                       |
| ------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `404` on `npm install @antivamp/sdk`                                | Wrong scope                                                 | Install `@antivamp_io/sdk`                                                                                                |
| `AntiVampApiError: missing_api_key`                                 | No key on an authenticated call                             | Set `ANTIVAMP_API_KEY`                                                                                                    |
| `403 keeper_required`                                               | Production event without the keeper header                  | Set `ANTIVAMP_KEEPER_TOKEN`; upgrade to ≥ 0.2.4                                                                           |
| `AntiVampApiError: keeper_required` thrown locally, no request sent | Production key, no keeper token — working as intended       | Set `ANTIVAMP_KEEPER_TOKEN`                                                                                               |
| `AntiVampFailClosedError`                                           | Outage, timeout, or unverifiable decision                   | Do not launch. Retry; it already retried transient failures — and on a rate limit check `retryAfterSeconds` to reschedule |
| `insufficient_scope`                                                | Key lacks the scope for that call                           | Check scopes in [Authentication](/developers/authentication.md)                                                           |
| Locks never appear on-chain                                         | Event reports rejected, or protection is `network`-enforced | Check `enforcement` on the response; see [Enforcement guide](/for-launchpads/enforcement-guide.md)                        |
| Types do not resolve in TypeScript                                  | Old resolution mode                                         | Use `moduleResolution: "nodenext"` or `"bundler"`                                                                         |

## Changelog

| Version   | Change                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **0.2.4** | Payer split and launcher delegation. `prepareReservation` accepts `payer` + `launcherApproval` (Solana): a funded wallet pays and owns the hold on-chain while the launcher — e.g. a Privy embedded wallet — keeps launch rights through a verified delegation. New `delegateLauncher()` rescues already-stranded holds on every chain: call without `signature` to receive the exact message the current on-chain holder must sign (thrown as `AntiVampApiError` code `signature_required` with `details.expectedMessage` + `details.holder`), then retry with it. See [Payer Split & Launcher Delegation](/for-launchpads/payer-split.md). |
| **0.2.3** | `getReservationRegistry` resolves a chain by its canonical id or an advertised alias, so `getReservationRegistry("hyperevm")` no longer 404s against a chains list that returns `hyperliquid`. `ChainInfo` gains `aliases`.                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **0.2.2** | Verification refuses a revoked decision key and one signed for the wrong environment — a sandbox-signed decision can no longer be trusted by a production client. Back-compatible with pinned key sets that predate the environment field.                                                                                                                                                                                                                                                                                                                                                                                                   |
| **0.2.1** | A `429` follows `Retry-After` instead of guessing with exponential backoff, since a guessed retry inside the same fixed window only deepens the overrun. Adds `maxRetryAfterMs` (default `5000`): a longer wait throws immediately with `retryAfterSeconds` on the error rather than blocking your call, and that field now survives `validateLaunch`'s fail-closed wrapper so you can refuse the launch and still know when to return. `checkIdentity` sends your key when one is configured, which meters the call against your own limit instead of a shared per-IP allowance.                                                            |
| **0.2.0** | Sends `X-AntiVamp-Keeper` on production `reportBond` / `reportMilestone`, and refuses locally when a production key has no keeper token. Adds `getChains`, `getReservationRegistry`, `listProtectedIdentities`, `iterateProtectedIdentities`, `getIdentityStatus`, and the reservation quote/prepare/status/list/create surface.                                                                                                                                                                                                                                                                                                             |
| **0.1.0** | First release. **Do not use for production event reporting** — it did not send the keeper attestation, so production bond and milestone reports were refused and the copycat lock silently never landed.                                                                                                                                                                                                                                                                                                                                                                                                                                     |

## Continue exploring

* 📦 [SDK Reference](/developers/sdk.md) — every method, with examples
* 🔑 [Authentication](/developers/authentication.md) — keys, scopes, the keeper header
* 🌐 [Environments](/developers/environments.md) — sandbox vs production
* ⚠️ [Errors](/developers/errors.md) — every code and what to do about it
* 🚀 [Integration Quickstart](/for-launchpads/quickstart.md) — the launchpad path end to end


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.antivamp.io/developers/sdk-setup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
