# Build with AI

> Everything an AI coding assistant needs to integrate 9in correctly: context files, specs and a prompt to start from.

Source: https://9in.io/docs/build-with-ai/

AI coding assistants integrate 9in well when they read the right context first. Everything in these docs is available as plain text built for that.

## Give your assistant the docs

| Link | What it is | Use it when |
|---|---|---|
| [`https://9in.io/llms.txt`](https://9in.io/llms.txt) | An index of every page with a one-line summary, plus the facts most often gotten wrong | The assistant can browse: it reads the index, then the pages it needs |
| [`https://9in.io/llms-full.txt`](https://9in.io/llms-full.txt) | All pages in one Markdown file | You paste or attach context once |
| `https://9in.io/docs/<page>.md` | One page in Markdown (or **Copy page as Markdown** at the top of any page) | You want a focused context, such as one guide |
| [`https://9in.io/openapi.json`](https://9in.io/openapi.json) | The Management API as OpenAPI 3.1 | Generating API clients or calls |
| [`https://9in.io/schemas/…`](https://9in.io/schemas/webhook-event.json) | JSON Schemas: webhook events, adapter protocol, theme manifest | Typing webhook handlers and adapters |
| `<issuer>/.well-known/openid-configuration` | Your tenant's live OpenID Connect metadata | Configuring any OIDC library |

The TypeScript SDK ships its own type definitions, so editors and assistants see every option of `@9in-io/sdk` as they type.

## A prompt to start from

Fill in the brackets and paste this into your assistant:

```text
Add sign-in with 9in to this [Next.js / Express / Laravel / React / iOS] app.

Read https://9in.io/llms.txt first, then the guide for this kind of app and
https://9in.io/docs/reference/tokens.md.

Our tenant:
- Issuer (sandbox while we develop): https://[tenant]-sandbox.9in.io
- Application client ID: [app_…]   (client secret in the env var NINE_CLIENT_SECRET, if any)
- Callback URL: [http://localhost:3000/callback]
- Our API's audience: [https://api.example.com], scopes: [orders:read]

Requirements:
- Use the official 9in SDK for this stack if there is one, otherwise a certified
  OpenID Connect library. Use authorization code + PKCE; never the implicit flow.
- Read configuration from environment variables (NINE_ISSUER, NINE_CLIENT_ID, …).
- Verify access tokens in the API: signature via the issuer's JWKS, iss, aud, exp, scopes.
- Add sign-in, sign-out, a protected page and one protected API route, and tell me which
  URLs to add to the application in the 9in console.
```

## Facts assistants get wrong

Give these to an assistant that is guessing, or check its work against them:

- **There is no client secret in browsers or mobile apps.** Single-page and native apps are public clients: authorization code + PKCE (S256). Never put a client secret in front-end code.
- **The issuer has no path.** It is `https://<tenant>.9in.io` (or a custom domain), not `…/oauth` or `…/v1`. Endpoints come from `<issuer>/.well-known/openid-configuration`.
- **Access tokens are for APIs, ID tokens are for the app.** Send the access token to your API; don't verify ID tokens there. Request access tokens for your API with `audience=<API identifier>`; without it, the access token's `aud` is your client ID.
- **Access tokens are JWTs with `typ: at+jwt`**, signed with the algorithm of the tenant's key (RS256 by default, but ES256, EdDSA or HMAC are possible). Don't hard-code RS256; take the algorithm from the key. Some APIs use opaque tokens (`9in_at_…`), which must be introspected.
- **Allowed web origins** must include a single-page app's origin, or the browser's token request fails with a CORS error.
- **The Management API is on the tenant host:** `https://<tenant>.9in.io/api/v1/…`, with a client-credentials token that has `management:*` scopes. There is no API key.
- **User fields differ between input and output** in the Management API: you send `emailVerified`, `phone` and `phoneVerified`; you get back `email_verified`, `phone_number` and `phone_number_verified`.
- **Webhooks and adapter calls are signed** with `9in-signature: t=<unix seconds>,v1=<hex>` where the HMAC-SHA256 covers `t + "." + METHOD + "." + path + "." + rawBody`. Verify against the raw body, not re-serialized JSON. Event ids repeat on retries: process each once.
- **Sandbox and production share configuration but not users.** `<tenant>-sandbox.9in.io` accepts any password and the code `000000`; production users never appear there.
