Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vocobase.com/llms.txt

Use this file to discover all available pages before exploring further.

B2B2B — Customer-Scoped Tool Connections

If you are a partner with downstream customers of your own, every customer needs to authorize tools (Google Sheets, Slack, Shopify, Cal.com, Zendesk, LeadSquared, etc.) with their own credentials, isolated from each other. The Vocobase B2B2B API gives each of your customers their own identity (PartnerCustomer) and their own connections, while you remain the single billing and integration boundary with us.
Mental model. Vocobase ↔ you (the partner) ↔ your customers. You authenticate to Vocobase with your rg_live_… API key. Your customers never log in to Vocobase. They authorize tools through one-time hosted URLs that you mint and hand off to them.

When you need this

  • You’re building a vertical app on top of Vocobase and need to serve multiple downstream customer accounts.
  • Each customer has their own Google Sheets / Slack / LSQ / Calendly / Shopify account and they should not share tokens with you or with each other.
  • You want to bind agents to a specific customer’s connection at runtime.
If you are a single-team partner using your own tool credentials, you do not need this surface — connect tools directly under your account from the dashboard at /dashboard/settings/integrations.

Glossary

TermWhat it is
PartnerYou. Holds the rg_live_… API key, billing relationship, agent quota.
Partner CustomerOne of your downstream customers. Has a stable external_id you choose.
ConnectorA tool definition on the Vocobase platform (Google Sheets, Slack, Cal.com, etc.). Admin curates which connectors your account can use.
ConnectionA specific authorization of a connector for a specific owner. Owners are mutually exclusive — either you (the partner user) OR a single PartnerCustomer.
Connect linkA one-time URL you mint and hand to a customer. They open it, complete OAuth (or paste an API key), and tokens land against the PartnerCustomer.

Discover available connectors

Before you can offer connectors to your customers, list the catalog your account has access to. Admin controls visibility per partner — if a connector you expect is missing, ask the Vocobase team to grant it.
curl https://api.vocobase.com/api/v2/connectors \
  -H "Authorization: Bearer rg_live_abc123def456ghi789jkl012"
Response
{
  "success": true,
  "data": {
    "connectors": [
      {
        "id": "td_01h…",
        "slug": "google_sheets",
        "name": "Google Sheets",
        "description": "Read and write rows to spreadsheets your customers own.",
        "provider": "GOOGLE",
        "status": "ACTIVE",
        "oauth_scopes": ["https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive.file"],
        "capabilities": { "functions": ["append_row", "read_range"] }
      },
      {
        "slug": "calcom",
        "name": "Cal.com",
        "provider": "CALCOM",
        "status": "ACTIVE",
        "oauth_scopes": [],
        "capabilities": { "functions": ["create_booking", "list_event_types"] }
      }
    ]
  }
}
GET /api/v2/connectors/:slug returns a single connector by slug — useful when you already know which one you want.
Only ACTIVE connectors are returned. The dashboard may show COMING_SOON previews for partners; the API filters those out because they have no working programmatic OAuth path.

Create a customer

Customers are identified by a stable external_id of your choice — your own primary key for that downstream account. Re-creating with the same (partner, external_id) pair is idempotent, so a sync that runs on every deploy is safe.
curl -X POST https://api.vocobase.com/api/v2/customers \
  -H "Authorization: Bearer rg_live_abc123def456ghi789jkl012" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "acct_customer_42",
    "name": "Acme Health",
    "email": "ops@customer.example",
    "metadata": { "tier": "enterprise", "country": "IN" }
  }'
Response
{
  "success": true,
  "data": {
    "id": "pc_01h…",
    "external_id": "acct_customer_42",
    "name": "Acme Health",
    "email": "ops@customer.example",
    "metadata": { "tier": "enterprise", "country": "IN" },
    "status": "ACTIVE",
    "created_at": "2026-05-10T08:14:22.000Z",
    "updated_at": "2026-05-10T08:14:22.000Z"
  }
}
FieldRequiredNotes
external_idyes1–200 chars. Stable, idempotent key in your namespace.
nameyes1–200 chars. Human-readable label shown to your team and to admins.
emailnoOptional contact email. Used only for display.
metadatanoFree-form JSON. Stored as-is; never used by Vocobase logic.

List, get, update, archive

