stateweave Docs
Guides

Client libraries

If your agent already uses a vendor's client library, keep it. Give it the run's address and token instead of the real service's, and nothing else in your code changes. This page lists the one setting each library needs.

At a glance

Each library below was tested against a run served over HTTPS exactly as hosted runs are, with reads and writes: queries, lists across several pages, creates and updates.

AppLibraryTestedWhat to set
Slackslack_sdk (Python)3.46.0base_url
Slack@slack/web-api (Node)8.3.0slackApiUrl
Googlegoogle-api-python-client2.201.0 discoveryServiceUrl and static_discovery=False
Googlegoogleapis (Node)189.0.0rootUrl
Salesforcesimple-salesforce1.12.10instance_url, version
Salesforcejsforce (Node)3.13.1instanceUrl, version
ShopifyShopifyAPI (Python)12.7.0 Session.myshopify_domain. GraphQL only.
Shopify@shopify/admin-api-client2.0.1storeDomain
Zendeskzenpy2.0.57subdomain and domain
Zendesknode-zendesk6.0.1endpointUri

The examples read the run as in Apps and credentials: app(name) is a run's app and credential(name, kind) one of its tokens. In Node:

run.js
const run = JSON.parse(require("fs").readFileSync(process.env.STATEWEAVE_RUN_FILE, "utf8"));
const app = (name) => run.apps[name];
const credential = (name, kind = "user") =>
  Object.entries(app(name).credentials).find(([label]) => label.split(":")[0] === kind)[1];

Slack

from slack_sdk import WebClient

slack = WebClient(token=credential("slack", "user"), base_url=app("slack")["endpoints"]["web_api"])
const { WebClient } = require("@slack/web-api");

const slack = new WebClient(credential("slack", "user"), { slackApiUrl: app("slack").endpoints.web_api });

Google

The same setting serves Gmail, Calendar, Sheets and Drive. Python's library ships its own copy of each API description, so turn that off and point it at the run's. Node's takes the run's address as rootUrl, with a trailing slash.

from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build

gmail = build("gmail", "v1", credentials=Credentials(credential("gmail")),
              discoveryServiceUrl=app("gmail")["endpoints"]["discovery"], static_discovery=False)
const { google } = require("googleapis");

const auth = new google.auth.OAuth2();
auth.setCredentials({ access_token: credential("gmail") });
const gmail = google.gmail({ version: "v1", auth, rootUrl: app("gmail").base_url + "/" });

For Sheets, list spreadsheets through Drive with the Sheets app's own token and its drive_discovery (Python) or the same rootUrl (Node).

Salesforce

Pass the version the run's rest_api names (68.0), not the library's default.

from simple_salesforce import Salesforce

sf = Salesforce(instance_url=app("salesforce")["endpoints"]["instance_url"],
                session_id=credential("salesforce"), version="68.0")
accounts = sf.query("SELECT Id, Name FROM Account LIMIT 10")["records"]
const jsforce = require("jsforce");

const conn = new jsforce.Connection({
  instanceUrl: app("salesforce").endpoints.instance_url,
  accessToken: credential("salesforce"),
  version: "68.0",
});
const accounts = (await conn.query("SELECT Id, Name FROM Account LIMIT 10")).records;

Shopify

StateWeave's Shopify serves the GraphQL Admin API. The REST Admin API (paths such as /admin/api/2026-10/products.json) answers 404 with the header x-twin-not-implemented: 1, so use a library's GraphQL client.

import shopify

host = app("shopify")["base_url"].removeprefix("https://")   # t-….app.stateweave.net
shop, _, domain = host.partition(".")
shopify.Session.myshopify_domain = domain   # the library appends this to the shop's name
session = shopify.Session(shop, "2026-10", credential("shopify", "app"))
shopify.ShopifyResource.activate_session(session)

result = shopify.GraphQL().execute("{ shop { name } orders(first: 10) { nodes { name } } }")
const { createAdminApiClient } = require("@shopify/admin-api-client");

const shopify = createAdminApiClient({
  storeDomain: app("shopify").base_url.replace("https://", ""),
  apiVersion: "2026-10",
  accessToken: credential("shopify", "app"),
});
const { data } = await shopify.request("{ shop { name } orders(first: 10) { nodes { name } } }");

ShopifyAPI builds its own address. Given any shop name, it keeps the first label and adds .myshopify.com. Without Session.myshopify_domain set, your agent would call a real Shopify store, not the run. Its REST resources (shopify.Product, shopify.Order, …) use the REST Admin API and fail with ResourceNotFound.

Zendesk

from zenpy import Zenpy

host = app("zendesk")["base_url"].removeprefix("https://")   # t-….app.stateweave.net
subdomain, _, domain = host.partition(".")
zendesk = Zenpy(subdomain=subdomain, domain=domain, oauth_token=credential("zendesk"))
const zendesk = require("node-zendesk");

const client = zendesk.createClient({
  endpointUri: app("zendesk").endpoints.rest_api.replace(/\/$/, ""),
  token: credential("zendesk"),
  oauth: true,
});

Other libraries

Any library works if it lets you set where it sends requests and which token it uses. Watch for two things:

  • A hard-coded host. Some libraries build the address from an account or shop name, like ShopifyAPI above. Find the setting that changes the domain; without one, the library can't reach the run.
  • Its own sign-in. A run hands over access tokens, not client secrets or refresh tokens. Give the library the token directly instead of running its OAuth flow.

Tell us at mikewei@stateweave.net if a library you use doesn't work.