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

# Examples

> Copy-paste SDK recipes — page edits, pagination, idempotent writes, rate-limit handling.

export const ExpectedOutput = ({caption = "Expected output", children}) => <div className="gv-output">
    <div className="gv-output__label">
      <svg className="gv-output__icon" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <polyline points="15 10 20 15 15 20" />
        <path d="M4 4v7a4 4 0 0 0 4 4h12" />
      </svg>
      <span>{caption}</span>
    </div>
    <div className="gv-output__body">{children}</div>
  </div>;

export const APIBadge = ({method = "GET", path, scope}) => {
  const m = method.toUpperCase();
  return <span className="gv-api-badge">
      <span className={`gv-api-badge__method gv-api-badge__method--${m.toLowerCase()}`}>
        {m}
      </span>
      <code className="gv-api-badge__path">{path}</code>
      {scope && <span className="gv-api-badge__scope">
          <span className="gv-api-badge__scope-label">scope</span>
          <code>{scope}</code>
        </span>}
    </span>;
};

export const BrandCard = ({eyebrow, title, href, icon, badge, cta, featured = false, horizontal = false, children}) => {
  const classes = ["gv-card", featured && "gv-card--featured", horizontal && "gv-card--horizontal"].filter(Boolean).join(" ");
  const inner = <>
      {icon && <span className="gv-card__icon" aria-hidden="true">
          <Icon icon={icon} />
        </span>}
      <div className="gv-card__main">
        {(eyebrow || badge) && <div className="gv-card__meta">
            {eyebrow && <Eyebrow label={eyebrow} tone="muted" />}
            {badge && <span className="gv-card__badge">{badge}</span>}
          </div>}
        <h3 className="gv-card__title">{title}</h3>
        {children && <div className="gv-card__body">{children}</div>}
        {cta && <span className="gv-card__cta">
            {cta}
            <svg className="gv-card__cta-arrow" viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <line x1="7" y1="17" x2="17" y2="7" />
              <polyline points="7 7 17 7 17 17" />
            </svg>
          </span>}
      </div>
    </>;
  return href ? <a className={classes} href={href}>
      {inner}
    </a> : <div className={classes}>{inner}</div>;
};

export const Eyebrow = ({label, tone = "default"}) => <div className={`gv-eyebrow gv-eyebrow--${tone}`}>
    <span className="gv-eyebrow__bar" aria-hidden="true" />
    <span className="gv-eyebrow__label">{label}</span>
  </div>;

<Eyebrow label="SDK" />

Short, self-contained recipes using `@gavai/sdk`. Each example is a working snippet you can drop into a file and run with `bun run`. By the end of this page you will have seen every common pattern at least once — read calls, paginated lists, idempotent writes, rate-limit retries, and custom fetch injection.

## Fetch the current user

<APIBadge method="GET" path="/v1/me" scope="me:read" />

```ts me.ts theme={null}
import { Gavai } from "@gavai/sdk";

const gv = new Gavai({ apiKey: process.env.GAVAI_API_KEY });

const me = await gv.me.get();
console.log(me.user_id, me.scopes);
```

<ExpectedOutput>
  ```text theme={null}
  usr_01HXR8K2M4... [ "pages:read", "pages:write", "pages:publish" ]
  ```
</ExpectedOutput>

## Patch a page and publish

<APIBadge method="PATCH" path="/v1/workspaces/:slug/pages/:id" scope="pages:write" />

Fetch the current page, build an [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) operation array, apply it, then publish to live.

```ts patch-page.ts theme={null}
import { Gavai } from "@gavai/sdk";

const gv = new Gavai({ apiKey: process.env.GAVAI_API_KEY });

const workspace = "acme";
const pageId = "page_01H...";

// 1. Fetch the current page document
const page = await gv.pages.get({ workspace, id: pageId });

// 2. Build the patch — RFC 6902 operation array
const operations = [
  {
    op: "replace",
    path: "/blocks/0/props/title",
    value: "Updated hero title",
  },
];

// 3. Apply the patch
await gv.pages.patch({ workspace, id: pageId, operations });

// 4. Publish to live
await gv.pages.publish({ workspace });
```

## Iterate a paginated list

Log resources use cursor-based pagination. Keep fetching until `next_cursor` is `null`.

```ts paginate-logs.ts theme={null}
import { Gavai } from "@gavai/sdk";

const gv = new Gavai({ apiKey: process.env.GAVAI_API_KEY });

const workspace = "acme";
let cursor: string | null = null;

do {
  const page = await gv.logs.list({
    workspace,
    ...(cursor ? { cursor } : {}),
  });

  for (const entry of page.items) {
    console.log(entry.timestamp, entry.message);
  }

  cursor = page.next_cursor;
} while (cursor);
```

See [Pagination](/api-reference/pagination) for query parameters and cursor semantics.

## Make a write idempotent

Pass an `idempotencyKey` as the second-argument options object so retrying the same call after a network failure does not duplicate the operation.

```ts idempotent-patch.ts theme={null}
import { Gavai } from "@gavai/sdk";

const gv = new Gavai({ apiKey: process.env.GAVAI_API_KEY });

await gv.pages.patch(
  {
    workspace: "acme",
    id: "page_01H...",
    operations: [
      { op: "replace", path: "/blocks/0/props/title", value: "Safe retry" },
    ],
  },
  { idempotencyKey: "patch-page-01H-title-2026-05-11" },
);
```

See [Idempotency](/api-reference/idempotency) for key format and caching window.

## Handle a rate limit

Catch `GavaiError` with `code === "rate_limited"`, wait for the duration the server signals via `Retry-After`, then retry once. Wrap in a bounded loop for production.

```ts rate-limit.ts theme={null}
import { Gavai, GavaiError } from "@gavai/sdk";

const gv = new Gavai({ apiKey: process.env.GAVAI_API_KEY });

async function fetchMeWithRetry() {
  try {
    return await gv.me.get();
  } catch (e) {
    if (e instanceof GavaiError && e.code === "rate_limited") {
      // Retry-After is in seconds; fall back to 5 s if absent
      const retryAfter = Number(e.headers["retry-after"] ?? 5);
      await Bun.sleep(retryAfter * 1000);
      return await gv.me.get();
    }
    throw e;
  }
}
```

## Inject a custom fetch

Swap in a custom fetch implementation — useful for tests against a mock server or for environments that require proxy configuration.

```ts custom-fetch.ts theme={null}
import { Gavai } from "@gavai/sdk";

const customFetch: typeof fetch = async (input, init) => {
  console.log("outbound:", input);
  return fetch(input, init);
};

const gv = new Gavai({
  apiKey: process.env.GAVAI_API_KEY,
  fetch: customFetch,
});

const me = await gv.me.get();
```

## Next steps

<Columns cols={2}>
  <BrandCard title="API reference" href="/api-reference/introduction">
    Every resource, every parameter, every response shape.
  </BrandCard>

  <BrandCard title="Error handling" href="/sdks/error-handling">
    Every error class both SDKs throw, and the catch block for each one.
  </BrandCard>
</Columns>
