Revyl Documentation

Partners

Partner API reference

Every partner endpoint, with its auth, request, responses, errors, and quotas.

The partner API lives under /api/v1/partner on your Revyl API base URL, such as https://backend.revyl.ai. To get a partner API key, email support@revyl.ai.

Requests

  • Auth: Authorization: Bearer <partner API key> on every request. The key identifies your platform; the account comes from the path or body. Keep the key on your servers.
  • Accounts: {external_account_id} is your ID for a customer account: 1 to 128 letters, digits, _, or -.
  • Request IDs: send a UUID in X-Request-Id, and Revyl returns it on the response for support.
  • Caching: responses that carry a credential or a dashboard link have Cache-Control: no-store. Don't log or cache them.

Errors

Every error the API defines has one shape. Branch on error.code, not on the message:

{
  "error": {
    "code": "not_connected",
    "message": "There's no connection for this external account."
  }
}

An already_connected error also carries connection. An unexpected 500 has no error.code; retry it with backoff.

StatusCodeMeaning
400invalid_requestThe request failed validation.
400authorization_pending, slow_down, access_denied, expired_tokenApproval polling outcomes. See Wait for approval.
401invalid_partner_credentialThe partner key is missing, invalid, or revoked.
403partner_not_allowedYour integration, or this account, isn't enabled in this environment.
403not_supported_for_connectionThis operation isn't available for this connection.
404not_connectedThere's no connection for this account.
409already_connectedThe account is already connected.
409connection_in_progressAnother request for this account is running. Retry after Retry-After.
409needs_supportRevyl found an inconsistent state. Contact support@revyl.ai.
429rate_limitedToo many requests this minute. Retry after Retry-After.
429daily_limit_reachedA daily cap is spent. It resets at 00:00 UTC.
503temporarily_unavailableRetry after Retry-After, with bounded backoff.

Quotas

Requests count against two per-minute buckets: one for your platform and one for each account. Responses report each bucket that was checked:

HeaderMeaning
X-RateLimit-Limit-Partner, X-RateLimit-Limit-AccountRequests allowed per UTC minute.
X-RateLimit-Remaining-Partner, X-RateLimit-Remaining-AccountRequests left this minute.
X-RateLimit-Reset-Partner, X-RateLimit-Reset-AccountWhen the window resets, in Unix seconds.

A missing header doesn't mean unlimited. The values are snapshots, so pace your requests and honor Retry-After on a 429. Two daily caps also reset at 00:00 UTC: new workspaces Revyl creates for your platform, and invitations per connection.

Endpoints

Connect an account

POST /api/v1/partner/connections

Body: external_account_id, external_account_name, organization_name, owner_email, and optional mode (auto or link_existing). Names are 1 to 200 characters.

StatusBody
201connection (state: "connected") and credential
202connection (state: "awaiting_approval") and approval

Errors include 403 partner_not_allowed, 409 already_connected, 409 connection_in_progress, 409 needs_support, and 429 daily_limit_reached.

Collect an approved credential

POST /api/v1/partner/connections/{external_account_id}/approval/token

No body. 200 returns connection and credential, once. Until then it answers one of the 400 polling codes.

Get a connection

GET /api/v1/partner/connections/{external_account_id}

200 returns the connection:

{
  "external_account_id": "acct_123",
  "state": "connected",
  "organization": { "id": "<organization UUID>", "name": "Example Workspace" },
  "origin": "provisioned"
}

state is connected, awaiting_approval, or not_connected. organization is present only while connected. origin is provisioned when Revyl created the workspace and existing when an admin linked one.

Rotate the connection credential

POST /api/v1/partner/connections/{external_account_id}/credentials

No body. 201 returns credential: type: "api_key", secret, and expires_at. The replaced credential keeps working for a short grace period; older ones and session credentials stop at once. Errors include 404 not_connected and 409 connection_in_progress.

Mint a session credential

POST /api/v1/partner/connections/{external_account_id}/session-credentials

Optional body: { "ttl_seconds": 7200 }, from 60 to 14,400. 201 returns credential_id and credential: type: "session_token", secret, and expires_at. Errors include 404 not_connected.

Revoke a session credential

DELETE /api/v1/partner/connections/{external_account_id}/session-credentials/{credential_id}

204. An unknown ID also answers 204. It can also answer 409 connection_in_progress.

Invite a teammate

POST /api/v1/partner/connections/{external_account_id}/invitations

Body: { "email": "sam@example.com" }. 202 returns { "status": "sent" }, and the person joins as a Member. Revyl also answers 202 when it already invited that address this UTC day, without sending again. Errors include 400 invalid_request when Revyl rejects the invitation, 403 not_supported_for_connection for a linked organization, 404 not_connected, 409 connection_in_progress, and 429 daily_limit_reached.

POST /api/v1/partner/connections/{external_account_id}/dashboard-links

No body. 200 returns url, requires_login: true, and expires_at: null. See Dashboard links.

Read usage

GET /api/v1/partner/connections/{external_account_id}/usage?from=<ISO time>&to=<ISO time>

from and to are ISO 8601 times with a time zone, such as 2026-10-01T00:00:00Z.

200 returns period and usage: one row per feature, with seconds for device and build time and millicents for AI usage, for work started through the account's connections. The period is [from, to) and at most 93 days. Errors include 400 invalid_request and 404 not_connected for an account that was never connected.

Disconnect an account

DELETE /api/v1/partner/connections/{external_account_id}

204. Revokes the connection's credentials and session credentials and stops the live sessions started with them. App embeds keep working until you revoke them with DELETE /api/v1/embeds/{embed_id}. Safe to repeat. A 503 means something couldn't be stopped yet; retry to finish.

On this page