From 89451f4ea21819de806057cd94dd80a52dae97b4 Mon Sep 17 00:00:00 2001 From: Andrew Nguonly Date: Wed, 2 Jul 2025 14:30:00 -0700 Subject: [PATCH] docs: Add LGP control plane API docs page (#5319) Add control plane API docs page. --- docs/docs/cloud/reference/api/api_ref.md | 8 +- .../reference/api/api_ref_control_plane.md | 247 ++++++++++++++++++ docs/docs/concepts/langgraph_control_plane.md | 8 +- docs/mkdocs.yml | 1 + 4 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 docs/docs/cloud/reference/api/api_ref_control_plane.md diff --git a/docs/docs/cloud/reference/api/api_ref.md b/docs/docs/cloud/reference/api/api_ref.md index 13b30acf2..c2d6a10a7 100644 --- a/docs/docs/cloud/reference/api/api_ref.md +++ b/docs/docs/cloud/reference/api/api_ref.md @@ -1,12 +1,12 @@ -# API Reference +# LangGraph Server API Reference -The LangGraph Platform API reference is available with each deployment at the `/docs` URL path (e.g. `http://localhost:8124/docs`). +The LangGraph Server API reference is available within each deployment at the `/docs` endpoint (e.g. `http://localhost:8124/docs`). Click here to view the API reference. ## Authentication -For deployments to LangGraph Platform, authentication is required. Pass the `X-Api-Key` header with each request to the LangGraph Platform API. The value of the header should be set to a valid LangSmith API key for the organization where the API is deployed. +For deployments to LangGraph Platform, authentication is required. Pass the `X-Api-Key` header with each request to the LangGraph Server. The value of the header should be set to a valid LangSmith API key for the organization where the LangGraph Server is deployed. Example `curl` command: ```shell @@ -18,5 +18,5 @@ curl --request POST \ "metadata": {}, "limit": 10, "offset": 0 -}' +}' ``` diff --git a/docs/docs/cloud/reference/api/api_ref_control_plane.md b/docs/docs/cloud/reference/api/api_ref_control_plane.md new file mode 100644 index 000000000..b6f3827ae --- /dev/null +++ b/docs/docs/cloud/reference/api/api_ref_control_plane.md @@ -0,0 +1,247 @@ +# LangGraph Control Plane API Reference + +The LangGraph Control Plane API is used to programmatically create and manage LangGraph Server deployments. For example, the APIs can be orchestrated to create custom CI/CD workflows. + +Click here to view the API reference. + +## Host + +LangGraph Control Plane hosts for Cloud SaaS data regions: + +| US | EU | +|----|----| +| `https://api.host.langchain.com` | `https://eu.api.host.langchain.com` | + +**Note**: Self-hosted deployments of LangGraph Platform will have a custom host for the LangGraph Control Plane. + +## Authentication + +To authenticate with the LangGraph Control Plane API, set the `X-Api-Key` header to a valid LangSmith API key. + +Example `curl` command: +```shell +curl --request GET \ + --url http://localhost:8124/v2/deployments \ + --header 'X-Api-Key: LANGSMITH_API_KEY' +``` + +## Versioning + +Each endpoint path is prefixed with a version (e.g. `v1`, `v2`). + +## Quick Start + +1. Call `POST /v2/deployments` to create a new Deployment. The response body contains the Deployment ID (`id`) and the ID of the latest (and first) revision (`latest_revision_id`). +1. Call `GET /v2/deployments/{deployment_id}` to retrieve the Deployment. Set `deployment_id` in the URL to the value of Deployment ID (`id`). +1. Poll for revision `status` until `status` is `DEPLOYED` by calling `GET /v2/deployments/{deployment_id}/revisions/{latest_revision_id}`. +1. Call `PATCH /v2/deployments/{deployment_id}` to update the deployment. + +## Example Code +Below is example Python code that demonstrates how to orchestrate the LangGraph Control Plane APIs to create a deployment, update the deployment, and delete the deployment. +```python +import os +import time + +import requests +from dotenv import load_dotenv + + +load_dotenv() + +# required environment variables +CONTROL_PLANE_HOST = os.getenv("CONTROL_PLANE_HOST") +LANGSMITH_API_KEY = os.getenv("LANGSMITH_API_KEY") +INTEGRATION_ID = os.getenv("INTEGRATION_ID") +MAX_WAIT_TIME = 1800 # 30 mins + + +def get_headers() -> dict: + """Return common headers for requests to LangGraph Control Plane API.""" + return { + "X-Api-Key": LANGSMITH_API_KEY, + } + + +def create_deployment() -> str: + """Create deployment. Return deployment ID.""" + headers = get_headers() + headers["Content-Type"] = "application/json" + + deployment_name = "my_deployment" + + request_body = { + "name": deployment_name, + "source": "github", + "source_config": { + "integration_id": INTEGRATION_ID, + "repo_url": "https://github.com/langchain-ai/langgraph-example", + "deployment_type": "dev", + "build_on_push": False, + "custom_url": None, + "resource_spec": None, + }, + "source_revision_config": { + "repo_ref": "main", + "langgraph_config_path": "langgraph.json", + "image_uri": None, + }, + "secrets": [ + { + "name": "OPENAI_API_KEY", + "value": "test_openai_api_key", + }, + { + "name": "ANTHROPIC_API_KEY", + "value": "test_anthropic_api_key", + }, + { + "name": "TAVILY_API_KEY", + "value": "test_tavily_api_key", + }, + ], + } + + response = requests.post( + url=f"{CONTROL_PLANE_HOST}/v2/deployments", + headers=headers, + json=request_body, + ) + + if response.status_code != 201: + raise Exception(f"Failed to create deployment: {response.text}") + + deployment_id = response.json()["id"] + print(f"Created deployment {deployment_name} ({deployment_id})") + return deployment_id + + +def get_deployment(deployment_id: str) -> dict: + """Get deployment.""" + response = requests.get( + url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}", + headers=get_headers(), + ) + + if response.status_code != 200: + raise Exception(f"Failed to get deployment ID {deployment_id}: {response.text}") + + return response.json() + + +def list_revisions(deployment_id: str) -> list[dict]: + """List revisions. + + Return list is sorted by created_at in descending order (latest first). + """ + response = requests.get( + url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}/revisions", + headers=get_headers(), + ) + + if response.status_code != 200: + raise Exception( + f"Failed to list revisions for deployment ID {deployment_id}: {response.text}" + ) + + return response.json() + + +def get_revision( + deployment_id: str, + revision_id: str, +) -> dict: + """Get revision.""" + response = requests.get( + url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}/revisions/{revision_id}", + headers=get_headers(), + ) + + if response.status_code != 200: + raise Exception(f"Failed to get revision ID {revision_id}: {response.text}") + + return response.json() + + +def patch_deployment(deployment_id: str) -> None: + """Patch deployment.""" + headers = get_headers() + headers["Content-Type"] = "application/json" + + response = requests.patch( + url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}", + headers=headers, + json={ + "source_config": { + "build_on_push": True, + }, + "source_revision_config": { + "repo_ref": "main", + "langgraph_config_path": "langgraph.json", + }, + }, + ) + + if response.status_code != 200: + raise Exception(f"Failed to patch deployment: {response.text}") + + print(f"Patched deployment ID {deployment_id}") + + +def wait_for_deployment(deployment_id: str, revision_id: str) -> None: + """Wait for revision status to be DEPLOYED.""" + start_time = time.time() + revision, status = None, None + while time.time() - start_time < MAX_WAIT_TIME: + revision = get_revision(deployment_id, revision_id) + status = revision["status"] + if status == "DEPLOYED": + break + elif "FAILED" in status: + raise Exception(f"Revision ID {revision_id} failed: {revision}") + + print(f"Waiting for revision ID {revision_id} to be DEPLOYED...") + time.sleep(60) + + if status != "DEPLOYED": + raise Exception( + f"Timeout waiting for revision ID {revision_id} to be DEPLOYED: {revision}" + ) + + +def delete_deployment(deployment_id: str) -> None: + """Delete deployment.""" + response = requests.delete( + url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}", + headers=get_headers(), + ) + + if response.status_code != 204: + raise Exception( + f"Failed to delete deployment ID {deployment_id}: {response.text}" + ) + + print(f"Deployment ID {deployment_id} deleted") + + +if __name__ == "__main__": + # create deployment and get the latest revision + deployment_id = create_deployment() + revisions = list_revisions(deployment_id) + latest_revision = revisions["resources"][0] + latest_revision_id = latest_revision["id"] + + # wait for latest revision to be DEPLOYED + wait_for_deployment(deployment_id, latest_revision_id) + + # patch the deployment and get the latest revision + patch_deployment(deployment_id) + revisions = list_revisions(deployment_id) + latest_revision = revisions["resources"][0] + latest_revision_id = latest_revision["id"] + + # wait for latest revision to be DEPLOYED + wait_for_deployment(deployment_id, latest_revision_id) + + # delete the deployment + delete_deployment(deployment_id) +``` \ No newline at end of file diff --git a/docs/docs/concepts/langgraph_control_plane.md b/docs/docs/concepts/langgraph_control_plane.md index 2e3ecc84d..f3562516c 100644 --- a/docs/docs/concepts/langgraph_control_plane.md +++ b/docs/docs/concepts/langgraph_control_plane.md @@ -26,7 +26,7 @@ The Control Plane UI is embedded in [LangSmith](https://docs.smith.langchain.com ## Control Plane API -This section describes data model of the control plane API. The API is used to create, update, and delete deployments. However, they are not publicly accessible. +This section describes the data model of the control plane API. The API is used to create, update, and delete deployments. See the [control plane API reference](../cloud/reference/api/api_ref_control_plane.md) for more details. ### Deployment @@ -34,11 +34,7 @@ A deployment is an instance of a LangGraph Server. A single deployment can have ### Revision -A revision is an iteration of a deployment. When a new deployment is created, an initial revision is automatically created. To deploy code changes or update environment variables for a deployment, a new revision must be created. - -### Environment Variable - -Environment variables are set for a deployment. All environment variables are stored as secrets (i.e. saved in a secrets store). +A revision is an iteration of a deployment. When a new deployment is created, an initial revision is automatically created. To deploy code changes or update secrets for a deployment, a new revision must be created. ## Control Plane Features diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 34a352fb0..69368662b 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -259,6 +259,7 @@ nav: - MCP Adapters: reference/mcp.md - LangGraph Platform: - Server API: cloud/reference/api/api_ref.md + - Control Plane API: cloud/reference/api/api_ref_control_plane.md - CLI: cloud/reference/cli.md - SDK (Python): cloud/reference/sdk/python_sdk_ref.md - SDK (JS/TS): cloud/reference/sdk/js_ts_sdk_ref.md