GET    /api/v2/customers?cursor=&limit=&status=
GET    /api/v2/customers/:id
PATCH  /api/v2/customers/:id           # name | email | metadata
DELETE /api/v2/customers/:id           # archive — cascade-revokes all connections
DELETE is archive, not delete — the row stays for audit. Their tool connections are immediately revoked (tokens cleared, AgentTool bindings dropped). Archived customers cannot mint new connect-links until reactivated by Vocobase support.
This is the core handoff for OAuth-style connectors (Google Sheets, Slack, Shopify, etc.). You mint a one-time URL, hand it to your customer however you like (in-app button, email, SMS), and they complete authorization without ever touching your or our credentials.
[Your backend]                          [Vocobase]                       [Customer's browser]
     │                                        │                                  │
     │ POST /api/v2/customers/:id/connect-link│                                  │
     │   { tool_slug, redirect_uri }          │                                  │
     ├───────────────────────────────────────►│                                  │
     │                                        │ Mints one-time connect link      │
     │                                        │ TTL default 30min, max 24h       │
     │ ◄──────────────────────────────────────┤                                  │
     │ { url, expires_at }                    │                                  │
     │                                        │                                  │
     │ Hand `url` to your customer            │                                  │
     ├──────────────────────────────────────────────────────────────────────────►│
     │                                        │                                  │
     │                                        │ ◄──────────── click ────────────┤
     │                                        │ Redirects to OAuth provider      │
     │                                        │   (or renders API-key form for   │
     │                                        │   Cal.com/Calendly/Zendesk)      │
     │                                        │                                  │
     │                                        │ Customer authorizes              │
     │                                        │ Tokens land against PartnerCustomer
     │                                        │                                  │
     │                                        │ Redirects to your `redirect_uri` │
     │                                        │   ?status=ok&tool=…              │
     │                                        │   &connection_id=…               │
     ├──────────────────────────────────────────────────────────────────────────►│
curl -X POST "https://api.vocobase.com/api/v2/customers/pc_01h.../connect-link" \
  -H "Authorization: Bearer rg_live_abc123def456ghi789jkl012" \
  -H "Content-Type: application/json" \
  -d '{
    "tool_slug": "google_sheets",
    "redirect_uri": "https://app.partner.example/integrations/return",
    "expires_in_seconds": 1800
  }'
Response
{
  "success": true,
  "data": {
    "url": "https://api.vocobase.com/connect/9f3c…",
    "expires_at": "2026-05-10T08:44:22.000Z"
  }
}

redirect_uri rules

