Move from prototype to production

A prototype proves that an agent can connect an account and call a tool. A production integration must also preserve user isolation, survive repeat visits, limit what the agent can do, and give your team enough evidence to diagnose failures.

Use this guide after the quickstart works and before customers depend on the integration.

Production decisions at a glance

Prototype defaultProduction decision
One sample user such as user_123Stable, immutable application user IDs
One project for every testSeparate projects for environments that must not share credentials or resources
A new session on every runPersist and reuse session IDs for multi-turn work
Every toolkit is discoverableRestrict toolkits and tools to the product's intended scope
Managed authKeep it, or use custom auth for branding, scopes, quotas, or custom providers
API keys in a local .env fileServer-side secret manager and environment-specific keys
A successful demo callReal account, failure-path, webhook, and tenant-isolation tests

1. Finalize your identity model

Replace sample values with an immutable ID from your application database. Never use an email address or a shared value such as default in production.

For a consumer product, each person usually owns their connections. See Design a consumer agent.

For a B2B product, decide whether connections belong to an individual member or to the customer workspace. See Design a B2B agent.

2. Separate environments where it matters

Use separate Composio projects for development, staging, and production when those environments must not share API keys, auth configs, connected accounts, webhooks, or logs.

Keep every project API key on the server. Store production keys in your deployment platform's secret manager, rotate them according to your security policy, and never expose them to browser or mobile clients.

For user- or organization-scoped operations, pass user_api_key or org_api_key to the Python Composio constructor, or userApiKey or orgApiKey in TypeScript. You can also set COMPOSIO_USER_API_KEY and COMPOSIO_ORG_API_KEY. A project API key is still required by default, and the client sends the scoped key only to operations that require it. To authenticate without a project API key, set apiKey: null in TypeScript and pass a user or organization API key, or set disable_api_key=True in Python and pass a user API key. A user API key passed this way is sent on every request; an organization API key is still sent only to operations that accept it. In Python, an organization API key still requires a project API key.

In TypeScript, apiKey: null disables project-key fallbacks, including COMPOSIO_API_KEY and the CLI config. To keep those fallbacks, omit apiKey or pass undefined.

For consumer requests, set org_id and project_id in Python or orgId and projectId in TypeScript together. See Run sessions in your organization's consumer project for an example.

3. Decide how customers authenticate

Keep managed auth when its provider app, scopes, and quotas fit your product. It removes OAuth app setup and token-refresh work.

Use a custom auth config when you need:

  • Your own app name on the provider consent screen
  • Different or additional OAuth scopes
  • Dedicated provider quotas
  • A custom, regional, or self-hosted provider instance
  • Customer-specific OAuth credentials

Test both first-time authentication and a returning user whose connected account already exists. If you need a branded flow, follow the white-labeling guide.

4. Bound the agent's authority

Configure sessions with only the toolkits and tools required by the feature. Narrower access improves tool discovery and reduces the number of actions the agent can attempt.

Require explicit user confirmation before destructive or externally visible actions, such as sending a message, creating a purchase, or deleting data. Enforce product authorization before creating or restoring the session, especially for workspace-owned connections.

See Configuring sessions for toolkit and tool filters.

5. Persist the right state

Store the Composio session ID with your conversation or task and reuse it with composio.use(). This preserves the session's tool, authentication, and workbench context across turns.

Also store the mapping between your application user, Composio user ID, connected accounts, and tenant when applicable. Your database remains the source of truth for product membership and permissions.

6. Test real execution and failure paths

Run at least one safe, read-only call against a real connected account. Confirm that:

  • The tool returns expected data for the correct user
  • A second user cannot access the first user's connection
  • A missing or expired connection returns the expected recovery flow
  • Invalid tool arguments produce a useful error
  • The tool call appears in Logs with a non-empty log ID

Do not treat a successful Connect Link alone as an end-to-end test. Authentication can succeed while a provider API, scope, or tool input still fails.

Retry failed executions deliberately

The SDKs retry reads — fetching tools, listing toolkits, reading a session — when a request times out or comes back 408, 409, 429, or 5xx. They never retry an execution. tools.execute, tools.proxy, and every session execute and proxyExecute call is sent exactly once, because the backend doesn't deduplicate executions and a silent retry after a read timeout would repeat the side effect, such as sending the same email twice.

A transient failure on an execution therefore reaches your code instead of being absorbed. Before retrying one, decide whether repeating that specific call is safe: a read is, GMAIL_SEND_EMAIL isn't. When it isn't, check Logs or the provider's own API to find out whether the first attempt landed.

Configure SDK logging

Pass logger and logLevel to the TypeScript Composio constructor to send SDK logs to your logging system. The logger must provide error, warn, info, and debug methods. Messages have credential-shaped values redacted before reaching the logger, including owned-client deprecation warnings. Logger configuration is process-wide: the last configured instance controls the SDK logger.

In Python, pass a standard logging.Logger as logger and a composio.utils.logging.LogLevel as logging_level. Sensitive values are redacted before records reach the logger. Deprecation notices use ComposioDeprecationWarning warnings rather than log records.

Inspect project usage

Use composio.experimental.usage.summary() for totals by entity type and composio.experimental.usage.breakdown() for grouped usage of one entity type, such as tool_calls or sessions. Both SDKs scope these queries to the project associated with your API key.

The summary also returns the total Instant charge for the window as an exact USD string: instantCharge in TypeScript and instant_charge in Python. It returns "0" when no usage was charged. Breakdowns contain usage quantities and event counts, not charges.

Usage metering is experimental, and its response shape may change.

7. Verify triggers through your real webhook

If your product uses triggers, test the deployed HTTPS webhook rather than only a local callback. Parse events with the Composio SDK, verify the payload reaches the correct environment, and map it to the expected user or workspace before doing work.

See Subscribing to trigger events for the webhook flow.

8. Set security and data-retention expectations

Review which tool inputs, outputs, logs, and files your integration creates. Align retention with your own product policy and customer commitments. See Data retention for the controls Composio provides.

Document who can access production projects, rotate keys, manage auth configs, and inspect logs. Keep those permissions limited to the people and services that need them.

Ready to ship

  • Stable user and tenant IDs are used everywhere.
  • Development, staging, and production use the intended project boundaries.
  • API keys are server-side and stored in a secret manager.
  • Authentication, reconnect, and returning-user flows work.
  • Session IDs are persisted for multi-turn work.
  • Tool access and confirmation rules match the product's intended authority.
  • Cross-user or cross-tenant isolation has been tested.
  • Real tool calls and trigger events appear in logs and map to the correct user.
  • The team knows how to diagnose and recover from provider or authentication failures.

Next