TL;DR: Reach any external API from a playbook with an HTTP step for a single request, a Code step when you need transforms or an SDK, or a reusable custom HTTP tool when several playbooks hit the same endpoint. Read credentials from Secrets with ${VAR} and never hardcode them.
Developers integrating REST APIs or SDKs that don't have an MCP server.
| Need | Use |
|---|---|
| One request with a clear URL/method/body | HTTP step |
| Data shaping, batching, conditionals, or an SDK | Code step |
| The same call reused across playbooks | Custom HTTP tool |
Add an HTTP step with the method, URL, headers, and body. Pull the token from Secrets:
POST https://api.example.com/v1/orders
Authorization: Bearer ${EXAMPLE_API_KEY}
Content-Type: application/json
{ "customerId": "{{input.customerId}}" }
Use a Code step when you need an SDK or non-trivial logic. Read secrets from the environment:
const res = await fetch("https://api.example.com/v1/orders", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.EXAMPLE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ customerId: input.customerId }),
});
const order = await res.json();
return { orderId: order.id };
Code steps can install and import packages, so you can call vendor SDKs (including AI SDKs) the same way you would in any service.
When multiple playbooks call the same endpoint, define a custom HTTP tool once (name, method, URL, parameter schema, auth) and reference it from any playbook. This keeps the request definition in one place and gives the model a clear, typed tool to call.
${VAR} — never inline keys.