VendoVendo Docs
GuidesRecipes

Handle NotConnected

Surface a structured needs_connection payload so the frontend can redirect users to the connect portal.

NotConnected is raised by vendo.data.execute when the provider required by the action is not connected (binding_missing from the proxy). The correct response is to return a structured payload so the frontend can redirect the user to the connect portal.

STRIPE_LIST_CUSTOMERS in the example below is the Composio action id pattern — <TOOLKIT>_<ACTION> in SCREAMING_SNAKE_CASE. Confirm the exact spelling against composio.dev before shipping; the proxy is a pass-through and Vendo doesn't curate the action catalog.

connections.get(slug) returns None / null (not NotConnected) when the provider is not connected. These are two different signals for two different code paths — see the comparison table below.


Catch NotConnected from data.execute

import vendo
from vendo.errors import NotConnected

def run_stripe_action(client):
    try:
        return {"customers": client.data.execute("STRIPE_LIST_CUSTOMERS", {"limit": 10})}
    except NotConnected as e:
        # e.slug is the missing provider, "stripe" here.
        slug = e.slug or "stripe"
        return {
            "needs_connection": slug,
            "connect_url": vendo.connect_url(slug),
        }
import { Vendo, NotConnected } from "@vendodev/sdk";

const vendo = new Vendo();

async function runStripeAction() {
  try {
    return { customers: await vendo.data.execute("STRIPE_LIST_CUSTOMERS", { limit: 10 }) };
  } catch (e) {
    if (e instanceof NotConnected) {
      const slug = e.slug ?? "stripe";
      return {
        needsConnection: slug,
        connectUrl: vendo.connectUrl(slug),
      };
    }
    throw e;
  }
}

Handle the response on the frontend

The frontend receives { needs_connection: "stripe", connect_url: "..." } and opens the connect portal:

const res = await fetch("/api/stripe-customers");
const data = await res.json();

if (data.needs_connection) {
  // Open the Vendo connect portal in a popup
  window.open(data.connect_url, "vendo-connect", "width=500,height=700");
}

After the user connects, the portal closes and Vendo emits a connection.connected event on the SDK's SSE stream. Subscribe with vendo.events.subscribe() (or client.events.subscribe() on an instance) and call vendo.invalidate(slug) when you see the event — the next data.execute call then picks up the fresh binding without a process restart.


connections.get vs NotConnected — which to use

SituationPattern
Check if a provider is connected before doing anythingconnections.get(slug) returns None
Execute an action and handle failure if not connecteddata.execute raises NotConnected
Show a connect button in the UI before the user attempts an actionconnections.get(slug) — render the setup_url from the returned entry
Execute an action and want a single try/catch for all error casesCatch NotConnected from data.execute

NotConnected error fields

FieldTypeDescription
slugstr | NoneThe provider slug that is not connected, e.g. "stripe". Optional — fall back to a known slug if absent.
connect_urlstr | NonePre-computed connect URL, when the proxy was able to build one.
messagestrHuman-readable message.

Notes

  • In Vendo mode connect_url returns a working URL only when VENDO_API_KEY is set. Do not call it in OSS mode.
  • The setup_url field on a Connection entry returned by connections.list() is the same URL — use it when you want to pre-render the connect button without waiting for a NotConnected error.
  • After the user connects, the next call to connections.get(slug) returns the connection, and data.execute succeeds. You do not need to restart the process.

On this page