Skip to content

Install an integration, connect a Hubspot account, mint a link token from your backend, open the Truto Link UI from your frontend, and make your first Unified API call.

Setting up Truto with a coding agent

If you're using Cursor, Claude Code, or any other agent that supports the Agent Skills convention, install the Truto skills pack and the Truto CLI once — the agent then knows how to wire Truto into your codebase from a single prompt.

1. Install the Truto skills pack

npx skills add trutohq/truto-skills

This installs five skills your agent can call into:

Skill What it covers
truto Application code that calls the Truto API — link-token routes, unified/proxy/custom calls, webhook handlers
truto-link-sdk Embedding the Truto connection UI in a frontend with @truto/truto-link-sdk
truto-cli Driving the Truto CLI for setup, exploration, and debugging in the terminal
truto-jsonata Writing JSONata for unified-API mappings, sync jobs, workflows, RapidForms
truto-api-conventions Truto API base URL, auth header, URL patterns, pagination, idempotency

2. Install the Truto CLI

curl -fsSL https://cli.truto.one/install.sh | bash
truto login --token "$TRUTO_API_TOKEN"
truto whoami -o json

The installer drops the truto binary in ~/.truto/bin. TRUTO_API_TOKEN is an API token created from the Truto Dashboard — see Generating an API token.

truto whoami -o json prints your team and environment. If you see your team name, the agent and the CLI are ready.

3. Prompts to drop into your agent

Once the skills and CLI are in place, paste any of these into your agent. Each one uses skills installed in step 1 and is enough on its own.

Set up Truto in this codebase. Add a POST /api/truto/link-token route on the
backend that mints a link token for a given tenantId, and a button in the
frontend that opens Truto Link with @truto/truto-link-sdk. Use the truto and
truto-link-sdk skills.
Add a webhook handler at POST /webhooks/truto. Switch on event_type. When we
receive integrated_account:active, mark the tenant's connection as ready and
store the integrated_account_id. Handle integrated_account:post_install_error
and integrated_account:validation_error too. Use the truto skill.
Add a server-side helper that lists CRM contacts for a given
integrated_account_id by calling GET /unified/crm/contacts on api.truto.one,
then walks pages with next_cursor. Use the truto skill.

Asking the docs with AI

The Truto Docs MCP server lets any AI assistant search and read these docs directly. No API key, no install — point your client at the endpoint and ask questions.

https://docs-mcp.truto.one/mcp

Pick your client below and add the config.

Claude Desktop

Claude Desktop connects to remote MCP servers through an npx bridge. Add this to your claude_desktop_config.json (Settings > Developer > Edit Config):

{
  "mcpServers": {
    "truto_docs": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://docs-mcp.truto.one/mcp"]
    }
  }
}

Fully quit and reopen Claude Desktop after saving.

Cursor

Cursor supports remote MCP servers natively. Add this to .cursor/mcp.json in your project or ~/.cursor/mcp.json globally:

{
  "mcpServers": {
    "truto_docs": {
      "url": "https://docs-mcp.truto.one/mcp"
    }
  }
}

Claude Code

claude mcp add --transport http truto_docs https://docs-mcp.truto.one/mcp

Add --scope user to make it available across all projects.

VS Code + Copilot

Add this to .vscode/mcp.json in your workspace:

{
  "servers": {
    "truto_docs": {
      "type": "http",
      "url": "https://docs-mcp.truto.one/mcp"
    }
  }
}

Windsurf

Add this to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "truto_docs": {
      "serverUrl": "https://docs-mcp.truto.one/mcp"
    }
  }
}

Setting up Truto by hand

The rest of this page is the same flow without an agent — install integrations from the Dashboard, generate an API token, mint a link token from your backend, and call the unified API yourself. Use it as a step-by-step walkthrough on its own, or as a reference for what the agent prompts above are doing.

Install your first integration

Integrations are what enable you to connect your customer's apps to Truto.

Your Truto account by default doesn't come with any Integrations installed and any integration you need to use needs to be installed manually before connecting an account for it.

You can head on over to Available integrations list to see the integrations available for installation.

In this guide, we'll install the Hubspot integration. You can install an integration by clicking the Install button and selecting the environments you want to install the integration in.

Integration list

Integration install modal

Info

Environments are logical grouping of resources in your Truto account. They help you try out things in isolation without affecting your production data.

Install the Unified API for CRMs

After installing Hubspot, we will install the Unified API for CRMs which will enable us to query the Hubspot API and get responses in a unified format. This Unified API can also be used with other CRMs.

Head on over to Available Unified API list and install the CRM Unified API. Installing Unified APIs is similar to installing Integrations.

Unified API list

Unified API install modal

Generate an API token

You can follow our guide to generate an API token here.

Connect your first Hubspot account

Via the dashboard

Go to Integrated accounts tab and click the Connect Account button on the top right corner of the page.

Enter a value in the Tenant ID field and click Get connection link.

Head on over to the link shown and select Hubspot. After you go through the OAuth flow, you can come back to the Integrated accounts tab and close the connection modal. An Integrated account would have been created.

From your own app

Connecting an account from your own app is two steps:

  1. Backend: mint a link token by POSTing to https://api.truto.one/link-token with your API token.
  2. Frontend: open the Truto Link UI with @truto/truto-link-sdk and that link token.

Step 1. Mint a link token from your backend

TRUTO_API_TOKEN is a server-side secret. Read it from an env var; never ship it to the browser. The same route handles new connections (tenant_id) and reconnections (integrated_account_id) — wiring both from the start prevents users from creating duplicate accounts when an existing connection fails.

