API reference
All endpoints require authentication unless noted otherwise. Authentication is via Auth0 OIDC session (web UI routes) or Bearer JWT (API/MCP routes).
Health & Monitoring
Section titled “Health & Monitoring”GET /health
Section titled “GET /health”Health check endpoint. No authentication required.
Response:
{ "status": "ok", "timestamp": "2026-03-26T12:00:00.000Z" }GET /api/orgs/:orgId/vendor-health
Section titled “GET /api/orgs/:orgId/vendor-health”Tenant-scoped vendor-container health — returns only the vendors this org has connected. See the Vendor Health reference for the full feature description.
Auth: Auth0 session (member+)
Response:
{ "vendors": [ { "vendorSlug": "datto-rmm", "displayName": "Datto RMM", "status": "healthy", "lastChecked": "2026-05-17T13:00:00.000Z", "latencyMs": 142, "version": "1.4.0", "errorDetail": null } ]}status is one of healthy / degraded / down / unknown. errorDetail is populated only when degraded or down.
OAuth 2.1 Endpoints
Section titled “OAuth 2.1 Endpoints”GET /.well-known/oauth-authorization-server
Section titled “GET /.well-known/oauth-authorization-server”RFC 8414 authorization server metadata. No authentication required. Advertises
device_authorization_endpoint and lists
urn:ietf:params:oauth:grant-type:device_code in grant_types_supported.
GET /.well-known/oauth-protected-resource/v1/mcp
Section titled “GET /.well-known/oauth-protected-resource/v1/mcp”RFC 9728 protected resource metadata for the unified MCP endpoint.
POST /oauth/register
Section titled “POST /oauth/register”Dynamic client registration (RFC 7591). Used by MCP clients (Claude Desktop, mcp-remote) to register before starting the OAuth flow.
GET /oauth/authorize
Section titled “GET /oauth/authorize”Authorization endpoint. Requires PKCE (S256). Redirects user to Auth0 for authentication, then to the credential connection page if needed.
Query Parameters:
response_type– must becodeclient_id– from dynamic registrationredirect_uri– client callback URLcode_challenge– PKCE S256 challengecode_challenge_method– must beS256scope–mcp:<vendor>(per-vendor) ormcp:all(unified)state– client-generated state parameter
POST /oauth/device_authorization
Section titled “POST /oauth/device_authorization”Device Authorization Grant (RFC 8628) — starts a flow for a client that has no browser and no redirect URI: an unattended agent on a server. No redirect URI is involved at any point.
Client auth: confidential service clients only. Send client_id and
client_secret (HTTP Basic or the body). A public dynamically registered
client is rejected with 400 and unauthorized_client; no device code is
issued. An unknown client_id is 401 invalid_client. Rate limited to
20/minute.
Body:
client_id=<client_id>&client_secret=<svc_client_secret> # service clients only&scope=mcp # optional, defaults to mcpResponse:
{ "device_code": "<opaque>", "user_code": "WDJB-MDBT", "verification_uri": "https://conduit.wyre.ai/device", "verification_uri_complete": "https://conduit.wyre.ai/device?user_code=WDJBMDBT", "expires_in": 600, "interval": 5}Show user_code and verification_uri to a human, then poll
POST /oauth/token every interval seconds. expires_in is DEVICE_CODE_TTL
(default 600 — 10 minutes); interval is DEVICE_POLL_INTERVAL (default
5).
Requiring the secret here is a security control, not bookkeeping: only the agent itself can open a flow capable of minting a token subjected to that agent.
GET /device
Section titled “GET /device”The human-facing approval page. The signed-in person types the user_code —
case- and dash-insensitive, so wdjb mdbt matches WDJB-MDBT — and chooses
Approve or Deny. verification_uri_complete pre-fills it.
Auth: Auth0 session
POST /oauth/token
Section titled “POST /oauth/token”Token exchange and refresh.
Code Exchange:
grant_type=authorization_code&code=<auth_code>&redirect_uri=<redirect_uri>&client_id=<client_id>&code_verifier=<pkce_verifier>Refresh:
grant_type=refresh_token&refresh_token=<refresh_token>&client_id=<client_id>Client Credentials (Service Clients):
grant_type=client_credentials&client_id=<svc_client_id>&client_secret=<svc_client_secret>&scope=mcp:allDevice Code (RFC 8628):
grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=<device_code>&client_id=<client_id>&client_secret=<svc_client_secret> # service clients onlyResponse:
{ "access_token": "<jwt>", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "<token>"}Polling the device grant. The device_code is bound to the client_id that
requested it and is single-use. Service clients must authenticate here too, for
the same reason they must at /oauth/device_authorization.
While the flow is unresolved the device grant returns 400 with an OAuth error
code:
error |
Meaning |
|---|---|
authorization_pending |
Nobody has approved or denied the code yet. Keep polling. |
slow_down |
Polled faster than the interval returned with the device code. Back off, then retry. |
access_denied |
The person chose Deny. |
expired_token |
The code passed its 10-minute TTL. Start a new device authorization request. |
On approval it returns the standard response above — access token plus a
refresh_token, so the agent renews itself without a further approval.
Subject: the issued token is subjected to the service account
(sub: svc:<org-id>:<client-id>), not to the person who approved it — the
human authorizes the agent rather than becoming it. Redeeming the device code
as a public client returns unauthorized_client and does not issue a token.
An approval or denial is written to that organization’s audit log with the approver’s user id and the service account’s organization id.
POST /oauth/revoke
Section titled “POST /oauth/revoke”Token revocation (RFC 7009).
token=<token>&token_type_hint=access_tokenProfile
Section titled “Profile”GET /api/profile
Section titled “GET /api/profile”Returns the authenticated user’s profile.
Auth: Auth0 session
Response:
{ "id": "auth0|abc123", "email": "user@example.com", "name": "John Doe", "firstName": "John", "lastName": "Doe", "displayName": "JD"}PATCH /api/profile
Section titled “PATCH /api/profile”Update profile fields.
Auth: Auth0 session
Body:
{ "firstName": "John", "lastName": "Doe", "displayName": "JD"}Organization CRUD
Section titled “Organization CRUD”POST /api/orgs
Section titled “POST /api/orgs”Create a new organization.
Auth: Auth0 session Body:
{ "name": "Acme MSP"}Response: 201 with org object
GET /api/orgs
Section titled “GET /api/orgs”List the authenticated user’s organizations.
Auth: Auth0 session Response: Array of org objects
GET /api/orgs/:orgId
Section titled “GET /api/orgs/:orgId”Get org details.
Auth: Auth0 session (member+) Response: Org object
PATCH /api/orgs/:orgId
Section titled “PATCH /api/orgs/:orgId”Update org name.
Auth: Auth0 session (owner)
Body: { "name": "New Name" }
DELETE /api/orgs/:orgId
Section titled “DELETE /api/orgs/:orgId”Delete organization.
Auth: Auth0 session (owner)
Response: 204 No Content
POST /api/orgs/:orgId/redeem-code
Section titled “POST /api/orgs/:orgId/redeem-code”Legacy endpoint from the pre-flat-pricing plan tiers. Under the current flat
plan every organization already resolves to the same (only) plan, so a
recognized code responds 409 (the plan is already active) — kept for
backward compatibility with old integrations, not a working activation step.
Invalid codes return 422 and an empty code 400. Rate limited: 5 per 15 minutes.
Auth: Auth0 session (owner)
Body: { "code": "ALPHA123" }
PATCH /api/orgs/:orgId/settings
Section titled “PATCH /api/orgs/:orgId/settings”Update org settings.
Auth: Auth0 session (owner) Body:
{ "defaultServerAccess": "all" }Values: "none" or "all"
Membership
Section titled “Membership”GET /api/orgs/:orgId/members
Section titled “GET /api/orgs/:orgId/members”List org members.
Auth: Auth0 session (member+) Response: Array of member objects
DELETE /api/orgs/:orgId/members/:userId
Section titled “DELETE /api/orgs/:orgId/members/:userId”Remove a member. Admins cannot remove other admins; only owners can.
Auth: Auth0 session (admin+)
Response: 204 No Content
PATCH /api/orgs/:orgId/members/:userId/role
Section titled “PATCH /api/orgs/:orgId/members/:userId/role”Change member role. Cannot change your own role.
Auth: Auth0 session (owner)
Body: { "role": "admin" } (or "member")
Invitations
Section titled “Invitations”POST /api/orgs/:orgId/invitations
Section titled “POST /api/orgs/:orgId/invitations”Create an invitation link. Rate limited: 10 per hour. Requires an active subscription.
Auth: Auth0 session (admin+) Response:
{ "id": "...", "token": "...", "inviteUrl": "https://conduit.wyre.ai/invite/<token>", "expiresAt": "...", "maxUses": 1, "useCount": 0}GET /api/orgs/:orgId/invitations
Section titled “GET /api/orgs/:orgId/invitations”List pending invitations.
Auth: Auth0 session (admin+)
DELETE /api/orgs/:orgId/invitations/:id
Section titled “DELETE /api/orgs/:orgId/invitations/:id”Revoke an invitation.
Auth: Auth0 session (admin+)
Response: 204 No Content
GET /invite/:token
Section titled “GET /invite/:token”Show invitation acceptance page (web UI).
POST /invite/:token
Section titled “POST /invite/:token”Accept an invitation. Rate limited: 5 per 15 minutes.
Server Access Control
Section titled “Server Access Control”GET /api/orgs/:orgId/server-access
Section titled “GET /api/orgs/:orgId/server-access”List all server access grants for the org.
Auth: Auth0 session (admin+)
GET /api/orgs/:orgId/members/:userId/server-access
Section titled “GET /api/orgs/:orgId/members/:userId/server-access”List a user’s vendor access grants. Users can view their own; admins can view any member’s.
Auth: Auth0 session (member for self, admin+ for others)
PUT /api/orgs/:orgId/members/:userId/server-access/:vendor
Section titled “PUT /api/orgs/:orgId/members/:userId/server-access/:vendor”Grant a member access to a vendor.
Auth: Auth0 session (admin+)
DELETE /api/orgs/:orgId/members/:userId/server-access/:vendor
Section titled “DELETE /api/orgs/:orgId/members/:userId/server-access/:vendor”Revoke a member’s access to a vendor.
Auth: Auth0 session (admin+)
Response: 204 No Content
PUT /api/orgs/:orgId/members/:userId/server-access
Section titled “PUT /api/orgs/:orgId/members/:userId/server-access”Bulk-set a member’s vendor access (replaces all grants).
Auth: Auth0 session (admin+)
Body: { "vendors": ["datto-rmm", "itglue", "autotask"] }
Credentials
Section titled “Credentials”POST /api/orgs/:orgId/credentials/:vendor
Section titled “POST /api/orgs/:orgId/credentials/:vendor”Store or update org-level credentials for a vendor. Rate limited: 10 per minute. Requires an active subscription. Validates credentials against vendor API when possible.
Auth: Auth0 session (admin+) Body: Vendor-specific fields (see vendor-integration.md)
{ "apiKey": "your-api-key", "apiSecret": "your-api-secret", "platform": "concord"}Response: 201 with { "id": "...", "vendor": "datto-rmm" }
GET /api/orgs/:orgId/credentials
Section titled “GET /api/orgs/:orgId/credentials”List connected vendor slugs for the org.
Auth: Auth0 session (member+)
Response: ["datto-rmm", "itglue", "autotask"]
DELETE /api/orgs/:orgId/credentials/:vendor
Section titled “DELETE /api/orgs/:orgId/credentials/:vendor”Remove org-level credentials for a vendor.
Auth: Auth0 session (admin+)
Response: 204 No Content
GET /api/orgs/:orgId/credentials/:vendor/keys
Section titled “GET /api/orgs/:orgId/credentials/:vendor/keys”List named org credential keys for a vendor (metadata only — never the stored fields).
Auth: Auth0 session (admin+)
Response: [{ "id": "...", "name": "...", "teamId": "..." | null }, ...]
POST /api/orgs/:orgId/credentials/:vendor/keys
Section titled “POST /api/orgs/:orgId/credentials/:vendor/keys”Add a named org credential key for a vendor, optionally bound to a team. Rate limited: 10 per minute. Requires an active subscription. Validates credentials against the vendor API when possible.
Auth: Auth0 session (admin+)
Body: { "name": "...", "teamId": "..." (optional), "fields": { ...vendor-specific } }
Response: 201 with the created key (metadata only)
PUT /api/orgs/:orgId/credentials/:vendor/keys/:keyId
Section titled “PUT /api/orgs/:orgId/credentials/:vendor/keys/:keyId”Rename a named org credential key and/or rebind it to a different team (teamId: null unbinds it). Metadata only — never the stored credential payload.
Auth: Auth0 session (admin+)
Body: { "name": "...", "teamId": "..." | null }
DELETE /api/orgs/:orgId/credentials/:vendor/keys/:keyId
Section titled “DELETE /api/orgs/:orgId/credentials/:vendor/keys/:keyId”Remove a named org credential key. A team bound to the deleted key falls back to the connection’s default credential.
Auth: Auth0 session (admin+)
Response: 204 No Content
POST /api/orgs/:orgId/teams
Section titled “POST /api/orgs/:orgId/teams”Create a team. Requires an active subscription.
Auth: Auth0 session (admin+)
Body: { "name": "Tier 1 Support" }
Response: 201 with team object
GET /api/orgs/:orgId/teams
Section titled “GET /api/orgs/:orgId/teams”List teams with member counts and vendor connections.
Auth: Auth0 session (admin+)
PATCH /api/orgs/:orgId/teams/:teamId
Section titled “PATCH /api/orgs/:orgId/teams/:teamId”Rename a team.
Auth: Auth0 session (admin+)
Body: { "name": "New Name" }
DELETE /api/orgs/:orgId/teams/:teamId
Section titled “DELETE /api/orgs/:orgId/teams/:teamId”Delete a team.
Auth: Auth0 session (owner)
Response: 204 No Content
PUT /api/orgs/:orgId/teams/:teamId/members/:userId
Section titled “PUT /api/orgs/:orgId/teams/:teamId/members/:userId”Add a member to a team.
Auth: Auth0 session (admin+)
DELETE /api/orgs/:orgId/teams/:teamId/members/:userId
Section titled “DELETE /api/orgs/:orgId/teams/:teamId/members/:userId”Remove a member from a team.
Auth: Auth0 session (admin+)
Response: 204 No Content
PUT /api/orgs/:orgId/teams/:teamId/server-access/:vendor
Section titled “PUT /api/orgs/:orgId/teams/:teamId/server-access/:vendor”Grant a team access to a vendor.
Auth: Auth0 session (admin+)
DELETE /api/orgs/:orgId/teams/:teamId/server-access/:vendor
Section titled “DELETE /api/orgs/:orgId/teams/:teamId/server-access/:vendor”Revoke a team’s access to a vendor.
Auth: Auth0 session (admin+)
Response: 204 No Content
Team Credentials
Section titled “Team Credentials”GET /api/orgs/:orgId/teams/:teamId/credentials
Section titled “GET /api/orgs/:orgId/teams/:teamId/credentials”List vendors with team-level credentials.
Auth: Auth0 session (admin+)
POST /api/orgs/:orgId/teams/:teamId/credentials/:vendor
Section titled “POST /api/orgs/:orgId/teams/:teamId/credentials/:vendor”Store team-level credentials for a vendor.
Auth: Auth0 session (admin+) Body: Vendor-specific credential fields
DELETE /api/orgs/:orgId/teams/:teamId/credentials/:vendor
Section titled “DELETE /api/orgs/:orgId/teams/:teamId/credentials/:vendor”Remove team-level credentials.
Auth: Auth0 session (admin+)
Response: 204 No Content
Service Clients (M2M)
Section titled “Service Clients (M2M)”POST /api/orgs/:orgId/service-clients
Section titled “POST /api/orgs/:orgId/service-clients”Create a service client for M2M authentication.
Auth: Auth0 session (admin+) Body:
{ "name": "Nightly Sync", "expires_in_days": 90}Response: 201
{ "id": "...", "name": "Nightly Sync", "client_id": "svc_...", "client_secret": "<shown-once>", "expires_at": "2026-06-24T00:00:00.000Z", "created_at": "2026-03-26T00:00:00.000Z"}GET /api/orgs/:orgId/service-clients
Section titled “GET /api/orgs/:orgId/service-clients”List service clients (secret is never returned after creation).
Auth: Auth0 session (admin+)
DELETE /api/orgs/:orgId/service-clients/:clientId
Section titled “DELETE /api/orgs/:orgId/service-clients/:clientId”Revoke a service client.
Auth: Auth0 session (admin+)
Response: 204 No Content
POST /api/orgs/:orgId/service-clients/:clientId/agent-key
Section titled “POST /api/orgs/:orgId/service-clients/:clientId/agent-key”Mint — or rotate — this service account’s agent key: a long-lived bearer for
/v1/mcp, for agents that set one Authorization header and cannot run an
OAuth flow. It resolves to the account’s own svc:<org-id>:<client-id>
identity, so its teams, access grants and audit entries are unchanged.
Calling this again rotates in place. The previous key stops working immediately; the account keeps its identity and all of its grants.
Prefer the device-code flow above where the client can run it: it ends with a rotating refresh token rather than a static bearer in a config file. An agent key is for clients that can only set one header.
Auth: Auth0 session (admin+). Rate limited to 10/hour.
Requires: the organization’s serviceClients entitlement — an org whose
subscription has lapsed cannot mint new agent credentials. Revoking stays open
so such an org can still wind existing keys down.
Response: 201
{ "agent_key": "cak_a4f9b2c8d1e0_<shown-once>", "prefix": "cak_a4f9b2c8d1e0", "rotated": false}| Status | Meaning |
|---|---|
402 |
The organization lacks the serviceClients entitlement. Distinct from an auth failure — the session is valid, the subscription is not. |
404 |
No service account with that clientId in this organization. |
agent_key is returned once and is never retrievable again. prefix is the
public half, safe to display, and is what the Service Accounts page lists.
DELETE /api/orgs/:orgId/service-clients/:clientId/agent-key
Section titled “DELETE /api/orgs/:orgId/service-clients/:clientId/agent-key”Revoke the agent key. Takes effect immediately; the service account itself is untouched.
Auth: Auth0 session (admin+)
Response: 204 No Content — or 404 if the account has no key.
GET /api/orgs/:orgId/service-clients/:clientId/credentials
Section titled “GET /api/orgs/:orgId/service-clients/:clientId/credentials”List vendors with service-client-level credentials.
Auth: Auth0 session (admin+)
POST /api/orgs/:orgId/service-clients/:clientId/credentials/:vendor
Section titled “POST /api/orgs/:orgId/service-clients/:clientId/credentials/:vendor”Store service-client-level credentials.
Auth: Auth0 session (admin+)
DELETE /api/orgs/:orgId/service-clients/:clientId/credentials/:vendor
Section titled “DELETE /api/orgs/:orgId/service-clients/:clientId/credentials/:vendor”Remove service-client-level credentials.
Auth: Auth0 session (admin+)
Response: 204 No Content
Tool Access (RBAC)
Section titled “Tool Access (RBAC)”GET /api/orgs/:orgId/tool-access/:vendor
Section titled “GET /api/orgs/:orgId/tool-access/:vendor”Get tool allowlists for all roles for a vendor.
Auth: Auth0 session (admin+)
PUT /api/orgs/:orgId/tool-access/:vendor/:role
Section titled “PUT /api/orgs/:orgId/tool-access/:vendor/:role”Set the tool allowlist for a role. When set, members with that role can only use the listed tools.
Auth: Auth0 session (owner)
Body: { "tools": ["datto_list_devices", "datto_list_sites"] }
DELETE /api/orgs/:orgId/tool-access/:vendor/:role
Section titled “DELETE /api/orgs/:orgId/tool-access/:vendor/:role”Clear the allowlist (revert to allow-all).
Auth: Auth0 session (owner)
Response: 204 No Content
GET /api/orgs/:orgId/tool-access/:vendor/discover
Section titled “GET /api/orgs/:orgId/tool-access/:vendor/discover”Discover available tools from a vendor container (queries the live container).
Auth: Auth0 session (admin+)
GET /api/audit
Section titled “GET /api/audit”Query the request audit log. Requires an active subscription and admin+ role.
Auth: Auth0 session Query Parameters:
org_id– filter by org (defaults to user’s primary org)user_id– filter by uservendor– filter by vendor slugstart– ISO date startend– ISO date endlimit– page sizeoffset– page offsetformat–csvfor CSV export
Each JSON entry includes userLabel (name, then email, then a service-account name, then a short last-4 fallback) alongside the stable userId. CSV export leads with that label in the user column and keeps user_id as the next column.
GET /api/audit/admin
Section titled “GET /api/audit/admin”Query the admin audit log (administrative actions).
Auth: Auth0 session (admin+, active subscription) Query Parameters:
org_id,event_type,actor_id,start,end,limit,offset,format
JSON entries include actorLabel and, when a target is present, targetLabel, alongside actorId and targetId. Service accounts use their configured name; background jobs use a readable sentinel name (for example “Log shipper”). CSV export leads with those labels (actor, target) and keeps actor_id / target_id beside them.
Usage Dashboard
Section titled “Usage Dashboard”Usage analytics for an organization. All three endpoints require an active subscription and admin+ role, and resolve to the caller’s primary organization. They read from the request_log — the same metadata described in Prompt Capture & Privacy.
Time window. Every endpoint accepts the same window parameters:
range– one of7d,30d,1y,all. Defaults to30dwhen neitherstartnorendis given.allcovers the org’s whole retained history and must be requested explicitly.start/end– ISO 8601 bounds. If either is present it overridesrange.
The Overview page’s usage section exposes the same presets as a 7d / 30d / 1y / All time picker and keeps the choice in the URL (/org?range=7d).
GET /api/dashboard/usage
Section titled “GET /api/dashboard/usage”Aggregate tool-call usage for the org.
Auth: Auth0 session (admin+, active subscription) Query Parameters:
range–7d|30d(default) |1y|allstart– ISO 8601 range start (overridesrange)end– ISO 8601 range end (overridesrange)
Response: total calls, unique users, average response time, plus breakdowns by vendor, by user, by day, and by source (mcp / cli).
GET /api/dashboard/savings
Section titled “GET /api/dashboard/savings”Estimated token and cost savings from CLI-wrapper calls versus raw MCP calls.
Auth: Auth0 session (admin+, active subscription)
Query Parameters: range, start, end
Response: { "totalMcpCalls": ..., "totalCliCalls": ..., "estimatedTokensSaved": ..., "estimatedCostSavedUsd": ... }. The savings figures are a heuristic estimate, not a metered measurement.
GET /api/dashboard/vendors
Section titled “GET /api/dashboard/vendors”Per-vendor usage breakdown.
Auth: Auth0 session (admin+, active subscription)
Query Parameters: range, start, end
Response: { "vendors": [ ... ] } — each entry has total calls, unique users, average response time, and the vendor’s top 5 tools by call count.
Billing
Section titled “Billing”POST /api/billing/checkout
Section titled “POST /api/billing/checkout”Create a Stripe Checkout session for the flat subscription.
Auth: Auth0 session (owner) Body:
{ "org_id": "...", "coupon": "DISCOUNT20"}Response: { "url": "https://checkout.stripe.com/..." }
POST /api/billing/portal
Section titled “POST /api/billing/portal”Create a Stripe Customer Portal session for managing subscription.
Auth: Auth0 session (owner)
Body: { "org_id": "..." }
Response: { "url": "https://billing.stripe.com/..." }
POST /api/webhooks/stripe
Section titled “POST /api/webhooks/stripe”Stripe webhook ingest. Called by Stripe, not by API clients — signature-verified per request (see Security § Billing & Payment Security). Listed here for completeness; not a customer-callable endpoint.
Auth: Stripe webhook signature (HMAC)
Log Shipping
Section titled “Log Shipping”GET /api/orgs/:orgId/log-shipping
Section titled “GET /api/orgs/:orgId/log-shipping”List log shipping destinations (configs are masked).
Auth: Auth0 session (admin+, active subscription)
POST /api/orgs/:orgId/log-shipping
Section titled “POST /api/orgs/:orgId/log-shipping”Create a log shipping destination.
Auth: Auth0 session (admin+, active subscription)
platform is one of loki, graylog, logscale, huntress, splunk, elastic, sentinel, webhook. endpointUrl may be omitted for huntress (preset to https://hec.huntress.io); huntress also rejects any other host, and sentinel requires an *.ingest.monitor.azure.com host. Required config keys per platform: logscale/huntress/splunk → token; sentinel → tenantId, clientId, clientSecret, dcrImmutableId. Secret values are returned masked (abcd****). See the log shipping guide for each platform’s fields.
Body:
{ "label": "Production Loki", "platform": "loki", "endpointUrl": "https://loki.example.com/loki/api/v1/push", "config": { "username": "...", "password": "..." }}CLI Endpoints
Section titled “CLI Endpoints”POST /v1/:vendor/cli
Section titled “POST /v1/:vendor/cli”Execute a tool call via plain JSON (not MCP JSON-RPC). Rate limited: 5,000/hour per user — one shared bucket across this endpoint and the two MCP endpoints below, not a separate allowance per vendor or per transport.
Auth: Bearer JWT Body:
{ "tool": "datto_list_devices", "args": { "siteId": "123" }}Response:
{ "result": { "content": [...] } }Response Headers: X-Auth-Ms, X-Session-Ms, X-Vendor-Ms, X-Total-Ms
GET /v1/:vendor/cli/schema
Section titled “GET /v1/:vendor/cli/schema”Get CLI-friendly tool definitions for a vendor. Rate limited: 600/minute, shared with every other route that has no endpoint-specific limit (global backstop, not a per-user allowance).
Auth: Bearer JWT Response:
{ "vendor": "datto-rmm", "vendorName": "Datto RMM", "commands": [ { "command": "list-devices", "description": "List all devices", "flags": [ { "name": "siteId", "type": "string", "required": false, "description": "..." } ] } ]}MCP Proxy Endpoints
Section titled “MCP Proxy Endpoints”POST /v1/mcp (Unified)
Section titled “POST /v1/mcp (Unified)”Single MCP endpoint for all vendors. Handles initialize, tools/list (aggregated), and tools/call (routed by vendor prefix). Rate limited: 5,000/hour per user — one shared bucket across this endpoint, the per-vendor endpoint below, and the CLI endpoint above.
Auth: Authorization: Bearer <token>, where the token is either a JWT from
the OAuth 2.1 flow (a person, or a service account via client_credentials) or
a service account’s long-lived agent key (cak_…). Both resolve to the same
identity and the same access grants; an agent key resolves to its service
account’s svc:<org-id>:<client-id>. See
Connect an unattended agent.
initialize response: echoes back the client’s requested protocolVersion when it’s one Conduit recognizes (2025-11-25 / 2025-06-18 / 2025-03-26 / 2024-11-05), falling back to 2025-03-26 for an absent or unrecognized request. serverInfo includes icons (Conduit’s logo, requires a negotiated protocol version of 2025-11-25 or later to be read), plus title, description, and websiteUrl.
POST /v1/:vendor/mcp (Per-Vendor, Deprecated)
Section titled “POST /v1/:vendor/mcp (Per-Vendor, Deprecated)”Per-vendor MCP endpoint. Legacy; prefer the unified endpoint. Same shared 5,000/hour-per-user rate limit as the unified and CLI endpoints.
Auth: Bearer JWT (via OAuth 2.1 flow)

