message.comDevelopers

Integrations Live

Third-party connections live behind a single resource. OAuth-based integrations (Shopify, Stripe, HubSpot, Salesforce, Cloudflare) return an auth URL; API-key integrations (Slack incoming webhook, generic webhook) take credentials directly. List, connect, configure, and disconnect from one consistent surface.

List integrations

GET/api/v1/integrationsAuth: Bearer

Returns all configured integrations for the workspace. Filters: kind, status (connected, pending, disconnected).

Code samples

cURL
curl 'https://app.message.com/api/v1/integrations' \
  -H 'Authorization: Bearer YOUR_WORKSPACE_JWT'
JavaScript
const res = await fetch('https://app.message.com/api/v1/integrations', {
  headers: { Authorization: 'Bearer ' + token }
});
const { integrations } = await res.json();
Python
import requests
r = requests.get(
    "https://app.message.com/api/v1/integrations",
    headers={"Authorization": f"Bearer {token}"},
)
integrations = r.json()["integrations"]
Ruby
require "net/http"
require "json"
uri = URI("https://app.message.com/api/v1/integrations")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  req = Net::HTTP::Get.new(uri)
  req["Authorization"] = "Bearer #{token}"
  http.request(req)
end
integrations = JSON.parse(res.body)["integrations"]
PHP
<?php
$ctx = stream_context_create([
  "http" => ["method" => "GET", "header" => "Authorization: Bearer $token"]
]);
$integrations = json_decode(file_get_contents("https://app.message.com/api/v1/integrations", false, $ctx), true)["integrations"];
200 OK · integration
{
  "id": "uuid",
  "kind": "shopify",
  "status": "connected",
  "config": {
    "shopDomain": "acme.myshopify.com",
    "scopes": ["read_orders", "read_customers", "read_products"]
  },
  "connectedAt": "2026-05-13T15:30:00Z",
  "createdAt": "2026-05-13T15:30:00Z"
}

Available integration kinds

KindModeStatus
shopifyOAuthComing soon
stripeOAuthPlanned
wordpressOAuthComing soon
cloudflareOAuthPlanned
hubspotOAuthPlanned
salesforceOAuthPlanned
slack_webhookAPI keyLive
generic_webhookAPI keyLive

Start a connection

POST/api/v1/integrationsAuth: Bearer

For OAuth kinds, returns an auth URL you redirect the user to. After they approve, the provider redirects to our callback, which completes the connection and notifies the dashboard. For API-key kinds, takes credentials in the body and returns status: connected immediately.

FieldTypeDescription
kindrequiredenumOne of the kinds in the table above.
configoptionalobjectOptional kind-specific config (e.g., Shopify shop domain). OAuth kinds discover most config from the provider; API-key kinds carry credentials here.
200 OK · OAuth flow
{
  "authUrl": "https://acme.myshopify.com/admin/oauth/authorize?client_id=...&scope=...&state=..."
}

Update an integration

PATCH/api/v1/integrations/:idAuth: Bearer

Update integration-specific config (e.g., which Shopify scopes to use, which Slack channel to post to). Requires expectedVersion.

Disconnect

DELETE/api/v1/integrations/:idAuth: Bearer

Disconnects the integration. For OAuth integrations, we also revoke the access token on the provider side. Inbound data already synced is preserved; future syncs stop immediately.

Test a connection

POST/api/v1/integrations/:id/testAuth: Bearer

Pings the upstream provider to verify the credentials still work. Used by the dashboard "test connection" button. Returns { "ok": true } or the underlying error.

Errors

CodeWhen
400 invalid_bodyKind unknown or config invalid for kind.
402 plan_limitWorkspace plan does not include the requested kind.
403 forbiddenAgent role is not admin.
409 conflictAn integration of this kind already exists; some kinds are singletons.
422 oauth_failedProvider rejected the OAuth callback. Inspect detail.providerError.

Common pitfalls

  • Forgetting to handle the OAuth redirect. The auth URL goes to the provider, then back to our callback. Your client polls /integrations/:id for status: connected.
  • Storing API keys in config for OAuth kinds. Ignored. OAuth flows persist tokens server-side.
  • Mixing test and production credentials. Use a separate workspace (or wait for sandbox API keys) for staging.