The redirect_uri is where the customer’s browser lands after authorization. Strict validation, intentionally:
  • Must be https://
  • Must NOT contain @, fragment (#…), or userinfo
  • Must use the default port (443)
  • Host must EXACT-match an entry in your allowed_redirect_hosts. If unset, falls back to the host of your webhook_url. Ask Vocobase to register additional hosts on your PartnerConfig.
A redirect_uri that fails validation returns 400 INVALID_REDIRECT_URI with a message explaining which rule was violated.

Callback contract

Vocobase appends query parameters to your redirect_uri. Reserved parameters:
ParamWhenValue
statusAlwaysok or error
toolOn successThe connector slug, e.g. google_sheets
connection_idOn successThe persistent connection ID (use to revoke later)
errorOn errorMachine-readable code (see table below)
Your existing query parameters in redirect_uri are preserved. Reserved keys overwrite.
Error codeMeaning
oauth_deniedCustomer rejected the OAuth consent screen.
customer_archivedThe customer was archived between mint and authorize. Re-create the customer, mint again.
invalid_stateThe session token expired or was already consumed. Mint a new one.
tool_not_found / tool_not_availableThe connector isn’t ACTIVE on your account.
provider_mismatchInternal mismatch between the requested tool and the OAuth provider returned.
connection_failedOAuth provider returned an error during code exchange.
token_smoke_test_failedShopify only — the issued token failed our connectivity smoke test.
invalid_hmacShopify only — the callback HMAC didn’t match.

Shopify

Shopify uses a per-shop OAuth handshake. The hosted page first prompts for the shop domain (mystore.myshopify.com), then redirects to Shopify. Other than the extra prompt, the flow is identical from your point of view — same connect-link mint, same callback contract.

Direct credential submission (no hosted UI)

For non-OAuth connectors (Cal.com, Calendly, Zendesk), you can skip the hosted handoff and submit credentials directly from your backend if your customer prefers to give them to you over phone/email.

Cal.com / Calendly — single API key

POST /api/v2/customers/:id/connections/api-key
Body: { "tool_slug": "calcom", "api_key": "cal_live_…" }
POST /api/v2/customers/:id/connections/api-key
Body: { "tool_slug": "calendly", "api_key": "eyJraWQ…" }

Zendesk — compound credential

POST /api/v2/customers/:id/connections/zendesk
Body: { "email": "alex@acme.example", "api_token": "<token>", "subdomain": "acme" }
Both endpoints return:
{
  "success": true,
  "data": { "connection_id": "uc_01h…", "tool_slug": "calcom" }
}
If the customer is ARCHIVED, the call returns 409 CUSTOMER_NOT_ACTIVE.

Inspect a customer’s connections

Per-tool status (catalog view)

GET /api/v2/customers/:id/tools
Returns every connector on your account along with this customer’s connection status — empty if not yet connected, or populated with id, status, provider_email, connectedAt.
{
  "success": true,
  "data": {
    "tools": [
      {
        "id": "td_01h…",
        "slug": "google_sheets",
        "name": "Google Sheets",
        "provider": "GOOGLE",
        "status": "ACTIVE",
        "connection": {
          "id": "uc_01h…",
          "status": "ACTIVE",
          "providerEmail": "ops@customer.example",
          "connectedAt": "2026-05-10T08:30:11.000Z"
        }
      },
      {
        "slug": "calcom",
        "name": "Cal.com",
        "connection": null
      }
    ]
  }
}

Just the connections (no catalog merge)

GET /api/v2/customers/:id/connections
{
  "success": true,
  "data": {
    "connections": [
      {
        "id": "uc_01h…",
        "tool_slug": "google_sheets",
        "tool_name": "Google Sheets",
        "status": "ACTIVE",
        "provider_email": "ops@customer.example",
        "created_at": "2026-05-10T08:30:11.000Z",
        "updated_at": "2026-05-10T08:30:11.000Z"
      }
    ]
  }
}

Revoke

DELETE /api/v2/customers/:id/connections/:connection_id
Revokes at the provider (best-effort), clears the encrypted tokens locally, and deletes any AgentTool rows that pointed to this connection. Returns 204 No Content on success, 404 CONNECTION_NOT_FOUND if the id doesn’t match this customer.

Bind an agent to a specific customer’s connection

Agents are owned by you. With B2B2B, an agent can be bound to a specific customer’s connection so that when the agent runs a session for one customer, it uses that customer’s connected tool account.

List eligible connections for an agent

GET /api/v2/agent/:agent_id/available-connections
Returns every connection (yours + your customers’) that this agent can be bound to.
{
  "success": true,
  "data": {
    "connections": [
      {
        "id": "uc_01h…",
        "toolSlug": "google_sheets",
        "toolName": "Google Sheets",
        "status": "ACTIVE",
          "providerEmail": "ops@customer.example",
        "owner": {
          "kind": "partnerCustomer",
          "partnerCustomerId": "pc_01h…",
          "name": "Acme Health",
          "externalId": "acct_customer_42"
        }
      },
      {
        "id": "uc_02g…",
        "toolSlug": "google_sheets",
        "toolName": "Google Sheets",
        "owner": { "kind": "user", "userId": "u_partner" }
      }
    ]
  }
}

Inspect what’s currently bound

GET /api/v2/agent/:agent_id/tools
Returns one row per (slug, owner) for this agent showing whether the binding is enabled.

Bind / unbind

PUT /api/v2/agent/:agent_id/tools/:slug
Body: { "enabled": true, "connection_id": "uc_01h…" }
The optional connection_id disambiguates when multiple connections share a slug (which is common in B2B2B — you might have a Google Sheets connection AND each customer might have one). Without connection_id, the binding falls back to your own connection for that slug.
Response
{ "success": true, "data": { "enabled": true } }
To unbind, pass enabled: false with the same connection_id.

Connector visibility (admin-controlled)

Vocobase admins curate which connectors your account can offer. Granting a connector to your account automatically makes it available to all of your customers. There is no per-customer connector grant. If GET /api/v2/connectors returns an empty list, you have no connectors yet — contact Vocobase support to onboard the ones you need. If connector availability changes, existing active connections remain available unless Vocobase support tells you otherwise.

Error reference

All endpoints return the standard envelope:
{ "success": false, "error": { "code": "INVALID_REDIRECT_URI", "message": "..." } }
HTTPCodeWhen
400INVALID_EXTERNAL_IDMissing/too long external_id on create.
400INVALID_NAMEMissing/too long name on create or update.
400INVALID_EMAILEmail failed validation on create or update.
400INVALID_TOOL_SLUGtool_slug missing or unrecognized.
400INVALID_REDIRECT_URI / sub-codesredirect_uri failed allowlist / scheme / port / fragment / userinfo check.
400TOOL_NOT_API_KEYDirect API-key submit called for an OAuth-only tool.
400INVALID_API_KEY / INVALID_API_TOKEN / INVALID_SUBDOMAINCredential field validation.
404NOT_FOUNDCustomer or connector doesn’t exist or doesn’t belong to your partner.
404CONNECTION_NOT_FOUNDConnection id doesn’t match the customer in path.
409CUSTOMER_NOT_ACTIVECustomer is archived; cannot accept new connections.
500INTERNAL_ERRORUnexpected. Retry idempotent operations.

Limits

LimitValue
external_id length1–200 chars
name length1–200 chars
email lengthup to 254 chars
Connect-link TTLdefault 1800s (30 min), max 86400s (24h), min 60s
Redirect host allowlistconfigured per partner — ask Vocobase to add hosts

What’s not in scope

  • Per-customer billing. ₹ is billed to your partner account, not to individual customers. (Track per-customer usage from session metadata or session listing.)
  • Sub-tenant logins. Customers don’t log in to Vocobase. They authorize via connect-links you mint.
  • Per-customer agents. Agents are owned by you; you bind them to specific customer connections at runtime via connection_id.
  • Per-customer webhook routing. Your single webhook_url receives events for all customers; the payload’s partner_customer_id distinguishes them.