Integrations Live
This is not a general third-party-connections resource. It is the OAuth controller behind the custom-domain setup wizard: connect a DNS provider so message.com can apply the sending-domain records (MX, SPF, DKIM) for you instead of you copying them into your registrar by hand. Four providers: cloudflare, vercel, digitalocean, gcp.
Business integrations like Shopify and WordPress are NOT under this resource. They connect through their own dedicated flows: the Shopify app and the WordPress plugin. There is no Stripe, HubSpot, or Salesforce connection here either; see the sync tutorials for those.
List connected DNS providers
Returns the workspace's active (non-revoked) provider connections. No filters.
Code samples
curl 'https://app.message.com/api/v1/integrations' \
-H 'Authorization: Bearer YOUR_WORKSPACE_JWT'const res = await fetch('https://app.message.com/api/v1/integrations', {
headers: { Authorization: 'Bearer ' + token }
});
const { integrations } = await res.json();import requests
r = requests.get(
"https://app.message.com/api/v1/integrations",
headers={"Authorization": f"Bearer {token}"},
)
integrations = r.json()["integrations"]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
$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"];{
"integrations": [
{
"provider": "cloudflare",
"providerAccountId": "cf-account-id",
"connectedAt": "2026-05-13T15:30:00Z",
"metadata": null
}
]
}Supported providers
| Provider | Notes |
|---|---|
cloudflare | Account-level OAuth (same endpoints Wrangler uses). |
vercel | Lights up once its marketplace listing is approved. |
digitalocean | Self-serve. |
gcp | Self-serve. Requires an extra step to pick a Cloud DNS project after OAuth. |
Start a connection
Browser-navigate the admin here (not a fetch call: this redirects to the provider's OAuth authorize page). 503 oauth_not_configured if that provider's credentials aren't configured server-side yet.
The provider redirects here after approval. Public (no auth header: the provider calls it directly), verified via a signed OAuth state parameter. On success or failure it redirects the browser back into the dashboard's domain-setup wizard.
GCP: pick a Cloud DNS project
GCP-only extra step: after OAuth, list the projects the grant can see, then POST the chosen projectId onto the integration before applying records.
Apply DNS records
Pushes the workspace's email domain's (or a specific sending domain's) DNS records into the connected provider's zone. SPF is merged into any existing TXT record rather than overwritten; an existing DMARC record is left alone.
| Field | Type | Description |
|---|---|---|
| domainrequired | string | The apex domain whose records to apply. |
| sendingDomainIdoptional | uuid | Apply a specific sending domain's records instead of the workspace's single legacy email domain. |
{ "domain": "acme.com" }{
"records": [
{ "type": "MX", "name": "@", "purpose": "inbound routing", "success": true },
{ "type": "TXT", "name": "@", "purpose": "spf", "success": true, "merged": true },
{ "type": "CNAME", "name": "resend._domainkey", "purpose": "dkim", "success": true }
],
"allOk": true
}Disconnect
Revokes the connection (soft: stamps revokedAt, doesn't remove a row). Does not remove DNS records already applied at the provider; those keep working.
Errors
| Code | When |
|---|---|
400 invalid_provider | Provider param failed validation. |
404 unknown_provider | Provider isn't one of the four supported. |
404 integration_not_found | No active connection for that provider on this workspace. |
400 no_email_domain | Apply-records called with no email domain registered yet. |
503 oauth_not_configured | That provider's OAuth client credentials aren't set server-side. |
503 resend_not_configured / 502 resend_error | Apply-records couldn't read the domain's records from the email provider. |
Common pitfalls
- Looking for Shopify/Stripe/HubSpot/Salesforce here. Wrong resource. Those are separate integrations (plugin, app, or CRM-sync tutorial), not OAuth providers under this path.
- Calling
/startwith fetch. It's a redirect flow, not a JSON API call. Navigate the browser to it. - Applying records before registering an email domain.
apply-recordsneeds a domain (orsendingDomainId) to pull records from first.