diff --git a/api-template.md b/api-template.md
new file mode 100644
index 0000000..e22c05c
--- /dev/null
+++ b/api-template.md
@@ -0,0 +1,106 @@
+# Replicate Python SDK API reference
+
+## Installation
+
+```bash
+pip install replicate
+```
+
+## Initialize a client
+
+Start by setting a `REPLICATE_API_TOKEN` environment variable in your environment. You can create a token at [replicate.com/account/api-tokens](https://replicate.com/account/api-tokens).
+
+Then use this code to initialize a client:
+
+```py
+import replicate
+```
+
+That's it! You can now use the client to make API calls.
+
+
+If you want to explicitly pass the token when creating a client, you can do so like this:
+
+
+```python
+import os
+import replicate
+
+client = replicate.Replicate(
+    bearer_token=os.environ["REPLICATE_API_TOKEN"]
+)
+```
+
+## High-level operations
+
+### `replicate.use()`
+
+Create a reference to a model that can be used to make predictions.
+
+```python
+import replicate
+
+claude = replicate.use("anthropic/claude-sonnet-4")
+
+output = claude(prompt="Hello, world!")
+print(output)
+
+banana = replicate.use("google/nano-banana")
+output = banana(prompt="Make me a sandwich")
+print(output)
+```
+
+Note: The `replicate.use()` method only returns output. If you need access to more metadata like prediction ID, status, metrics, or input values, use `replicate.predictions.create()` instead.
+
+### `replicate.run()`
+
+Run a model and wait for the output. This is a convenience method that creates a prediction and waits for it to complete.
+
+```python
+import replicate
+
+# Run a model and get the output directly
+output = replicate.run(
+    "anthropic/claude-sonnet-4",
+    input={"prompt": "Hello, world!"}
+)
+print(output)
+```
+
+Note: The `replicate.run()` method only returns output. If you need access to more metadata like prediction ID, status, metrics, or input values, use `replicate.predictions.create()` instead.
+
+
+## API operations
+
+
+
+## Low-level API
+
+For cases where you need to make direct API calls not covered by the SDK methods, you can use the low-level request interface:
+
+### Making custom requests
+
+```python
+import replicate
+
+client = replicate.Replicate()
+
+# Make a custom GET request
+response = client.get("/custom/endpoint")
+
+# Make a custom POST request with data
+response = client.post(
+    "/custom/endpoint",
+    json={"key": "value"}
+)
+
+# Make a custom request with all options
+response = client.request(
+    method="PATCH",
+    url="/custom/endpoint",
+    json={"key": "value"},
+    headers={"X-Custom-Header": "value"}
+)
+```
+
+See the [README](https://github.com/replicate/replicate-python-stainless/blob/main/README.md) for more details about response handing, error handling, pagination, async support, and more.
diff --git a/api.md b/api.md
index d037762..c6c966f 100644
--- a/api.md
+++ b/api.md
@@ -1,193 +1,731 @@
-# Replicate
+# Replicate Python SDK API reference
+
+## Installation
+
+```bash
+pip install replicate
+```
+
+## Initialize a client
+
+Start by setting a `REPLICATE_API_TOKEN` environment variable in your environment. You can create a token at [replicate.com/account/api-tokens](https://replicate.com/account/api-tokens).
+
+Then use this code to initialize a client:
+
+```py
+import replicate
+```
+
+That's it! You can now use the client to make API calls.
+
+
+If you want to explicitly pass the token when creating a client, you can do so like this:
+
+
+```python
+import os
+import replicate
+
+client = replicate.Replicate(
+    bearer_token=os.environ["REPLICATE_API_TOKEN"]
+)
+```
+
+## High-level operations
+
+### `replicate.use()`
+
+Create a reference to a model that can be used to make predictions.
+
+```python
+import replicate
+
+claude = replicate.use("anthropic/claude-sonnet-4")
+
+output = claude(prompt="Hello, world!")
+print(output)
+
+banana = replicate.use("google/nano-banana")
+output = banana(prompt="Make me a sandwich")
+print(output)
+```
+
+Note: The `replicate.use()` method only returns output. If you need access to more metadata like prediction ID, status, metrics, or input values, use `replicate.predictions.create()` instead.
+
+### `replicate.run()`
+
+Run a model and wait for the output. This is a convenience method that creates a prediction and waits for it to complete.
+
+```python
+import replicate
+
+# Run a model and get the output directly
+output = replicate.run(
+    "anthropic/claude-sonnet-4",
+    input={"prompt": "Hello, world!"}
+)
+print(output)
+```
+
+Note: The `replicate.run()` method only returns output. If you need access to more metadata like prediction ID, status, metrics, or input values, use `replicate.predictions.create()` instead.
+
+
+## API operations
+
+Available operations:
+
+- [`search`](#search)
+- [`predictions.create`](#predictionscreate)
+- [`predictions.get`](#predictionsget)
+- [`predictions.list`](#predictionslist)
+- [`predictions.cancel`](#predictionscancel)
+- [`models.create`](#modelscreate)
+- [`models.get`](#modelsget)
+- [`models.list`](#modelslist)
+- [`models.delete`](#modelsdelete)
+- [`models.examples.list`](#modelsexampleslist)
+- [`models.predictions.create`](#modelspredictionscreate)
+- [`models.readme.get`](#modelsreadmeget)
+- [`models.versions.get`](#modelsversionsget)
+- [`models.versions.list`](#modelsversionslist)
+- [`models.versions.delete`](#modelsversionsdelete)
+- [`collections.get`](#collectionsget)
+- [`collections.list`](#collectionslist)
+- [`deployments.create`](#deploymentscreate)
+- [`deployments.get`](#deploymentsget)
+- [`deployments.list`](#deploymentslist)
+- [`deployments.update`](#deploymentsupdate)
+- [`deployments.delete`](#deploymentsdelete)
+- [`deployments.predictions.create`](#deploymentspredictionscreate)
+- [`files.list`](#fileslist)
+- [`files.create`](#filescreate)
+- [`files.delete`](#filesdelete)
+- [`files.get`](#filesget)
+- [`files.download`](#filesdownload)
+- [`trainings.create`](#trainingscreate)
+- [`trainings.get`](#trainingsget)
+- [`trainings.list`](#trainingslist)
+- [`trainings.cancel`](#trainingscancel)
+- [`hardware.list`](#hardwarelist)
+- [`account.get`](#accountget)
+- [`webhooks.default.secret.get`](#webhooksdefaultsecretget)
+
+### `search`
+
+Search models, collections, and docs (beta)
+
+
+```python
+response = replicate.search(
+    query="nano banana",
+)
+print(response.collections)
+```
+
+Docs: https://replicate.com/docs/reference/http#search
+
+---
+
+### `predictions.create`
+
+Create a prediction
+
+
+```python
+prediction = replicate.predictions.create(
+    input={
+        "text": "Alice"
+    },
+    version="replicate/hello-world:9dcd6d78e7c6560c340d916fe32e9f24aabfa331e5cce95fe31f77fb03121426",
+)
+print(prediction.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#predictions.create
+
+---
+
+### `predictions.get`
+
+Get a prediction
+
+
+```python
+prediction = replicate.predictions.get(
+    prediction_id="prediction_id",
+)
+print(prediction.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#predictions.get
+
+---
+
+### `predictions.list`
+
+List predictions
+
+
+```python
+page = replicate.predictions.list()
+page = page.results[0]
+print(page.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#predictions.list
+
+---
+
+### `predictions.cancel`
+
+Cancel a prediction
+
+
+```python
+prediction = replicate.predictions.cancel(
+    prediction_id="prediction_id",
+)
+print(prediction.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#predictions.cancel
+
+---
+
+### `models.create`
+
+Create a model
+
+
+```python
+model = replicate.models.create(
+    hardware="cpu",
+    name="hot-dog-detector",
+    owner="alice",
+    visibility="public",
+)
+print(model.cover_image_url)
+```
+
+Docs: https://replicate.com/docs/reference/http#models.create
+
+---
+
+### `models.get`
+
+Get a model
+
+
+```python
+model = replicate.models.get(
+    model_owner="model_owner",
+    model_name="model_name",
+)
+print(model.cover_image_url)
+```
+
+Docs: https://replicate.com/docs/reference/http#models.get
+
+---
+
+### `models.list`
+
+List public models
+
+
+```python
+page = replicate.models.list()
+page = page.results[0]
+print(page.cover_image_url)
+```
+
+Docs: https://replicate.com/docs/reference/http#models.list
+
+---
+
+### `models.delete`
+
+Delete a model
+
+
+```python
+replicate.models.delete(
+    model_owner="model_owner",
+    model_name="model_name",
+)
+```
+
+Docs: https://replicate.com/docs/reference/http#models.delete
+
+---
+
+### `models.examples.list`
+
+List examples for a model
+
+
+```python
+page = replicate.models.examples.list(
+    model_owner="model_owner",
+    model_name="model_name",
+)
+page = page.results[0]
+print(page.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#models.examples.list
+
+---
+
+### `models.predictions.create`
+
+Create a prediction using an official model
+
+
+```python
+prediction = replicate.models.predictions.create(
+    model_owner="model_owner",
+    model_name="model_name",
+    input={
+        "prompt": "Tell me a joke",
+        "system_prompt": "You are a helpful assistant",
+    },
+)
+print(prediction.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#models.predictions.create
+
+---
+
+### `models.readme.get`
+
+Get a model's README
 
-Types:
 
 ```python
-from replicate.types import SearchResponse
+readme = replicate.models.readme.get(
+    model_owner="model_owner",
+    model_name="model_name",
+)
+print(readme)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#models.readme.get
+
+---
 
-- replicate.search(\*\*params) -> SearchResponse
+### `models.versions.get`
 
-# Collections
+Get a model version
 
-Types:
 
 ```python
-from replicate.types import CollectionListResponse, CollectionGetResponse
+version = replicate.models.versions.get(
+    model_owner="model_owner",
+    model_name="model_name",
+    version_id="version_id",
+)
+print(version.id)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#models.versions.get
+
+---
 
-- replicate.collections.list() -> SyncCursorURLPage[CollectionListResponse]
-- replicate.collections.get(\*, collection_slug) -> CollectionGetResponse
+### `models.versions.list`
 
-# Deployments
+List model versions
 
-Types:
 
 ```python
-from replicate.types import (
-    DeploymentCreateResponse,
-    DeploymentUpdateResponse,
-    DeploymentListResponse,
-    DeploymentGetResponse,
+page = replicate.models.versions.list(
+    model_owner="model_owner",
+    model_name="model_name",
 )
+page = page.results[0]
+print(page.id)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#models.versions.list
 
-- replicate.deployments.create(\*\*params) -> DeploymentCreateResponse
-- replicate.deployments.update(\*, deployment_owner, deployment_name, \*\*params) -> DeploymentUpdateResponse
-- replicate.deployments.list() -> SyncCursorURLPage[DeploymentListResponse]
-- replicate.deployments.delete(\*, deployment_owner, deployment_name) -> None
-- replicate.deployments.get(\*, deployment_owner, deployment_name) -> DeploymentGetResponse
+---
 
-## Predictions
+### `models.versions.delete`
 
-Methods:
+Delete a model version
 
-- replicate.deployments.predictions.create(\*, deployment_owner, deployment_name, \*\*params) -> Prediction
 
-# Hardware
+```python
+replicate.models.versions.delete(
+    model_owner="model_owner",
+    model_name="model_name",
+    version_id="version_id",
+)
+```
+
+Docs: https://replicate.com/docs/reference/http#models.versions.delete
+
+---
+
+### `collections.get`
+
+Get a collection of models
 
-Types:
 
 ```python
-from replicate.types import HardwareListResponse
+collection = replicate.collections.get(
+    collection_slug="collection_slug",
+)
+print(collection.description)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#collections.get
 
-- replicate.hardware.list() -> HardwareListResponse
+---
 
-# Account
+### `collections.list`
+
+List collections of models
 
-Types:
 
 ```python
-from replicate.types import AccountGetResponse
+page = replicate.collections.list()
+page = page.results[0]
+print(page.description)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#collections.list
+
+---
 
-- replicate.account.get() -> AccountGetResponse
+### `deployments.create`
 
-# Models
+Create a deployment
 
-Types:
 
 ```python
-from replicate.types import (
-    ModelCreateResponse,
-    ModelListResponse,
-    ModelGetResponse,
-    ModelSearchResponse,
+deployment = replicate.deployments.create(
+    hardware="hardware",
+    max_instances=0,
+    min_instances=0,
+    model="model",
+    name="name",
+    version="version",
 )
+print(deployment.current_release)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#deployments.create
 
-- replicate.models.create(\*\*params) -> ModelCreateResponse
-- replicate.models.list() -> SyncCursorURLPage[ModelListResponse]
-- replicate.models.delete(\*, model_owner, model_name) -> None
-- replicate.models.get(\*, model_owner, model_name) -> ModelGetResponse
-- replicate.models.search(\*\*params) -> SyncCursorURLPage[ModelSearchResponse]
+---
 
-## Examples
+### `deployments.get`
 
-Methods:
+Get a deployment
 
-- replicate.models.examples.list(\*, model_owner, model_name) -> SyncCursorURLPage[Prediction]
 
-## Predictions
+```python
+deployment = replicate.deployments.get(
+    deployment_owner="deployment_owner",
+    deployment_name="deployment_name",
+)
+print(deployment.current_release)
+```
+
+Docs: https://replicate.com/docs/reference/http#deployments.get
 
-Methods:
+---
 
-- replicate.models.predictions.create(\*, model_owner, model_name, \*\*params) -> Prediction
+### `deployments.list`
 
-## Readme
+List deployments
 
-Types:
 
 ```python
-from replicate.types.models import ReadmeGetResponse
+page = replicate.deployments.list()
+page = page.results[0]
+print(page.current_release)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#deployments.list
 
-- replicate.models.readme.get(\*, model_owner, model_name) -> str
+---
 
-## Versions
+### `deployments.update`
+
+Update a deployment
 
-Types:
 
 ```python
-from replicate.types.models import VersionListResponse, VersionGetResponse
+deployment = replicate.deployments.update(
+    deployment_owner="deployment_owner",
+    deployment_name="deployment_name",
+)
+print(deployment.current_release)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#deployments.update
 
-- replicate.models.versions.list(\*, model_owner, model_name) -> SyncCursorURLPage[VersionListResponse]
-- replicate.models.versions.delete(\*, model_owner, model_name, version_id) -> None
-- replicate.models.versions.get(\*, model_owner, model_name, version_id) -> VersionGetResponse
+---
 
-# Predictions
+### `deployments.delete`
+
+Delete a deployment
 
-Types:
 
 ```python
-from replicate.types import Prediction, PredictionOutput, PredictionRequest
+replicate.deployments.delete(
+    deployment_owner="deployment_owner",
+    deployment_name="deployment_name",
+)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#deployments.delete
 
-- replicate.predictions.create(\*\*params) -> Prediction
-- replicate.predictions.list(\*\*params) -> SyncCursorURLPageWithCreatedFilters[Prediction]
-- replicate.predictions.cancel(\*, prediction_id) -> Prediction
-- replicate.predictions.get(\*, prediction_id) -> Prediction
+---
 
-# Trainings
+### `deployments.predictions.create`
+
+Create a prediction using a deployment
 
-Types:
 
 ```python
-from replicate.types import (
-    TrainingCreateResponse,
-    TrainingListResponse,
-    TrainingCancelResponse,
-    TrainingGetResponse,
+prediction = replicate.deployments.predictions.create(
+    deployment_owner="deployment_owner",
+    deployment_name="deployment_name",
+    input={
+        "prompt": "Tell me a joke",
+        "system_prompt": "You are a helpful assistant",
+    },
 )
+print(prediction.id)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#deployments.predictions.create
+
+---
+
+### `files.list`
+
+List files
+
+
+```python
+page = replicate.files.list()
+page = page.results[0]
+print(page.id)
+```
 
-- replicate.trainings.create(\*, model_owner, model_name, version_id, \*\*params) -> TrainingCreateResponse
-- replicate.trainings.list() -> SyncCursorURLPage[TrainingListResponse]
-- replicate.trainings.cancel(\*, training_id) -> TrainingCancelResponse
-- replicate.trainings.get(\*, training_id) -> TrainingGetResponse
+Docs: https://replicate.com/docs/reference/http#files.list
 
-# Webhooks
+---
 
-## Default
+### `files.create`
 
-### Secret
+Create a file
 
-Types:
 
 ```python
-from replicate.types.webhooks.default import SecretGetResponse
+file = replicate.files.create(
+    content=b"raw file contents",
+)
+print(file.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#files.create
+
+---
+
+### `files.delete`
+
+Delete a file
+
+
+```python
+replicate.files.delete(
+    file_id="file_id",
+)
+```
+
+Docs: https://replicate.com/docs/reference/http#files.delete
+
+---
+
+### `files.get`
+
+Get a file
+
+
+```python
+file = replicate.files.get(
+    file_id="file_id",
+)
+print(file.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#files.get
+
+---
+
+### `files.download`
+
+Download a file
+
+
+```python
+response = replicate.files.download(
+    file_id="file_id",
+    expiry=0,
+    owner="owner",
+    signature="signature",
+)
+print(response)
+content = response.read()
+print(content)
 ```
 
-Methods:
+Docs: https://replicate.com/docs/reference/http#files.download
 
-- replicate.webhooks.default.secret.get() -> SecretGetResponse
+---
 
-# Files
+### `trainings.create`
+
+Create a training
 
-Types:
 
 ```python
-from replicate.types import FileCreateResponse, FileListResponse, FileGetResponse
+training = replicate.trainings.create(
+    model_owner="model_owner",
+    model_name="model_name",
+    version_id="version_id",
+    destination="destination",
+    input={},
+)
+print(training.id)
 ```
+
+Docs: https://replicate.com/docs/reference/http#trainings.create
+
+---
+
+### `trainings.get`
+
+Get a training
+
+
+```python
+training = replicate.trainings.get(
+    training_id="training_id",
+)
+print(training.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#trainings.get
+
+---
+
+### `trainings.list`
+
+List trainings
+
+
+```python
+page = replicate.trainings.list()
+page = page.results[0]
+print(page.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#trainings.list
+
+---
+
+### `trainings.cancel`
+
+Cancel a training
+
+
+```python
+response = replicate.trainings.cancel(
+    training_id="training_id",
+)
+print(response.id)
+```
+
+Docs: https://replicate.com/docs/reference/http#trainings.cancel
+
+---
+
+### `hardware.list`
+
+List available hardware for models
+
+
+```python
+hardware = replicate.hardware.list()
+print(hardware)
+```
+
+Docs: https://replicate.com/docs/reference/http#hardware.list
+
+---
+
+### `account.get`
+
+Get the authenticated account
+
+
+```python
+account = replicate.account.get()
+print(account.type)
+```
+
+Docs: https://replicate.com/docs/reference/http#account.get
+
+---
+
+### `webhooks.default.secret.get`
+
+Get the signing secret for the default webhook
+
+
+```python
+secret = replicate.webhooks.default.secret.get()
+print(secret.key)
+```
+
+Docs: https://replicate.com/docs/reference/http#webhooks.default.secret.get
+
+---
+
+
+## Low-level API
+
+For cases where you need to make direct API calls not covered by the SDK methods, you can use the low-level request interface:
+
+### Making custom requests
+
+```python
+import replicate
+
+client = replicate.Replicate()
+
+# Make a custom GET request
+response = client.get("/custom/endpoint")
+
+# Make a custom POST request with data
+response = client.post(
+    "/custom/endpoint",
+    json={"key": "value"}
+)
+
+# Make a custom request with all options
+response = client.request(
+    method="PATCH",
+    url="/custom/endpoint",
+    json={"key": "value"},
+    headers={"X-Custom-Header": "value"}
+)
+```
+
+See the [README](https://github.com/replicate/replicate-python-stainless/blob/main/README.md) for more details about response handing, error handling, pagination, async support, and more.
diff --git a/pyproject.toml b/pyproject.toml
index 044be7f..c790881 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -70,6 +70,7 @@ format = { chain = [
 ]}
 "format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md"
 "format:ruff" = "ruff format"
+"update-api-docs" = "python scripts/utils/update-api-docs.py"
 
 "lint" = { chain = [
   "check:ruff",
diff --git a/scripts/update-api-docs b/scripts/update-api-docs
new file mode 100755
index 0000000..d84cd61
--- /dev/null
+++ b/scripts/update-api-docs
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -e
+
+cd "$(dirname "$0")/.."
+
+echo "==> Updating API documentation"
+python3 scripts/utils/update-api-docs.py
\ No newline at end of file
diff --git a/scripts/utils/update-api-docs.py b/scripts/utils/update-api-docs.py
new file mode 100644
index 0000000..acb3538
--- /dev/null
+++ b/scripts/utils/update-api-docs.py
@@ -0,0 +1,315 @@
+#!/usr/bin/env python3
+"""
+Script to generate API.md documentation from OpenAPI spec with code samples.
+"""
+
+from __future__ import annotations
+
+import re
+import sys
+import json
+import tempfile
+import subprocess
+from typing import Any
+from pathlib import Path
+
+
+def download_openapi_spec() -> dict[str, Any]:
+    """Download and parse the OpenAPI spec from Stainless."""
+    import urllib.request
+
+    spec_url = "https://app.stainless.com/api/spec/documented/replicate-client/openapi.documented.yml"
+
+    print(f"Downloading OpenAPI spec from {spec_url}...")
+
+    with urllib.request.urlopen(spec_url) as response:
+        yaml_content = response.read().decode("utf-8")
+
+    # Save to temp file to dereference it
+    with tempfile.NamedTemporaryFile(mode="w", suffix=".yml", delete=False) as f:
+        f.write(yaml_content)
+        temp_path = f.name
+
+    try:
+        # Try to use swagger-cli if available to dereference
+        result = subprocess.run(
+            ["npx", "@apidevtools/swagger-cli", "bundle", temp_path, "--dereference", "--type", "json"],
+            capture_output=True,
+            text=True,
+        )
+        if result.returncode == 0:
+            spec = json.loads(result.stdout)
+            print("Successfully dereferenced OpenAPI spec using swagger-cli")
+        else:
+            # Fallback to PyYAML
+            import yaml
+
+            with open(temp_path, "r") as f:
+                spec = yaml.safe_load(f)
+            print("Loaded OpenAPI spec using PyYAML (not dereferenced)")
+    finally:
+        Path(temp_path).unlink(missing_ok=True)
+
+    return spec
+
+
+def extract_operation_id(path: str, method: str, operation: dict[str, Any]) -> str:
+    """Extract operation ID from operation object."""
+    if "operationId" in operation:
+        return operation["operationId"]
+
+    # Fallback: generate from path and method
+    # Convert path like /models/{model_owner}/{model_name} to models_get
+    clean_path = path.strip("/").replace("{", "").replace("}", "").replace("/", "_")
+    return f"{clean_path}_{method}"
+
+
+def remove_client_instantiation(code: str) -> str:
+    """Remove client instantiation code from examples."""
+    # Pattern to match Replicate client instantiation
+    patterns = [
+        # Multi-line instantiation
+        r"replicate\s*=\s*Replicate\s*\([^)]*\)\s*\n",
+        # Single-line instantiation
+        r"replicate\s*=\s*Replicate\s*\([^)]*\)",
+        # Import and instantiation in one
+        r"from replicate import Replicate\s*\n",
+        r"import replicate\s*\n\s*replicate\s*=\s*Replicate\s*\([^)]*\)\s*\n?",
+        # Client with bearer_token
+        r'client\s*=\s*replicate\.Replicate\s*\(\s*bearer_token\s*=\s*"[^"]*"\s*\)\s*\n?',
+        r'replicate\s*=\s*replicate\.Replicate\s*\(\s*bearer_token\s*=\s*"[^"]*"\s*\)\s*\n?',
+    ]
+
+    cleaned = code
+    for pattern in patterns:
+        cleaned = re.sub(pattern, "", cleaned, flags=re.MULTILINE)
+
+    # Clean up extra blank lines at the start
+    lines = cleaned.split("\n")
+    while lines and not lines[0].strip():
+        lines.pop(0)
+
+    return "\n".join(lines)
+
+
+def format_operation(operation_id: str, operation: dict[str, Any]) -> str:
+    """Format a single operation as markdown."""
+    summary = operation.get("summary", "").strip()
+
+    # Extract code sample
+    code_sample = ""
+    if "x-readme" in operation and "code-samples" in operation["x-readme"]:
+        samples = operation["x-readme"]["code-samples"]
+        # Look for Python sample
+        for sample in samples:
+            if sample.get("language") == "python" or sample.get("lang") == "python":
+                code = sample.get("code", "")
+                code = remove_client_instantiation(code)
+                if code:
+                    code_sample = f"\n```python\n{code}\n```"
+                break
+
+    # Generate docs link
+    docs_link = f"https://replicate.com/docs/reference/http#{operation_id}"
+
+    # Build the markdown section
+    lines = [f"### `{operation_id}`", ""]
+
+    if summary:
+        lines.append(summary)
+        lines.append("")
+
+    if code_sample:
+        lines.append(code_sample)
+        lines.append("")
+
+    lines.append(f"Docs: {docs_link}")
+    lines.append("")
+    lines.append("---")
+    lines.append("")
+
+    return "\n".join(lines)
+
+
+def get_ordered_operations(spec: dict[str, Any]) -> list[tuple[str, str, str, dict[str, Any]]]:
+    """Get operations in the specified order."""
+    # Specified order from the Linear issue
+    operation_order = [
+        "search",
+        "predictions.create",
+        "predictions.get",
+        "predictions.list",
+        "predictions.cancel",
+        "models.create",
+        "models.get",
+        "models.list",
+        "models.search",
+        "models.delete",
+        "models.examples.list",
+        "models.predictions.create",
+        "models.readme.get",
+        "models.versions.get",
+        "models.versions.list",
+        "models.versions.delete",
+        "collections.get",
+        "collections.list",
+        "deployments.create",
+        "deployments.get",
+        "deployments.list",
+        "deployments.update",
+        "deployments.delete",
+        "deployments.predictions.create",
+        "files.list",
+        "files.create",
+        "files.delete",
+        "files.get",
+        "files.download",
+        "trainings.create",
+        "trainings.get",
+        "trainings.list",
+        "trainings.cancel",
+        "hardware.list",
+        "account.get",
+        "webhooks.default.secret.get",
+    ]
+
+    operations: dict[str, tuple[str, str, str, dict[str, Any]]] = {}
+
+    # Extract all operations from paths
+    for path, path_obj in spec.get("paths", {}).items():
+        for method in ["get", "post", "put", "patch", "delete"]:
+            if method in path_obj:
+                operation = path_obj[method]
+                op_id = extract_operation_id(path, method, operation)
+
+                # Try to match with our ordered list using multiple strategies
+                matched_name = None
+
+                # Strategy 1: Direct operationId match
+                if op_id in operation_order:
+                    matched_name = op_id
+
+                # Strategy 2: Case-insensitive exact match
+                if not matched_name:
+                    for ordered_name in operation_order:
+                        if op_id.lower() == ordered_name.lower():
+                            matched_name = ordered_name
+                            break
+
+                # Strategy 3: Convert ordered name to possible operation IDs
+                if not matched_name:
+                    for ordered_name in operation_order:
+                        # e.g., "predictions.create" might be "predictionsCreate" or "predictions_create"
+                        variants = [
+                            ordered_name.replace(".", "_"),
+                            ordered_name.replace(".", ""),
+                            "".join(word.capitalize() if i > 0 else word for i, word in enumerate(ordered_name.split("."))),
+                        ]
+
+                        if op_id in variants or any(v.lower() == op_id.lower() for v in variants):
+                            matched_name = ordered_name
+                            break
+
+                # Strategy 4: Match by path structure and method
+                if not matched_name:
+                    for ordered_name in operation_order:
+                        ordered_parts = ordered_name.split(".")
+                        if len(ordered_parts) >= 2:
+                            resource = ordered_parts[0]
+                            action = ordered_parts[-1]
+
+                            # Check various path patterns
+                            path_lower = path.lower()
+                            if (resource in path_lower and
+                                ((action == "create" and method == "post") or
+                                 (action == "get" and method == "get" and "{" in path) or
+                                 (action == "list" and method == "get" and "{" not in path) or
+                                 (action == "update" and method in ["put", "patch"]) or
+                                 (action == "delete" and method == "delete") or
+                                 (action == "cancel" and method == "post" and "cancel" in path) or
+                                 (action == "search" and method == "get" and "search" in path))):
+                                matched_name = ordered_name
+                                break
+
+                key = matched_name or op_id
+                operations[key] = (op_id, path, method, operation)
+
+    # Order operations according to the specified list
+    ordered = []
+    added_keys = set()
+
+    for name in operation_order:
+        if name in operations:
+            ordered.append(operations[name])
+            added_keys.add(name)
+
+    # Add any remaining operations not in the ordered list
+    for key, value in operations.items():
+        if key not in added_keys:
+            ordered.append(value)
+
+    return ordered
+
+
+def generate_api_docs(spec: dict[str, Any]) -> str:
+    """Generate the API operations documentation."""
+    lines = []
+    operations = get_ordered_operations(spec)
+
+    # Generate sorted list of operations at the top
+    lines.append("Available operations:")
+    lines.append("")
+    for op_id, _path, _method, _operation in operations:
+        # Create anchor link from operation_id
+        anchor = op_id.lower().replace('.', '').replace('_', '')
+        lines.append(f"- [`{op_id}`](#{anchor})")
+    lines.append("")
+
+    # Generate detailed documentation for each operation
+    for op_id, _path, _method, operation in operations:
+        lines.append(format_operation(op_id, operation))
+
+    return "\n".join(lines)
+
+
+def update_api_md():
+    """Main function to update api.md file."""
+    # Paths
+    project_root = Path(__file__).parent.parent.parent
+    template_path = project_root / "api-template.md"
+    output_path = project_root / "api.md"
+
+    # Download and parse OpenAPI spec
+    try:
+        spec = download_openapi_spec()
+    except Exception as e:
+        print(f"Error downloading OpenAPI spec: {e}", file=sys.stderr)
+        sys.exit(1)
+
+    # Read template
+    if not template_path.exists():
+        print(f"Template file not found: {template_path}", file=sys.stderr)
+        sys.exit(1)
+
+    with open(template_path, "r") as f:
+        template_content = f.read()
+
+    # Generate API operations documentation
+    api_docs = generate_api_docs(spec)
+
+    # Replace placeholder in template
+    if "" not in template_content:
+        print("Warning:  placeholder not found in template", file=sys.stderr)
+        final_content = template_content + "\n\n" + api_docs
+    else:
+        final_content = template_content.replace("", api_docs)
+
+    # Write output
+    with open(output_path, "w") as f:
+        f.write(final_content)
+
+    print(f"Successfully updated {output_path}")
+
+
+if __name__ == "__main__":
+    update_api_md()