# Use Apideck with LangGraph

Build a graph that reads one invoice and stops. Start with an explicit transition to the end state before adding model-driven branches or approval steps.

[Open the runnable Python example](https://github.com/apideck-io/developer-docs/tree/Gdewilde/use-case-driven/examples/ai-frameworks/langgraph_example.py) · [Compare framework guides](/guides/ai-frameworks)

## Start with a local check

Use Python 3.12 and [uv](https://docs.astral.sh/uv/). Download or clone the [example directory](https://github.com/apideck-io/developer-docs/tree/Gdewilde/use-case-driven/examples/ai-frameworks) with its shared helper files. Python scripts declare exact dependency versions for uv; the Node example includes a lockfile. These dependencies belong to the example, not your frontend bundle.

```bash
cd examples/ai-frameworks
uv run --python 3.12 langgraph_example.py
```

The default mode runs the framework wiring against a local fixture. It makes no Apideck request and needs no model key. Expected output:

```json
{"status":"fixture","records":1,"has_more":false}
```

This proves the example can load and invoke its tool or graph. It does **not** verify customer access or model behavior. See the [verification record](https://github.com/apideck-io/developer-docs/tree/Gdewilde/use-case-driven/examples/ai-frameworks/VERIFICATION.md) for the exact checks and limits.

## Connect a customer

[Create a Vault connection](/guides/vault) for your sandbox customer. Confirm the selected connector supports [listing accounting invoices](/apis/accounting/reference/invoices/invoicesAll). Set these server-side environment variables in the example process:

| Variable | Purpose |
| --- | --- |
| `APIDECK_API_KEY` | Your application API key; inject it through an untracked environment or secret manager |
| `APIDECK_APP_ID` | The application that owns the key |
| `APIDECK_CONSUMER_ID` | Your authenticated customer's consumer |
| `APIDECK_SERVICE_ID` | The connector, such as `xero` |

Resolve the consumer from your application's authenticated user. Do not let the model choose a consumer or put credentials in a prompt, public URL or browser bundle.

These examples use **Apideck MCP** at `https://mcp.apideck.dev/mcp?scopes=read&lock_identity=true`. The MCP-specific key header is `x-apideck-api-key`. Read scope and identity locking require server 0.20.1 or later. [Docs MCP](/mcp#docs-mcp) serves documentation; it does not execute connected API operations and needs no Apideck key.

## Discover and validate the operation

```bash
uv run --python 3.12 langgraph_example.py --discover
```

The helper loads the dynamic server tools, searches accounting invoices with `list_tools`, then checks `accounting-invoices-all` through `describe_tool_input`. It validates `limit: 1` and `fields: "id"` against the returned schema before execution. Discovery returns `schema_verified` with `ledger_access_verified: false`; a listed operation is not proof that your connector supports it.

## Read one invoice

After checking the customer and connector, explicitly run:

```bash
uv run --python 3.12 langgraph_example.py --read
```

This makes one bounded downstream request. The summary contains `status`, `records` (zero or one), and `has_more`. Invoice identifiers, payloads and cursors are not printed or passed to a model. The sample does not follow pagination or retry failures.

Verify the consumer, connector and request in [Logs](/logs). Zero records is a valid result, but does not prove you selected the intended account. The example has a 60-second CLI deadline; a timeout is not evidence that the server never executed the request.

## Add it to your agent

The sample compiles a `StateGraph` with one read node and an explicit `END` edge. State contains the sanitized summary, not invoice payloads. The recursion limit bounds graph transitions; the reader independently enforces one downstream attempt. If you add checkpointing, do not replay an uncertain call automatically when resuming.

The following wiring uses files from the sample directory. Agent construction is shown separately from the offline check; model-driven execution needs provider configuration and has not been live-tested here.

```python
from common import make_reader
from langgraph_example import build_graph

# Run inside your server async request handler.
async def check_invoice():
    graph = build_graph(make_reader())
    return await graph.ainvoke(
        {"result": ""}, config={"recursion_limit": 3}
    )
```

Keep the shared helper alongside the example. Its fixed operation and argument-free tool prevent the model from widening the requested fields or selecting another customer. The general MCP discovery `scope` filter only narrows search results; use server scope, identity controls and application authorization for execution restrictions.

The sample's one-attempt budget is in memory. A process restart resets it. Production workers need durable request state when retries or restarts could replay an operation. Keep raw MCP payloads out of provider tracing and logs; only the sanitized tool result should enter model context.

## Recover deliberately

| Result | Action |
| --- | --- |
| Missing environment | Set all four values in the same server process |
| Schema or tool mismatch | Check the server mode and pinned framework versions; do not guess input fields |
| 401 | Check key/application pairing and reconnect the customer where needed |
| 403 | Ask the customer's administrator to grant the required permission |
| 429 | Inspect retry guidance; this example stops rather than retrying automatically |
| Timeout or uncertain result | Inspect parent and child requests in Logs before starting another attempt |

See [MCP verification and recovery](/guides/mcp-verification-and-recovery) for discovery, execution and revocation checks. Removing a client config does not revoke the underlying key or provider connection.

## Frequently asked questions

### Does the default check use a model?

No. It exercises the framework's tool or graph interface with a fixture. A model-driven agent needs its provider configuration and separate evaluation.

### Can I use this with CRM or HRIS?

Yes, the architecture applies to other APIs. Discover the required operation, inspect its schema and create a separate bounded tool for it. This particular sample only reads accounting invoices; it is not a compatibility claim for every connector.

### Is this a benchmark result?

No. Connection checks establish integration behavior. Model accuracy, latency and token/cost comparisons need a separate controlled evaluation; the Experience Lab does not yet have scored runs for this framework example.

Continue with [the month-end close agent](/guides/month-end-close-agent), [security and data handling](/guides/security-and-data-handling), or the [official LangGraph documentation](https://docs.langchain.com/oss/python/langgraph/graph-api).
