Skip to content

API v1 reference

When to use this guide: This is the complete, authoritative contract for OutboundSync API v1 — the vocabulary, every endpoint’s request and response shape, the account-status blocker and warning codes, and the security model. To create and manage keys first, see Creating API keys.

Public REST API for OutboundSync account introspection and pipeline status checks. Use at any lifecycle stage — before a campaign, mid-flight when CRM data looks wrong, or after completion. Authenticate with a Bearer token:

Authorization: Bearer osapi_<key>

Every v1 endpoint is a GET request authenticated with a Bearer token. The base URL is:

https://app.outboundsync.com/api/v1

Start with GET /api/v1/me to confirm the key is valid and see which CRM connections it can access.

Terminal window
curl https://app.outboundsync.com/api/v1/me \
-H "Authorization: Bearer osapi_<your-secret>"
const response = await fetch('https://app.outboundsync.com/api/v1/me', {
headers: {
Authorization: `Bearer ${process.env.OUTBOUNDSYNC_API_KEY}`,
},
});
if (!response.ok) {
throw new Error(`OutboundSync API request failed: ${response.status}`);
}
const data = await response.json();

The API is read-only and returns no secrets (see Security). For 401 / 403 / 429 handling and a retry pattern, see Errors and rate limits.

The word “webhook” is overloaded in OutboundSync. The public API uses industry-standard sources → destinations vocabulary:

ConceptSchema todayUI label todayAPI termPath
Inbound URLs sequencers POST events to (POST /webhooks/:code)Webhook model”Webhook receiver”sourceGET /api/v1/sources
Customer URLs OutboundSync forwards received events toUserAccount + UserAccountWebhook junction”Webhook endpoint” / “Additional endpoints”destinationfield names only; /api/v1/destinations later
OutboundSync platform-emitted events (future)webhooks/api/v1/webhooks reserved, unused

Notes:

  • “Webhooks” is reserved for platform-emitted events (Stripe/HubSpot/Segment convention).
  • “Destination” is the umbrella term for managed integrations and raw webhook URLs.
  • eventTypes[] lives on the destination binding, not on the source.
  • The physical inbound route /webhooks/:code is unchanged — it is the value of a source’s url field. Legacy sources created before code-based routing use /webhooks/:hubId/:ownerId; the url field always reflects the correct form.
