> For the complete documentation index, see [llms.txt](https://docs.themochi.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.themochi.app/start-here/code-examples.md).

# Use an example in your language

Choose the language your server already uses. The cURL, Python, Node.js/TypeScript, and PHP examples below all make the same read-only request. They use ordinary HTTP libraries, so you can see exactly what is sent to Mochi.

Run these examples only on a trusted computer or server. Never put a Mochi API key in browser JavaScript, a mobile app, or software distributed to customers.

Set these values before running an example. Run `read`, paste the key when the cursor waits, and press Enter. The terminal does not display the key or put it in the command in your shell history.

```bash
read -s MOCHI_API_KEY
export MOCHI_API_KEY
export MOCHI_BASE_URL="https://api.themochi.app"
```

## First example: list leads

Each example requests up to ten leads. A successful response contains a `data` list and `next_cursor`, the value used to load another page.

### cURL

```bash
curl --fail-with-body --silent --show-error \
  --url "${MOCHI_BASE_URL}/v1/leads/?page_size=10" \
  --header "Authorization: Bearer ${MOCHI_API_KEY}" \
  --header "Accept: application/json"
```

### Python

This example uses [Requests](https://requests.readthedocs.io/).

```python
import os

import requests


api_key = os.environ["MOCHI_API_KEY"]
base_url = os.environ.get("MOCHI_BASE_URL", "https://api.themochi.app")

response = requests.get(
    f"{base_url}/v1/leads/",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Accept": "application/json",
    },
    params={"page_size": 10},
    timeout=30,
)

request_id = response.headers.get("X-Request-ID", "unknown")
if not response.ok:
    raise RuntimeError(f"Mochi returned HTTP {response.status_code}; request_id={request_id}")

payload = response.json()
print(payload["data"])
print("next_cursor:", payload["next_cursor"])
```

### Node.js / TypeScript

This example uses Node.js's built-in Fetch API. Run it on a currently supported Node.js release.

```typescript
type LeadPage = {
  data: Array<Record<string, unknown>>;
  next_cursor: string | null;
};

const apiKey = process.env.MOCHI_API_KEY;
const baseUrl = process.env.MOCHI_BASE_URL ?? "https://api.themochi.app";

if (!apiKey) {
  throw new Error("MOCHI_API_KEY is required");
}

const url = new URL("/v1/leads/", baseUrl);
url.searchParams.set("page_size", "10");

const response = await fetch(url, {
  headers: {
    Authorization: `Bearer ${apiKey}`,
    Accept: "application/json",
  },
  signal: AbortSignal.timeout(30_000),
});

const requestId = response.headers.get("x-request-id") ?? "unknown";
if (!response.ok) {
  throw new Error(`Mochi returned HTTP ${response.status}; request_id=${requestId}`);
}

const payload = (await response.json()) as LeadPage;
console.log(payload.data);
console.log("next_cursor:", payload.next_cursor);
```

### PHP

This example requires a currently supported PHP release with the cURL extension.

```php
<?php

$apiKey = getenv("MOCHI_API_KEY");
$baseUrl = getenv("MOCHI_BASE_URL") ?: "https://api.themochi.app";

if (!$apiKey) {
    throw new RuntimeException("MOCHI_API_KEY is required");
}

$requestId = "unknown";
$handle = curl_init($baseUrl . "/v1/leads/?page_size=10");
curl_setopt_array($handle, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . $apiKey,
        "Accept: application/json",
    ],
    CURLOPT_HEADERFUNCTION => function ($curl, $header) use (&$requestId) {
        if (stripos($header, "X-Request-ID:") === 0) {
            $requestId = trim(substr($header, strlen("X-Request-ID:")));
        }
        return strlen($header);
    },
]);

$body = curl_exec($handle);
if ($body === false) {
    throw new RuntimeException("Mochi request failed: " . curl_error($handle));
}

$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
curl_close($handle);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException("Mochi returned HTTP {$status}; request_id={$requestId}");
}

$payload = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
print_r($payload["data"]);
echo "next_cursor: " . ($payload["next_cursor"] ?? "null") . PHP_EOL;
```

## Next: load every page

Treat `next_cursor` as opaque, which means you must not interpret or change it. Pass it back unchanged and stop when it is `null`.

```python
cursor = None

while True:
    params = {"page_size": 100}
    if cursor is not None:
        params["cursor"] = cursor

    response = requests.get(
        f"{base_url}/v1/leads/",
        headers={"Authorization": f"Bearer {api_key}"},
        params=params,
        timeout=30,
    )
    response.raise_for_status()

    page = response.json()
    for lead in page["data"]:
        print(lead)

    cursor = page["next_cursor"]
    if cursor is None:
        break
```

Do not construct a cursor, infer business meaning from it, or automatically restart from the first page when a cursor is rejected.

## Advanced: make a write safe to retry

This example changes data by adding one existing manual tag to one lead. It requires `leads:write`, explicit approval, and an **idempotency key** that identifies this one intended change. Use only an approved test lead and tag. Generate a new UUID4 for each new intended operation.

```bash
export MOCHI_LEAD_ID="123"
export MOCHI_TAG_ID="456"
export MOCHI_IDEMPOTENCY_KEY="$(python -c 'import uuid; print(uuid.uuid4())')"

curl --fail-with-body --silent --show-error \
  --request POST \
  --url "${MOCHI_BASE_URL}/v1/leads/${MOCHI_LEAD_ID}/tags/" \
  --header "Authorization: Bearer ${MOCHI_API_KEY}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: ${MOCHI_IDEMPOTENCY_KEY}" \
  --data "{\"tag_id\": ${MOCHI_TAG_ID}}"
```

If the client times out, retry the same method, path, body, and `Idempotency-Key`. Do not generate a new key for the retry. A successful replay includes `Idempotent-Replay: true`.

## Retry safely

* Retry `429` only after the `Retry-After` delay. Add a small random delay when workers share a key.
* Retry temporary network failures a limited number of times, waiting longer after each failure.
* Do not retry `400`, `401`, `403`, or `404` automatically.
* Do not log authorization headers, request or response bodies, cursors, contact values, or message content.
* Retain the response `X-Request-ID`, status, method, path, and UTC timestamp for troubleshooting.

Unset the example values when you finish:

```bash
unset MOCHI_API_KEY MOCHI_BASE_URL MOCHI_LEAD_ID MOCHI_TAG_ID MOCHI_IDEMPOTENCY_KEY
```


---

# 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.themochi.app/start-here/code-examples.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.