curl --location 'https://api.truto.one/link-token' \
  --header 'Content-Type: application/json' \
  --header "Authorization: Bearer $TRUTO_API_TOKEN" \
  --data '{
    "tenant_id": "acme-1"
  }'
import express from 'express';
 
const app = express();
app.use(express.json());
 
app.post('/api/truto/link-token', async (req, res) => {
  const { tenantId, integratedAccountId } = req.body;
 
  const body = integratedAccountId
    ? { integrated_account_id: integratedAccountId, persist_previous_context: true }
    : { tenant_id: tenantId };
 
  const response = await fetch('https://api.truto.one/link-token', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.TRUTO_API_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });
 
  const { link_token } = await response.json();
  res.json({ linkToken: link_token });
});
// app/api/truto/link-token/route.ts
export async function POST(req: Request) {
  const { tenantId, integratedAccountId } = await req.json();
 
  const body = integratedAccountId
    ? { integrated_account_id: integratedAccountId, persist_previous_context: true }
    : { tenant_id: tenantId };
 
  const response = await fetch('https://api.truto.one/link-token', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.TRUTO_API_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });
 
  const { link_token } = await response.json();
  return Response.json({ linkToken: link_token });
}
import { Hono } from 'hono';
 
type Env = { TRUTO_API_TOKEN: string };
const app = new Hono<{ Bindings: Env }>();
 
app.post('/api/truto/link-token', async (c) => {
  const { tenantId, integratedAccountId } = await c.req.json();
 
  const body = integratedAccountId
    ? { integrated_account_id: integratedAccountId, persist_previous_context: true }
    : { tenant_id: tenantId };
 
  const response = await fetch('https://api.truto.one/link-token', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${c.env.TRUTO_API_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });
 
  const { link_token } = await response.json();
  return c.json({ linkToken: link_token });
});
 
export default app;
// npm install @truto/truto-ts-sdk
import TrutoApi from '@truto/truto-ts-sdk';
 
const truto = new TrutoApi({
  token: process.env.TRUTO_API_TOKEN!,
});
 
// New connection
const { link_token } = await truto.linkToken.createForNewIntegration({
  tenant_id: 'acme-1',
});
 
// Reconnect an existing account
const reconnect = await truto.linkToken.createForExistingIntegratedAccount({
  integrated_account_id: 'existing-account-id',
});
import os
import requests
from flask import Flask, request, jsonify
 
app = Flask(__name__)
 
@app.post("/api/truto/link-token")
def link_token():
    payload = request.get_json() or {}
    tenant_id = payload.get("tenantId")
    integrated_account_id = payload.get("integratedAccountId")
 
    body = (
        {"integrated_account_id": integrated_account_id, "persist_previous_context": True}
        if integrated_account_id
        else {"tenant_id": tenant_id}
    )
 
    response = requests.post(
        "https://api.truto.one/link-token",
        headers={
            "Authorization": f"Bearer {os.environ['TRUTO_API_TOKEN']}",
            "Content-Type": "application/json",
        },
        json=body,
        timeout=10,
    )
    response.raise_for_status()
    return jsonify(linkToken=response.json()["link_token"])
# pip install truto-python-sdk
import asyncio, os
from truto_python_sdk import TrutoApi
 
async def main():
    truto = TrutoApi(token=os.environ["TRUTO_API_TOKEN"])
 
    # New connection
    new_token = await truto.link_tokens.create({"tenant_id": "acme-1"})
 
    # Reconnect an existing account
    reconnect_token = await truto.link_tokens.create({
        "integrated_account_id": "existing-account-id",
        "persist_previous_context": True,
    })
 
    print(new_token, reconnect_token)
 
asyncio.run(main())

Response:

{
  "link_token": "e73c7b9b-2e4d-47d1-b5d2-83441fd24e4c"
}
Warning

TRUTO_API_TOKEN must stay on the server. Never expose it to the browser, and never hardcode it in client bundles. Link tokens are short-lived, single-use credentials safe for the frontend; the API token isn't.

Step 2. Open Truto Link from your frontend

Install the SDK:

npm install @truto/truto-link-sdk

Call your backend route to get a link token, then hand it to authenticate(). The same call works for new connections and reconnections — the difference is in the body your backend posts.

import authenticate from '@truto/truto-link-sdk';
 
async function getLinkToken(body: Record<string, string>) {
  const res = await fetch('/api/truto/link-token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  const { linkToken } = await res.json();
  return linkToken;
}
 
async function openTrutoLink(linkToken: string) {
  try {
    const result = await authenticate(linkToken);
    console.log('Connected:', result);
    // { result: 'success', integration: 'hubspot', integrated_account_id: '...' }
    return result;
  } catch (err) {
    if (err === 'closed') {
      console.log('User closed the connection dialog');
    } else {
      console.error('Connection failed:', err);
    }
    throw err;
  }
}
 
// New connection
const linkToken = await getLinkToken({ tenantId: 'acme-1' });
await openTrutoLink(linkToken);
 
// Reconnect an existing account
const reconnectToken = await getLinkToken({ integratedAccountId: 'existing-account-id' });
await openTrutoLink(reconnectToken);

If you'd rather not embed the SDK, you can hand the link token to Truto's hosted connection page directly:

https://app.truto.one/connect-account?link_token=<link-token-from-previous-step>

See Embedding the Truto Link SDK for popup, iframe, and same-window options, and the full request schema for POST /link-token.

Make your first API request

You can checkout the API methods available for the newly connected Hubspot Integrated account by going to its detail page and switching to the Unified API tab. You can also check out the API reference page for the CRM Unified API in the docs.

Use the same API token in the Bearer authorization and make a request to one of the URLs.

API Reference

To know more about how our APIs work, you can checkout our API Reference.