NamespaceNowLater
/api/v1/account/*statususage, limits; /me stays as key-identity check
/api/v1/connectionslist w/ embedded status/:id, /:id/test, /:id/properties
/api/v1/sourceslist w/ config + destinations summary/:id, /:id/logs, POST create
/api/v1/destinations— (fields only)standalone resource
/api/v1/blocklists— (fast-follow)list, /:id/entries
/api/v1/webhooksreservedplatform webhooks + subscriptions
/api/v1/events, /api/v1/sync-logsactivity/observability

Rules: plural kebab-case resources; status embedded on resources; cross-cutting checks under account/; every list response wrapped in a named key ({ "sources": [...] }). GET /api/v1/me is the identity exception — flat top-level fields plus a links object for related endpoints.

Returns account, API key metadata, accessible CRM connections, and links to related v1 endpoints. Use as the bootstrap call after authentication.

apiKey.connectionId is set when the key is connection-scoped (connectionScope: "connection"); it is null for account-scoped keys and matches the single entry in connections[].

connections[] order matches accessibleConnectionIds — the same order as /connections and /account/status.

Response: MeResponse

{
"account": {
"id": 42,
"email": "harris@outboundsync.com"
},
"apiKey": {
"name": "prod",
"scopes": ["read"],
"connectionScope": "account",
"connectionId": null
},
"connections": [
{
"id": 7,
"crm": "HUBSPOT",
"organizationId": "123",
"organizationDomain": "acme.com"
}
],
"links": {
"accountStatus": {
"href": "/api/v1/account/status",
"description": "Pipeline readiness with blockers and warnings for each connection."
},
"connections": {
"href": "/api/v1/connections",
"description": "CRM connections with OAuth status and plan capabilities."
},
"sources": {
"href": "/api/v1/sources",
"description": "Inbound paste URLs, platform config, and destination bindings."
},
"documentation": {
"href": "https://outboundsync.com/docs/api/v1/",
"description": "OutboundSync API v1 reference."
}
}
}

For connection-scoped keys, connectionScope is "connection", connectionId matches connections[0].id, and connections[] has one element.

Point-in-time pipeline status across all connections the key can access. Answers: can OutboundSync receive events and sync them to the CRM right now? Connection-scoped keys receive a one-element array.

This is account-specific and requires a key. For platform-wide availability (independent of your account), use the public, unauthenticated Platform health endpoints instead.

Response: AccountStatusResponse

The response has three outcome layers:

LayerFieldMeaning
Red lightblockers[]Sync cannot work until resolved. Gates ready.
Yellow lightwarnings[]Optional features not configured or non-fatal issues. Never gates ready.
Detailconnections[].* per-component statusEmbedded component state for each connection.
{
"ready": true,
"checkedAt": "2026-07-03T12:00:00.000Z",
"connections": [
{
"connectionId": 7,
"crm": "HUBSPOT",
"ready": true,
"crmConnection": {
"status": "ready",
"crm": "HUBSPOT",
"organizationId": "123",
"organizationDomain": "acme.com"
},
"sources": {
"status": "ready",
"count": 2,
"platforms": ["smartlead", "instantly"]
},
"destinations": {
"status": "not_configured",
"count": 0,
"eventTypes": []
},
"blocklists": {
"status": "not_configured",
"enabledCount": 0,
"lastError": null,
"lastFetchedAt": null
}
}
],
"blockers": [],
"warnings": [
{
"code": "destinations_not_configured",
"connectionId": 7,
"crm": "HUBSPOT",
"message": "No additional endpoints are configured — events still sync to HubSpot; nothing is forwarded to external URLs.",
"remediation": "Optional: add forwarding URLs in the OutboundSync dashboard (https://app.outboundsync.com/admin/dashboard/webhooks) if you need events sent to Clay, Zapier, or other systems.",
"docUrl": "https://outboundsync.com/docs/api/v1/#warning-destinations_not_configured"
},
{
"code": "blocklists_not_configured",
"connectionId": 7,
"crm": "HUBSPOT",
"message": "No block list is configured — sync to HubSpot is active but no contacts are being suppressed.",
"remediation": "Optional: configure a block list in the OutboundSync dashboard (https://app.outboundsync.com/admin/dashboard/smartlead-block-lists) if you need to skip certain contacts.",
"docUrl": "https://outboundsync.com/docs/api/v1/#warning-blocklists_not_configured"
}
]
}

When CRM is disconnected, ready is false and blockers contains crm_disconnected — warnings may also be present but do not affect ready.

HTTP semantics: authenticated-but-not-ready returns HTTP 200 with ready: false. Auth failures return 401/403; rate limits return 429.

CRM connections with embedded status and capability flags.

Response: ConnectionsResponse

{
"connections": [
{
"id": 7,
"crm": "HUBSPOT",
"status": "ready",
"organizationId": "123",
"organizationDomain": "acme.com",
"capabilities": {
"sync": true,
"destinations": true,
"blocklists": true
},
"createdAt": "2025-01-01T00:00:00.000Z"
}
]
}

Inbound sources with the URL to paste into a sequencer, platform, config summary, and destination bindings.

Response: SourcesResponse

{
"sources": [
{
"id": 10,
"url": "https://sync.outboundsync.com/webhooks/abc123",
"platform": "smartlead",
"connectionId": 7,
"crm": "HUBSPOT",
"config": {
"createOrUpdateCompany": true,
"createOrUpdateTask": true,
"assignContactOwner": true,
"salesforceObjectType": null
},
"destinations": [
{
"url": "https://hooks.example.com/os",
"description": "Clay",
"eventTypes": ["EMAIL_SENT", "EMAIL_REPLY"],
"isDelayed": false
}
],
"createdAt": "2025-01-02T00:00:00.000Z"
}
]
}
ValueMeaning
readyComponent is configured and operational (DB-derived)
not_configuredFeature enabled but nothing set up yet
disconnectedCRM OAuth token missing (refreshToken is null)
disabledFeature not enabled on this connection (plan/capability gate)
errorComponent has a recorded error (blocklists only)

Blockers are hard failures — sync cannot work. They gate the top-level ready flag. Only these three codes appear in blockers[].

Each blocker includes:

FieldTypeDescription
codeBlockerCodeMachine-readable identifier
connectionIdnumberConnection this blocker applies to
crmstringCRM profile enum (e.g. HUBSPOT, SALESFORCE)
messagestringHuman-readable explanation of what is wrong
remediationstringActionable next step, including dashboard deep links where applicable
docUrlstringLink to this documentation section for the blocker code
CodeConditionGates ready
crm_disconnectedCRM OAuth token missingYes
sync_not_enabledcanWebhook is false (account not authorized to sync)Yes
no_sourcescanWebhook is true but zero inbound sources configuredYes

Warnings are optional gaps or non-fatal issues. They never gate ready. A connection can be ready: true with warnings present.

Each warning includes the same fields as blockers (code, connectionId, crm, message, remediation, docUrl).

CodeConditionGates ready
destinations_not_configuredcanUserAccount is true but no forwarding URLs boundNo
blocklists_not_configuredcanBlockList is true but no enabled block listNo
blocklists_errorEnabled block list has lastError setNo

When a feature is disabled on the plan (canUserAccount or canBlockList is false), the component status is disabled and no warning is emitted — the customer chose not to use that feature.

Per connection:

crmConnection

  • refreshToken != nullready
  • refreshToken == nulldisconnected + blocker crm_disconnected

sources

  • canWebhook == falsedisabled + blocker sync_not_enabled
  • canWebhook && count == 0not_configured + blocker no_sources
  • count > 0ready

destinations (component detail; may also surface as warnings[])

  • canUserAccount == falsedisabled (no warning)
  • zero destination bindings → not_configured + warning destinations_not_configured
  • ≥1 binding → ready

blocklists (component detail; may also surface as warnings[])

  • canBlockList == falsedisabled (no warning)
  • no lists or none enabled → not_configured + warning blocklists_not_configured
  • any enabled list with lastError != nullerror + warning blocklists_error
  • otherwise → ready

Connection ready: crmConnection.status === "ready" && sources.status === "ready"

Top-level ready: connections.length > 0 && every(connection.ready)

Responses never include: refreshToken, settings, details, keyHash, apiKeyId, salesfinityWebhookSecret.

refreshToken is read from the database only to derive crmConnected status; the token value is discarded before any response assembly.

FieldEndpointNote
sources[].url/sourcesContains the webhook ingress code. Treat API keys like secrets — anyone with read access can obtain paste URLs.
destinations[].url/sourcesCustomer-configured forwarding URLs. Only returned for bindings owned by the same connection.
blocklists.lastError/account/statusOperational error text from CRM sync jobs. May contain vendor API messages; surfaced in warnings[] when applicable.
account.email/mePII; only returned on the identity endpoint.
StatusMeaning
401Missing/invalid/revoked API key (WWW-Authenticate: Bearer realm="OutboundSync API")
403Valid key but no API-enabled connections (canUseApi)
429Per-IP or per-account rate limit exceeded (Retry-After header set)

API keys are scoped to accessibleConnectionIds resolved at auth time. Connection-scoped keys see exactly one connection. All list queries re-apply deletedAt: null on connections. See Errors and rate limits for the full error contract and retry guidance.

  • Endpoints are read-only; the only write on authenticated requests is fire-and-forget lastUsedAt on the API key (existing auth guard behavior).
  • Status is DB-derived; no live CRM calls that would expand the data processing boundary.
  • Scope enforcement (scopes[]) is stored on keys but not yet checked per-endpoint — all issued keys currently receive read only.
  • lastEventReceivedAt on sources (requires WebhookLog index migration)
  • POST /api/v1/connections/:id/test (live CRM token probe)
  • GET /api/v1/blocklists
  • Standalone /api/v1/destinations resource
  • OpenAPI spec
Using the OutboundSync API v1 (https://outboundsync.com/docs/api/v1/), write a function that:
1. Reads OUTBOUNDSYNC_API_KEY from the environment.
2. Calls GET https://app.outboundsync.com/api/v1/account/status with Bearer authentication.
3. Returns `ready`, plus any blockers[] and warnings[] (code, message, remediation).
Handle 401, 403, and 429 per https://outboundsync.com/docs/api/errors-and-rate-limits/.