Developers

The trustyourinbox API

Pull your domains, reports, senders, and issues into your own scripts and dashboards, automate fixes, and register outbound webhooks for a signed push the moment something breaks. Authenticate with a workspace API key over HTTPS; every response is JSON.

Authentication

Every request authenticates with a workspace API key sent as a bearer token in the Authorization header. Keys are header-only, never a cookie, and there is no browser CORS, so calls are made server-to-server.

Mint a key in the app under Settings, Integrations, API keys. A key carries a read scope and, optionally, a write scope; a write also requires that the creator's role still allows edits, so revoking a role revokes the key's writes live. API keys are available on the Pro plan and up.

Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx

Base URL and versioning

The base URL is https://api.trustyourinbox.com/v1. The /v1 path is a versioned, stable contract: existing fields will not change shape, and new fields are added without a version bump. Every response is JSON with Cache-Control: no-store.

Rate limits

Requests are rate-limited per key (120 requests per 60 seconds). When the limit is exceeded the API returns 429 with a Retry-After header (seconds); back off for that long and retry. Staging DNS fixes has a separate, stricter cap (five changes per 24 hours).

Errors

Errors use a stable envelope: an error machine code and a human-readable message. A 429 also carries retryAfterSec. Switch on error, not the message text.

{ "error": "invalid_request", "message": "name is required" }
CodeWhen
unauthorizedThe API key is missing, malformed, revoked, or expired.
forbiddenA read-only key (or a role without edit rights) attempted a write.
plan_requiredAPI keys need the Pro plan or higher; the workspace is below it.
not_foundThe domain, report, or change is not in the key's workspace.
invalid_requestThe body or a parameter failed validation.
conflictThe resource already exists, or its state blocks the action.
plan_limitA plan cap was reached (for example the domain limit).
aup_blockThe domain fails the acceptable use policy.
idempotency_in_progressA request with the same Idempotency-Key is still running.
idempotency_key_reusedThe Idempotency-Key was reused for a different request body.
rate_limitedThe per-key rate limit was exceeded; honor Retry-After.
internalAn unexpected server error. Safe to retry.

Idempotency

Creating writes (add a domain, stage a DNS fix, identify a sender) accept an optional Idempotency-Key header. A retry with the same key replays the original response instead of acting twice. Reusing a key for a different body returns idempotency_key_reused; keys are remembered for 24 hours.

Ranges

Endpoints over a time window take a range query parameter in days (default 30, clamped to 90). The reports endpoint takes limit instead (default 50, clamped to 200).

Quickstart

Mint a Pro-plan API key, then call the workspace health endpoint to confirm it works:

Request
curl https://api.trustyourinbox.com/v1/workspace/health \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "alignmentPct": 98,
  "trendDeltaPp": 2,
  "totalMessages": 14820,
  "totalReports": 36,
  "totalDomains": 6
}

Prefer a GUI? Use Open in Postman above to download a ready-to-import collection of every endpoint, then import it into Postman (File, then Import). Set the apiKey collection variable to your key once and every request sends it. The API has no browser CORS, so requests run from Postman, curl, or your server, not from this page.

Domains#

get/v1/domains

List the domains in the workspace (public REST API) #

Public REST API. Served at https://api.trustyourinbox.com/v1/domains (the api host rewrites /v1/* to /api/v1/*). Bearer API key; read scope; scoped to the key's workspace. Rate-limited (120/60s per key).

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200The workspace's domains
domainsarray of objectrequired
namestringrequired
statusenumrequired
One of: pending · verified · paused · deleted
purposeenumrequired
One of: sending · monitor_only
dnsProviderstringnullablerequired
createdAtstring · date-timerequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
429Rate limited
curl https://api.trustyourinbox.com/v1/domains?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domains": [
    {
      "name": "acme.com",
      "status": "pending",
      "purpose": "sending",
      "dnsProvider": "cloudflare",
      "createdAt": "2026-06-01T00:00:00Z"
    },
    {
      "name": "shop.acme.com",
      "status": "pending",
      "purpose": "sending",
      "dnsProvider": "cloudflare",
      "createdAt": "2026-06-08T00:00:00Z"
    }
  ]
}
post/v1/domains

Add a domain to the workspace (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope (the key carries `write` AND the creator's live role allows edits). Reuses the same add-domain core the dashboard uses - validation, the plan domain cap, the AUP gate, provider detection, insert, and audit. Honors an optional Idempotency-Key header (a retry replays the created domain). Audited "via API key X".

Requires a write-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

namestringrequired

The domain to add, e.g. acme.com

purposeenum

Defaults to sending.

One of: sending · monitor_only
201Domain added (pending verification); body carries the TXT to publish
domainstringrequired
statusstringrequired
purposeenumrequired
One of: sending · monitor_only
verificationobjectrequired
recordTypestringrequired
recordNamestringrequired
recordValuestringrequired
dnsProviderstringnullablerequired
400invalid_request (missing/invalid name)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
409conflict (duplicate) or plan_limit
422aup_block (domain fails the acceptable use policy)
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/domains?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6" \
  -d '{
  "name": "acme.com",
  "purpose": "sending"
}'
Response 201
{
  "domain": "acme.com",
  "status": "verified",
  "purpose": "sending",
  "verification": {
    "recordType": "TXT",
    "recordName": "_dmarc.acme.com",
    "recordValue": "v=DMARC1; p=reject; rua=mailto:dmarc@acme.com"
  },
  "dnsProvider": "cloudflare"
}
post/v1/domains/{domain}/recheck

Re-detect the domain's DNS provider now (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Re-runs DNS-provider detection immediately instead of waiting for the daily sweep (after moving DNS / connecting a provider). No body. Reuses refreshDnsProviderForDomain; audited "via API key X" only when the provider flips.

Requires a write-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Re-checked (body reports the detected provider + whether it changed)
domainstringrequired
detectedbooleanrequired
providerstringrequired
providerNamestring

Present only when detected is true.

changedbooleanrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404Domain not found in the caller's workspace
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/domains/acme.com/recheck?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "detected": true,
  "provider": "cloudflare",
  "providerName": "Mailchimp",
  "changed": false
}

Authentication & deliverability#

get/v1/domains/{domain}/compliance

The four mandate compliance tiles for one domain (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; the domain must belong to the key's workspace.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Compliance tiles
domainstringrequired
complianceobjectrequired
googleobjectrequired

One mandate tile (Google/Yahoo, Microsoft, BIMI, or TLS) for a domain.

idenumrequired
One of: google · microsoft · bimi · tls
titlestringrequired
tierenumrequired
One of: pass · at_risk · fail · not_set_up · coming_soon · no_data
compliantCountintegernullablerequired
totalScoredintegernullablerequired
nounstringrequired
microsoftobjectrequired

One mandate tile (Google/Yahoo, Microsoft, BIMI, or TLS) for a domain.

idenumrequired
One of: google · microsoft · bimi · tls
titlestringrequired
tierenumrequired
One of: pass · at_risk · fail · not_set_up · coming_soon · no_data
compliantCountintegernullablerequired
totalScoredintegernullablerequired
nounstringrequired
bimiobjectrequired

One mandate tile (Google/Yahoo, Microsoft, BIMI, or TLS) for a domain.

idenumrequired
One of: google · microsoft · bimi · tls
titlestringrequired
tierenumrequired
One of: pass · at_risk · fail · not_set_up · coming_soon · no_data
compliantCountintegernullablerequired
totalScoredintegernullablerequired
nounstringrequired
tlsobjectrequired

One mandate tile (Google/Yahoo, Microsoft, BIMI, or TLS) for a domain.

idenumrequired
One of: google · microsoft · bimi · tls
titlestringrequired
tierenumrequired
One of: pass · at_risk · fail · not_set_up · coming_soon · no_data
compliantCountintegernullablerequired
totalScoredintegernullablerequired
nounstringrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/compliance?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "compliance": {
    "google": {
      "id": "google",
      "title": "Google and Yahoo bulk-sender requirements",
      "tier": "pass",
      "compliantCount": 3,
      "totalScored": 14,
      "noun": "domains"
    },
    "microsoft": {
      "id": "google",
      "title": "Google and Yahoo bulk-sender requirements",
      "tier": "pass",
      "compliantCount": 3,
      "totalScored": 14,
      "noun": "domains"
    },
    "bimi": {
      "id": "google",
      "title": "Google and Yahoo bulk-sender requirements",
      "tier": "pass",
      "compliantCount": 3,
      "totalScored": 14,
      "noun": "domains"
    },
    "tls": {
      "id": "google",
      "title": "Google and Yahoo bulk-sender requirements",
      "tier": "pass",
      "compliantCount": 3,
      "totalScored": 14,
      "noun": "domains"
    }
  }
}
get/v1/domains/{domain}/enforcement-simulation

Enforcement Preview: what a stricter DMARC policy would have done (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. Replays the last 30 days of receiver-reported mail under each ladder scenario (the recommended next step plus the p=reject end state): spoof that would have been stopped, the domain's own senders that would break, the forwarding gray zone, and subdomain handling under sp. A replay of receiver reports (1 to 2 day lag), not a prediction. Stage the flip with POST /v1/domains/{domain}/dns-fixes.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Enforcement simulation
domainstringrequired
windowDaysintegerrequired
purposeenumrequired
One of: sending · monitor_only
currentobjectrequired
hasRecordbooleanrequired
policystringnullablerequired
spstringnullablerequired
pctintegernullablerequired
testModebooleanrequired
fullyEnforcedbooleanrequired
alignmentPctintegernullablerequired

Spoofer-adjusted (never raw aligned/total).

totalVolumeintegerrequired
nextStepobjectrequired
stepstringrequired
reasonstringrequired
fixTypestringnullablerequired
daysRemainingintegernullablerequired
scenariosarray of objectrequired

One counterfactual per ladder scenario (the recommended next step first, then the p=reject end state). Empty at p=reject.

kindenumrequired
One of: policy_step · bump_pct · disable_test_mode
targetPolicyenumrequired
One of: quarantine · reject
effectiveSubdomainPolicyenumrequired
One of: none · quarantine · reject
verdictenumrequired
One of: clear_to_flip · fix_senders_first · investigate · wait · already_enforced · no_data
summarystringrequired
totalsobjectrequired
totalintegerrequired
unaffectedintegerrequired
newlyAffectedintegerrequired
alreadyEnforcedintegerrequired
notCoveredintegerrequired
newlyAffectedBySegmentobjectrequired
spoofintegerrequired
senderMisconfigintegerrequired
forwardingintegerrequired
unclassifiedintegerrequired
alreadyEnforcedBySegmentobjectrequired
spoofintegerrequired
senderMisconfigintegerrequired
forwardingintegerrequired
unclassifiedintegerrequired
forwardingWithOverrideintegerrequired
senderRiskarray of objectrequired
namestringrequired
categorystringnullablerequired
newlyAffectedintegerrequired
totalMessagesintegerrequired
alignedMessagesintegerrequired
firstDaystringrequired
lastDaystringrequired
subdomainsarray of stringrequired
senderRiskDroppedintegerrequired
subdomainsarray of objectrequired
headerFromstringrequired
effectivePolicyenumrequired
One of: none · quarantine · reject
messagesintegerrequired
alignedMessagesintegerrequired
newlyAffectedintegerrequired
notCoveredintegerrequired
subdomainsDroppedintegerrequired
overridesarray of objectrequired
typestringrequired
messagesintegerrequired
dailySeriesarray of objectrequired
daystringrequired
spoofintegerrequired
riskintegerrequired
otherintegerrequired
watchobjectnullablerequired

The domain's ACTIVE post-flip watch (14 days after a detected policy strengthening), or null. The watch reads receiver reports and alerts on regression with a one-click rollback; it never writes DNS on its own.

toPolicystringrequired
changeDetectedAtstringrequired
watchUntilstringrequired
regressionDetectedAtstringnullablerequired
regressionSenderNamesarray of stringrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/enforcement-simulation?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "windowDays": 0,
  "purpose": "sending",
  "current": {
    "hasRecord": true,
    "policy": "reject",
    "sp": "reject",
    "pct": 98,
    "testMode": true
  },
  "fullyEnforced": true,
  "alignmentPct": 98,
  "totalVolume": 1240,
  "nextStep": {
    "step": "example",
    "reason": "example",
    "fixType": "dmarc.add_np_reject",
    "daysRemaining": 0
  },
  "scenarios": [
    {
      "kind": "policy_step",
      "targetPolicy": "quarantine",
      "effectiveSubdomainPolicy": "none",
      "verdict": "clear_to_flip",
      "summary": "example",
      "totals": {
        "total": 1240,
        "unaffected": 0,
        "newlyAffected": 0,
        "alreadyEnforced": 0,
        "notCovered": 0
      },
      "newlyAffectedBySegment": {
        "spoof": 0,
        "senderMisconfig": 0,
        "forwarding": 0,
        "unclassified": 0
      },
      "alreadyEnforcedBySegment": {
        "spoof": 0,
        "senderMisconfig": 0,
        "forwarding": 0,
        "unclassified": 0
      },
      "forwardingWithOverride": 0,
      "senderRisk": [
        {
          "name": "acme.com",
          "category": "esp_marketing",
          "newlyAffected": 0,
          "totalMessages": 1240,
          "alignedMessages": 0,
          "firstDay": "example",
          "lastDay": "example",
          "subdomains": [
            "example",
            "example"
          ]
        },
        {
          "name": "shop.acme.com",
          "category": "esp_marketing",
          "newlyAffected": 0,
          "totalMessages": 360,
          "alignedMessages": 0,
          "firstDay": "example",
          "lastDay": "example",
          "subdomains": [
            "example",
            "example"
          ]
        }
      ],
      "senderRiskDropped": 0,
      "subdomains": [
        {
          "headerFrom": "example",
          "effectivePolicy": "none",
          "messages": 0,
          "alignedMessages": 0,
          "newlyAffected": 0,
          "notCovered": 0
        },
        {
          "headerFrom": "example",
          "effectivePolicy": "none",
          "messages": 0,
          "alignedMessages": 0,
          "newlyAffected": 0,
          "notCovered": 0
        }
      ],
      "subdomainsDropped": 0,
      "overrides": [
        {
          "type": "tls_rpt_missing",
          "messages": 0
        },
        {
          "type": "tls_rpt_missing",
          "messages": 0
        }
      ],
      "dailySeries": [
        {
          "day": "example",
          "spoof": 0,
          "risk": 0,
          "other": 0
        },
        {
          "day": "example",
          "spoof": 0,
          "risk": 0,
          "other": 0
        }
      ]
    },
    {
      "kind": "policy_step",
      "targetPolicy": "quarantine",
      "effectiveSubdomainPolicy": "none",
      "verdict": "clear_to_flip",
      "summary": "example",
      "totals": {
        "total": 1240,
        "unaffected": 0,
        "newlyAffected": 0,
        "alreadyEnforced": 0,
        "notCovered": 0
      },
      "newlyAffectedBySegment": {
        "spoof": 0,
        "senderMisconfig": 0,
        "forwarding": 0,
        "unclassified": 0
      },
      "alreadyEnforcedBySegment": {
        "spoof": 0,
        "senderMisconfig": 0,
        "forwarding": 0,
        "unclassified": 0
      },
      "forwardingWithOverride": 0,
      "senderRisk": [
        {
          "name": "acme.com",
          "category": "esp_marketing",
          "newlyAffected": 0,
          "totalMessages": 1240,
          "alignedMessages": 0,
          "firstDay": "example",
          "lastDay": "example",
          "subdomains": [
            "example",
            "example"
          ]
        },
        {
          "name": "shop.acme.com",
          "category": "esp_marketing",
          "newlyAffected": 0,
          "totalMessages": 360,
          "alignedMessages": 0,
          "firstDay": "example",
          "lastDay": "example",
          "subdomains": [
            "example",
            "example"
          ]
        }
      ],
      "senderRiskDropped": 0,
      "subdomains": [
        {
          "headerFrom": "example",
          "effectivePolicy": "none",
          "messages": 0,
          "alignedMessages": 0,
          "newlyAffected": 0,
          "notCovered": 0
        },
        {
          "headerFrom": "example",
          "effectivePolicy": "none",
          "messages": 0,
          "alignedMessages": 0,
          "newlyAffected": 0,
          "notCovered": 0
        }
      ],
      "subdomainsDropped": 0,
      "overrides": [
        {
          "type": "tls_rpt_missing",
          "messages": 0
        },
        {
          "type": "tls_rpt_missing",
          "messages": 0
        }
      ],
      "dailySeries": [
        {
          "day": "example",
          "spoof": 0,
          "risk": 0,
          "other": 0
        },
        {
          "day": "example",
          "spoof": 0,
          "risk": 0,
          "other": 0
        }
      ]
    }
  ],
  "watch": {
    "toPolicy": "example",
    "changeDetectedAt": "example",
    "watchUntil": "example",
    "regressionDetectedAt": "example",
    "regressionSenderNames": [
      "example",
      "example"
    ]
  }
}
get/v1/domains/{domain}/senders

Sender breakdown with spoofer-adjusted alignment (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. The alignment headline is spoofer-adjusted (the Q12 invariant) - it matches the dashboard, not raw aligned/total.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

rangeinteger

Window in days (clamped to 90, default 30)

200Sender breakdown
domainstringrequired
rangeDaysintegerrequired
totalVolumeintegerrequired
alignmentPctintegernullablerequired

Spoofer-adjusted (never raw aligned/total).

blockedSpoofintegerrequired
knownVolumeinteger

Present only when totalVolume > 0.

unknownVolumeinteger

Present only when totalVolume > 0.

distinctSendersinteger

Present only when totalVolume > 0.

sendersarray of objectrequired
ipstringrequired
networkstringnullablerequired

The ASN / org name for the IP.

volumeintegerrequired
alignedPctintegerrequired
knownbooleanrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/senders?workspace=value&range=30 \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "rangeDays": 30,
  "totalVolume": 1240,
  "alignmentPct": 98,
  "blockedSpoof": 318,
  "knownVolume": 0,
  "unknownVolume": 0,
  "distinctSenders": 0,
  "senders": [
    {
      "ip": "203.0.113.10",
      "network": "Google LLC",
      "volume": 1240,
      "alignedPct": 98,
      "known": true
    },
    {
      "ip": "198.51.100.24",
      "network": "Amazon.com, Inc.",
      "volume": 360,
      "alignedPct": 94,
      "known": true
    }
  ]
}
get/v1/domains/{domain}/protocol

Published authentication records for a domain (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. The DMARC / SPF / DKIM / MTA-STS records and what's wrong with them - mirrors the MCP get_protocol_status payload.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Authentication records
domainstringrequired
dmarcobjectnullablerequired
policystringrequired
pctintegernullablerequired
testModeenumnullablerequired

DMARCbis t= - "y" means published but receivers don't enforce.

One of: y · n
npstringnullablerequired

DMARCbis non-existent-subdomain policy.

reportsToUsbooleannullablerequired
multiRecordbooleannullablerequired
spfobjectnullablerequired
lookupCountintegernullablerequired

DNS lookups consumed vs the RFC 7208 limit of 10.

allQualifierstringnullablerequired

The qualifier on the final all mechanism (~, -, +, ?).

multiRecordbooleannullablerequired
dkimSelectorsintegerrequired

Count of published selectors found.

dkimMinKeyBitsintegernullablerequired

Smallest published key size in bits.

mtaStsstringnullablerequired

MTA-STS mode (testing / enforce), or null when not published.

400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/protocol?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "dmarc": {
    "policy": "reject",
    "pct": 98,
    "testMode": "y",
    "np": "reject",
    "reportsToUs": true,
    "multiRecord": false
  },
  "spf": {
    "lookupCount": 7,
    "allQualifier": "~",
    "multiRecord": false
  },
  "dkimSelectors": 2,
  "dkimMinKeyBits": 2048,
  "mtaSts": "enforce"
}
get/v1/domains/{domain}/dkim-rotations

DKIM key rotation state for a domain (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. Rotations in flight through the guided wizard (planned -> new key published -> new key signing -> old key retired) with the RUA-observed signing evidence a published key waits on, plus the last completed rotation - mirrors the MCP get_dkim_rotations payload. Read-only; rotations are started and advanced in the dashboard's DKIM tab, where the private key is generated in the browser.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200DKIM rotation state
domainstringrequired
activearray of objectrequired

Non-terminal rotations, oldest first (the wizard's render order).

idstring · uuidrequired
oldSelectorstringrequired
newSelectorstringrequired
vendorstringnullablerequired

Vendor label of the old selector at rotation start; null = long-tail self-hosted.

custodyenumrequired
One of: self_hosted · esp
stateenumrequired
One of: planned · new_key_published · new_key_signing · old_key_retired
createdAtstring · date-timerequired
newKeyPublishedAtstring · date-timenullablerequired
newKeySigningAtstring · date-timenullablerequired
oldKeyRetiredAtstring · date-timenullablerequired
ruaEvidenceobjectnullablerequired

RUA-observed signing evidence for the new selector; populated only in state new_key_published (reports lag 1-2 days).

passVolumenumberrequired
totalVolumenumberrequired
lastReportAtstring · date-timenullablerequired
lastCompletedobjectnullablerequired
oldSelectorstringrequired
newSelectorstringrequired
completedAtstring · date-timenullablerequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/dkim-rotations?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "active": [
    {
      "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
      "oldSelector": "example",
      "newSelector": "example",
      "vendor": "example",
      "custody": "self_hosted",
      "state": "planned",
      "createdAt": "2026-06-01T00:00:00Z",
      "newKeyPublishedAt": "2026-06-01T00:00:00Z",
      "newKeySigningAt": "2026-06-01T00:00:00Z",
      "oldKeyRetiredAt": "2026-06-01T00:00:00Z",
      "ruaEvidence": {
        "passVolume": 0,
        "totalVolume": 1240,
        "lastReportAt": "2026-06-01T00:00:00Z"
      }
    },
    {
      "id": "2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
      "oldSelector": "example",
      "newSelector": "example",
      "vendor": "example",
      "custody": "self_hosted",
      "state": "planned",
      "createdAt": "2026-06-08T00:00:00Z",
      "newKeyPublishedAt": "2026-06-08T00:00:00Z",
      "newKeySigningAt": "2026-06-08T00:00:00Z",
      "oldKeyRetiredAt": "2026-06-08T00:00:00Z",
      "ruaEvidence": {
        "passVolume": 0,
        "totalVolume": 360,
        "lastReportAt": "2026-06-08T00:00:00Z"
      }
    }
  ],
  "lastCompleted": {
    "oldSelector": "example",
    "newSelector": "example",
    "completedAt": "2026-06-01T00:00:00Z"
  }
}
get/v1/domains/{domain}/subdomains

Subdomains sending as a domain, bucketed (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. One row per sending subdomain with its spoofer-adjusted alignment and a Known / Review / Not in DNS bucket - mirrors the MCP get_subdomain_breakdown payload. Probes live DNS for the "Not in DNS" split.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

rangeinteger

Window in days (clamped to 90, default 30)

200Subdomain breakdown
domainstringrequired
rangeDaysintegerrequired
subdomainCountintegerrequired
knownCountinteger

Present only when subdomainCount > 0.

worthALookCountinteger

Present only when subdomainCount > 0.

nonexistentCountinteger

Present only when subdomainCount > 0.

unrecognizedCountinteger

Present only when subdomainCount > 0.

totalVolumeinteger

Present only when subdomainCount > 0.

nxdomainPolicystringnullable

What a non-existent subdomain resolves to (np ?? sp ?? p). Present only when subdomainCount > 0.

extendedSubdomainCountintegerrequired

Distinct subdomains over a wider 90-day lookback (subdomain abuse is bursty).

subdomainsarray of objectrequired
subdomainstringrequired
labelstringrequired

The relative label (e.g. "marketing" for marketing.acme.com).

statusenumrequired
One of: Known · Review · Not in DNS
bucketenumrequired
One of: known · worth_a_look · nonexistent
volumeintegerrequired
alignmentPctintegernullablerequired

Spoofer-adjusted; null when no legit mail is measurable.

spoofVolumeintegerrequired
blockedSpoofintegerrequired
distinctSendersintegerrequired
lastSeenstring · date-timenullablerequired
inDnsbooleannullablerequired

true = the subdomain resolves; false = NXDOMAIN; null = inconclusive.

verdictstringrequired
whatItMeansstringrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/subdomains?workspace=value&range=30 \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "rangeDays": 30,
  "subdomainCount": 3,
  "knownCount": 3,
  "worthALookCount": 3,
  "nonexistentCount": 3,
  "unrecognizedCount": 3,
  "totalVolume": 1240,
  "nxdomainPolicy": "example",
  "extendedSubdomainCount": 3,
  "subdomains": [
    {
      "subdomain": "marketing.acme.com",
      "label": "marketing",
      "status": "Known",
      "bucket": "known",
      "volume": 1240,
      "alignmentPct": 98,
      "spoofVolume": 318,
      "blockedSpoof": 318,
      "distinctSenders": 0,
      "lastSeen": "2026-06-01T00:00:00Z",
      "inDns": true,
      "verdict": "Known sender",
      "whatItMeans": "This subdomain is recognized and aligned."
    },
    {
      "subdomain": "news.acme.com",
      "label": "news",
      "status": "Known",
      "bucket": "known",
      "volume": 360,
      "alignmentPct": 94,
      "spoofVolume": 42,
      "blockedSpoof": 42,
      "distinctSenders": 0,
      "lastSeen": "2026-06-08T00:00:00Z",
      "inDns": true,
      "verdict": "Known sender",
      "whatItMeans": "This subdomain is recognized and aligned."
    }
  ]
}
get/v1/domains/{domain}/spoof-activity

Blocked-spoof volume and top sources over a window (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. Uses the canonical blocked-spoof filter.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

rangeinteger

Window in days (clamped to 90, default 30)

200Spoof activity
domainstringrequired
rangeDaysintegerrequired
blockedSpoofintegerrequired
blockedSpoofPriorintegerrequired
topSourcesarray of objectrequired
ipstringrequired
attemptsintegerrequired
networkstringnullablerequired
countrystringnullablerequired
dispositionstringrequired
dailyarray of objectrequired
datestring · date-timerequired
volumeintegerrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/spoof-activity?workspace=value&range=30 \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "rangeDays": 30,
  "blockedSpoof": 318,
  "blockedSpoofPrior": 0,
  "topSources": [
    {
      "ip": "203.0.113.10",
      "attempts": 512,
      "network": "Google LLC",
      "country": "US",
      "disposition": "reject"
    },
    {
      "ip": "198.51.100.24",
      "attempts": 87,
      "network": "Amazon.com, Inc.",
      "country": "DE",
      "disposition": "reject"
    }
  ],
  "daily": [
    {
      "date": "2026-06-01T00:00:00Z",
      "volume": 1240
    },
    {
      "date": "2026-06-08T00:00:00Z",
      "volume": 360
    }
  ]
}

Reports#

get/v1/domains/{domain}/reports

Recent aggregate (RUA) reports for one domain (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. Newest first.

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

limitinteger

Max reports (clamped to 200, default 50)

200Recent reports
domainstringrequired
reportsarray of objectrequired
idstring · uuidrequired
reportingOrgstringrequired
rangeStartstring · date-timerequired
rangeEndstring · date-timerequired
volumeintegerrequired
passingintegerrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/reports?workspace=value&limit=50 \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "reports": [
    {
      "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
      "reportingOrg": "google.com",
      "rangeStart": "2026-06-01T00:00:00Z",
      "rangeEnd": "2026-06-01T00:00:00Z",
      "volume": 1240,
      "passing": 1198
    },
    {
      "id": "2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
      "reportingOrg": "Yahoo Inc.",
      "rangeStart": "2026-06-08T00:00:00Z",
      "rangeEnd": "2026-06-08T00:00:00Z",
      "volume": 360,
      "passing": 352
    }
  ]
}
get/v1/reports/{id}

Drill into one aggregate (RUA) report (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. The report's provider, window, outcome composition, and diagnosed failing senders - mirrors the MCP get_report payload. A report id from another tenant returns 404 with no existence leak.

Requires a read-scoped key (Bearer).
idstringrequired

aggregate-report id (from .../reports; workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Report detail
reportIdstring · uuidrequired
externalReportIdstringrequired
reportingOrgstringrequired
domainstringrequired
rangeStartstring · date-timerequired
rangeEndstring · date-timerequired
outcomeobjectrequired
alignedintegerrequired
dkimOnlyintegerrequired
spfOnlyintegerrequired
failedintegerrequired
totalintegerrequired
alignmentPctintegernullablerequired

Raw aligned/total - the report's factual composition.

spoofVolumeintegerrequired
adjustedPctintegernullablerequired

Verdict-grade alignment of the legitimate mail; null for an all-spoof report.

recordCountintegerrequired
failureGroupsarray of objectrequired
senderstringrequired
vendorNamestringnullablerequired
ipCountintegerrequired
failedVolumeintegerrequired
classenumrequired
One of: forwarding · esp_misconfig · spoof_likely · unknown
diagnosisstringrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Report not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/reports/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "reportId": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
  "externalReportId": "1a2b3c4d5e6f",
  "reportingOrg": "google.com",
  "domain": "acme.com",
  "rangeStart": "2026-06-01T00:00:00Z",
  "rangeEnd": "2026-06-01T00:00:00Z",
  "outcome": {
    "aligned": 1198,
    "dkimOnly": 22,
    "spfOnly": 8,
    "failed": 12,
    "total": 1240,
    "alignmentPct": 98,
    "spoofVolume": 318,
    "adjustedPct": 98,
    "recordCount": 9
  },
  "failureGroups": [
    {
      "sender": "example",
      "vendorName": "Mailchimp",
      "ipCount": 4,
      "failedVolume": 318,
      "class": "forwarding",
      "diagnosis": "Receivers cannot report TLS delivery problems for this domain."
    },
    {
      "sender": "example",
      "vendorName": "Mailchimp",
      "ipCount": 1,
      "failedVolume": 42,
      "class": "forwarding",
      "diagnosis": "Receivers cannot report TLS delivery problems for this domain."
    }
  ]
}

Issues#

get/v1/issues

Open issues across the workspace (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. Open (non-dismissed) issues across every domain, worst-first. Rate-limited (120/60s per key).

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Open issues
issuesarray of objectrequired
keystringrequired
typestringrequired

The anomaly type id (the issue's stable machine key).

severityenumrequired
One of: opportunity · warn · crit
headlinestringrequired
whystringrequired
domainstringrequired
firstSeenAtstring · date-timerequired
impactstringnullablerequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
429Rate limited
curl https://api.trustyourinbox.com/v1/issues?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "issues": [
    {
      "key": "tls_rpt_missing:acme.com",
      "type": "tls_rpt_missing",
      "severity": "opportunity",
      "headline": "TLS reporting is not configured",
      "why": "Receivers cannot report TLS delivery problems for this domain.",
      "domain": "acme.com",
      "firstSeenAt": "2026-06-01T00:00:00Z",
      "impact": "Low"
    },
    {
      "key": "tls_rpt_missing:acme.com",
      "type": "tls_rpt_missing",
      "severity": "opportunity",
      "headline": "TLS reporting is not configured",
      "why": "Receivers cannot report TLS delivery problems for this domain.",
      "domain": "acme.com",
      "firstSeenAt": "2026-06-08T00:00:00Z",
      "impact": "Low"
    }
  ]
}
get/v1/domains/{domain}/issues

Open issues for one domain (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope; workspace-scoped domain. Dismissal-aware (the same source the action inbox and digest read).

Requires a read-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Open issues for the domain
domainstringrequired
issuesarray of objectrequired
keystringrequired
typestringrequired

The anomaly type id (the issue's stable machine key).

severityenumrequired
One of: opportunity · warn · crit
headlinestringrequired
whystringrequired
domainstringrequired
firstSeenAtstring · date-timerequired
impactstringnullablerequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/issues?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "issues": [
    {
      "key": "tls_rpt_missing:acme.com",
      "type": "tls_rpt_missing",
      "severity": "opportunity",
      "headline": "TLS reporting is not configured",
      "why": "Receivers cannot report TLS delivery problems for this domain.",
      "domain": "acme.com",
      "firstSeenAt": "2026-06-01T00:00:00Z",
      "impact": "Low"
    },
    {
      "key": "tls_rpt_missing:acme.com",
      "type": "tls_rpt_missing",
      "severity": "opportunity",
      "headline": "TLS reporting is not configured",
      "why": "Receivers cannot report TLS delivery problems for this domain.",
      "domain": "acme.com",
      "firstSeenAt": "2026-06-08T00:00:00Z",
      "impact": "Low"
    }
  ]
}
post/v1/domains/{domain}/issues/{type}/dismiss

Dismiss / snooze an open issue (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Hides the issue: body { "permanent": false } snoozes 7 days (default), true dismisses indefinitely. Reverse with .../restore. Reuses dismissAnomalyCore (the same core the dashboard + MCP use); audited "via API key X".

Requires a write-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

typestringrequired

the issue (anomaly) type to hide, e.g. tls_rpt_missing

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

permanentboolean

true = dismiss indefinitely; false (default) = snooze 7 days.

200Issue dismissed / snoozed
domainstringrequired
typestringrequired
modeenumrequired
One of: dismiss · snooze
dismissedbooleanrequired
400invalid_request (unknown issue type)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404Domain not found in the caller's workspace
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/domains/acme.com/issues/tls_rpt_missing/dismiss?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "permanent": true
}'
Response 200
{
  "domain": "acme.com",
  "type": "tls_rpt_missing",
  "mode": "dismiss",
  "dismissed": true
}
post/v1/domains/{domain}/issues/{type}/restore

Restore a dismissed / snoozed issue (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Un-hides the issue so it returns to the open inbox. The inverse of .../dismiss. Reuses restoreAnomalyCore; audited "via API key X".

Requires a write-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

typestringrequired

the issue (anomaly) type to restore

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Issue restored
domainstringrequired
typestringrequired
restoredbooleanrequired
400invalid_request (unknown issue type)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404Domain not found in the caller's workspace
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/domains/acme.com/issues/tls_rpt_missing/restore?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "type": "tls_rpt_missing",
  "restored": true
}

DNS fixes#

post/v1/domains/{domain}/dns-fixes

Stage a one-click DNS fix for an issue (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Body { "type": "<issue_type>" } for a one-click-fixable issue. The fix is STAGED (not applied immediately) through the same 5-minute-delay / email-with-one-click-cancel / 24-hour-undo safety pipeline the dashboard + MCP use - no second DNS-write path. Reuses stageFixForAnomalyById; audited "via API key X". Honors Idempotency-Key (no double-stage).

Requires a write-scoped key (Bearer).
domainstringrequired

domain name (workspace-scoped)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

typestringrequired

A one-click-fixable issue type, e.g. dmarc_np_missing.

200Nothing to stage (the fix is already in place)
An object.
201Fix staged; body carries the change id, record, and apply time
Returns one of:
staged: true
domainstringrequired
typestringrequired
stagedbooleanrequired
changeIdstring · uuidrequired
recordNamestringrequired
newValuestringrequired
applyAtstring · date-timerequired
warningstring
staged: false
domainstringrequired
typestringrequired
stagedbooleanrequired
alreadyAppliedbooleanrequired
400invalid_request (not a one-click-fixable type / invalid input)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404Domain not found in the caller's workspace
409conflict (no provider connected, already pending, etc.)
429Rate limited (per key, or the 5-changes/24h staging cap)
curl -X POST https://api.trustyourinbox.com/v1/domains/acme.com/dns-fixes?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6" \
  -d '{
  "type": "tls_rpt_missing"
}'
Response 200
{}
get/v1/changes

Staged / in-undo-window DNS changes for the workspace (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. The read half of the staged-fix loop - DNS fixes currently staged (in the 5-minute pre-apply window) or recently applied but still inside the 24-hour undo window. Cancel one via DELETE /v1/changes/{id}.

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Active staged / in-undo-window changes
changesarray of objectrequired
idstring · uuidrequired
domainstringnullablerequired
fixTypestringrequired
recordNamestringrequired
recordTypestringrequired
statusstringrequired

staged, applied, canceled, etc.

stagedAtstring · date-timerequired
applyAtstring · date-timenullablerequired
undoUntilstring · date-timenullablerequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
429Rate limited
curl https://api.trustyourinbox.com/v1/changes?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "changes": [
    {
      "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
      "domain": "acme.com",
      "fixType": "dmarc.add_np_reject",
      "recordName": "_dmarc.acme.com",
      "recordType": "TXT",
      "status": "verified",
      "stagedAt": "2026-06-01T00:00:00Z",
      "applyAt": "2026-06-01T00:00:00Z",
      "undoUntil": "2026-06-01T00:00:00Z"
    },
    {
      "id": "2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
      "domain": "acme.com",
      "fixType": "dmarc.add_np_reject",
      "recordName": "_dmarc.acme.com",
      "recordType": "TXT",
      "status": "verified",
      "stagedAt": "2026-06-08T00:00:00Z",
      "applyAt": "2026-06-08T00:00:00Z",
      "undoUntil": "2026-06-08T00:00:00Z"
    }
  ]
}
delete/v1/changes/{id}

Cancel a staged DNS change (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Cancels a fix that is still staged (inside the 5-minute pre-apply window); an applied change has the 24-hour undo in the app. Reuses cancelStagedChange, workspace-scoped so a foreign change id can't be canceled. Audited "via API key X".

Requires a write-scoped key (Bearer).
idstringrequired

the staged change id (from GET /v1/changes)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Change canceled
canceledbooleanrequired
changeobjectnullablerequired

A staged or recently-applied one-click DNS change. The email cancel secret is never exposed.

idstring · uuidrequired
domainstringnullablerequired
fixTypestringrequired
recordNamestringrequired
recordTypestringrequired
statusstringrequired

staged, applied, canceled, etc.

stagedAtstring · date-timerequired
applyAtstring · date-timenullablerequired
undoUntilstring · date-timenullablerequired
400invalid_request (malformed id)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404No staged change with that id in the caller's workspace
409conflict (the change is no longer staged)
429Rate limited
curl -X DELETE https://api.trustyourinbox.com/v1/changes/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "canceled": true,
  "change": {
    "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
    "domain": "acme.com",
    "fixType": "dmarc.add_np_reject",
    "recordName": "_dmarc.acme.com",
    "recordType": "TXT",
    "status": "verified",
    "stagedAt": "2026-06-01T00:00:00Z",
    "applyAt": "2026-06-01T00:00:00Z",
    "undoUntil": "2026-06-01T00:00:00Z"
  }
}

Delivery Diagnosis#

get/v1/diagnosis

List Delivery Diagnosis cases (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. Recent Delivery Diagnosis cases for the workspace (bounces or spam-foldered messages forwarded to the minted diagnose address, or pasted headers), newest first. ?limit= (default 20, max 50). Mirrors the MCP list_diagnosis_cases tool's structured payload.

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

limitinteger
200Recent diagnosis cases
casesarray of objectrequired
idstringrequired
createdAtstringrequired
statusenumrequired
One of: received · analyzing · diagnosed · needs_headers · refused · failed
sourceenumrequired
One of: email · paste
subjectstringnullablerequired
domainstringnullablerequired
causestringnullablerequired
causeLabelstringnullablerequired
confidencestringnullablerequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
429Rate limited
curl https://api.trustyourinbox.com/v1/diagnosis?workspace=value&limit=50 \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "cases": [
    {
      "id": "example",
      "createdAt": "example",
      "status": "received",
      "source": "email",
      "subject": "example",
      "domain": "acme.com",
      "cause": "example",
      "causeLabel": "example",
      "confidence": "example"
    },
    {
      "id": "example",
      "createdAt": "example",
      "status": "received",
      "source": "email",
      "subject": "example",
      "domain": "acme.com",
      "cause": "example",
      "causeLabel": "example",
      "confidence": "example"
    }
  ]
}
post/v1/diagnosis

Diagnose pasted message headers (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. The machine-callable paste path - runs the same diagnosePastedHeadersCore the dashboard uses (demo refusal, plan capability, monthly quota, daily cap + Message-ID dedupe, the verified-domain authorization boundary, pure collectors, verdict, audited "via API key X"). The quick check only (header chain + Microsoft annotations); forwarding the message by email to the minted address stays the rich diagnosis. Honors Idempotency-Key. The 201 body is the same case-detail DTO as GET /v1/diagnosis/{id}.

Requires a write-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

headersstringrequired

The original message's full header block (max 64 KiB).

201The diagnosed case
idstringrequired
createdAtstringrequired
statusenumrequired
One of: received · analyzing · diagnosed · needs_headers · refused · failed
sourceenumrequired
One of: email · paste
artifactKindstringnullablerequired
domainstringnullablerequired
subjectstringnullablerequired
forwarderEmailstringnullablerequired
replySentAtstringnullablerequired
refusalReasonstringnullablerequired
verdictobjectnullablerequired
causeenumrequired
One of: authentication · reputation · forwarding · transport · recipient_issue · policy_block · unclear
confidencestringnullablerequired
causeLabelstringnullablerequired
narrativestringnullablerequired
providersAffectedarray of stringrequired
ruledOutarray of objectrequired
An object.
actionsarray of objectrequired
An object.
bounceStatusstringnullablerequired
bounceReplyLinestringnullablerequired
evidencearray of objectrequired
sourcestringrequired
statestringrequired
stateLabelstringrequired
findingstringrequired
fixobjectrequired
changeIdstringnullablerequired
changeStatusstringnullablerequired
watchUntilstringnullablerequired
recoveryConfirmedAtstringnullablerequired
400invalid_request (missing/oversized headers)
401Missing or invalid API key
403forbidden (read-only key, role lacks edit_data) or plan_required
409conflict (duplicate submission) or plan_limit (monthly quota)
422invalid_request (needs_headers / foreign_domain; a case row still lands, its id is in the body)
429Rate limited (incl. the per-workspace daily cap)
curl -X POST https://api.trustyourinbox.com/v1/diagnosis?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "headers": "example"
}'
Response 201
{
  "id": "example",
  "createdAt": "example",
  "status": "received",
  "source": "email",
  "artifactKind": "example",
  "domain": "acme.com",
  "subject": "example",
  "forwarderEmail": "example",
  "replySentAt": "example",
  "refusalReason": "example",
  "verdict": {
    "cause": "authentication",
    "confidence": "example",
    "causeLabel": "example",
    "narrative": "example",
    "providersAffected": [
      "example",
      "example"
    ],
    "ruledOut": [
      {},
      {}
    ],
    "actions": [
      {},
      {}
    ],
    "bounceStatus": "example",
    "bounceReplyLine": "example"
  },
  "evidence": [
    {
      "source": "example",
      "state": "example",
      "stateLabel": "example",
      "finding": "example"
    },
    {
      "source": "example",
      "state": "example",
      "stateLabel": "example",
      "finding": "example"
    }
  ],
  "fix": {
    "changeId": "example",
    "changeStatus": "example"
  },
  "watchUntil": "example",
  "recoveryConfirmedAt": "example"
}
get/v1/diagnosis/{id}

One Delivery Diagnosis case in full (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. The verdict (cause, confidence, plain-English narrative, ruled-out causes, suggested actions), the per-source evidence chain, the bound one-click fix, and the recovery-watch state. Workspace-scoped - a foreign case id returns 404 with no existence leak. Mirrors the MCP get_diagnosis_case tool's structured payload.

Requires a read-scoped key (Bearer).
idstringrequired

the case id (from GET /v1/diagnosis)

workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200The case detail
idstringrequired
createdAtstringrequired
statusenumrequired
One of: received · analyzing · diagnosed · needs_headers · refused · failed
sourceenumrequired
One of: email · paste
artifactKindstringnullablerequired
domainstringnullablerequired
subjectstringnullablerequired
forwarderEmailstringnullablerequired
replySentAtstringnullablerequired
refusalReasonstringnullablerequired
verdictobjectnullablerequired
causeenumrequired
One of: authentication · reputation · forwarding · transport · recipient_issue · policy_block · unclear
confidencestringnullablerequired
causeLabelstringnullablerequired
narrativestringnullablerequired
providersAffectedarray of stringrequired
ruledOutarray of objectrequired
An object.
actionsarray of objectrequired
An object.
bounceStatusstringnullablerequired
bounceReplyLinestringnullablerequired
evidencearray of objectrequired
sourcestringrequired
statestringrequired
stateLabelstringrequired
findingstringrequired
fixobjectrequired
changeIdstringnullablerequired
changeStatusstringnullablerequired
watchUntilstringnullablerequired
recoveryConfirmedAtstringnullablerequired
400invalid_request (malformed id)
401Missing or invalid API key
404No case with that id in the caller's workspace
429Rate limited
curl https://api.trustyourinbox.com/v1/diagnosis/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "id": "example",
  "createdAt": "example",
  "status": "received",
  "source": "email",
  "artifactKind": "example",
  "domain": "acme.com",
  "subject": "example",
  "forwarderEmail": "example",
  "replySentAt": "example",
  "refusalReason": "example",
  "verdict": {
    "cause": "authentication",
    "confidence": "example",
    "causeLabel": "example",
    "narrative": "example",
    "providersAffected": [
      "example",
      "example"
    ],
    "ruledOut": [
      {},
      {}
    ],
    "actions": [
      {},
      {}
    ],
    "bounceStatus": "example",
    "bounceReplyLine": "example"
  },
  "evidence": [
    {
      "source": "example",
      "state": "example",
      "stateLabel": "example",
      "finding": "example"
    },
    {
      "source": "example",
      "state": "example",
      "stateLabel": "example",
      "finding": "example"
    }
  ],
  "fix": {
    "changeId": "example",
    "changeStatus": "example"
  },
  "watchUntil": "example",
  "recoveryConfirmedAt": "example"
}

Mandate Monitor#

get/v1/domains/{domain}/mandate

Mandate Monitor status for a domain (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. Message-verified sender-mandate compliance for one domain: per-check aggregates proven by real probe-graded mail (worst-of-window; the denominators are the messages each check applied to), the streams the probe has seen, and the Microsoft 5.7.515 count. Mirrors the MCP get_mandate_status tool's structured payload. Intake stays email-only by design - there is no write endpoint.

Requires a read-scoped key (Bearer).
domainstringrequired
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Mandate Monitor status
domainstringrequired
hasCapabilitybooleanrequired
probeMintedbooleanrequired
gradedCountintegerrequired
steadybooleanrequired
checksarray of objectrequired
idstringrequired
labelstringrequired
sourcestringrequired
passedintegerrequired
applicableintegerrequired
worststringnullablerequired
streamsarray of objectrequired
idstringrequired
fromAddressstringrequired
dkimDomainstringrequired
dkimSelectorstringrequired
classificationstringrequired
classificationSourcestringrequired
messageCountintegerrequired
worstVerdictstringnullablerequired
lastSeenAtstringrequired
microsoft515Count30dintegerrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Domain not found in the workspace (or the feature is switched off)
429Rate limited
curl https://api.trustyourinbox.com/v1/domains/acme.com/mandate?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "domain": "acme.com",
  "hasCapability": true,
  "probeMinted": true,
  "gradedCount": 3,
  "steady": true,
  "checks": [
    {
      "id": "example",
      "label": "marketing",
      "source": "example",
      "passed": 0,
      "applicable": 0,
      "worst": "example"
    },
    {
      "id": "example",
      "label": "news",
      "source": "example",
      "passed": 0,
      "applicable": 0,
      "worst": "example"
    }
  ],
  "streams": [
    {
      "id": "example",
      "fromAddress": "example",
      "dkimDomain": "example",
      "dkimSelector": "example",
      "classification": "example",
      "classificationSource": "example",
      "messageCount": 3,
      "worstVerdict": "example",
      "lastSeenAt": "example"
    },
    {
      "id": "example",
      "fromAddress": "example",
      "dkimDomain": "example",
      "dkimSelector": "example",
      "classification": "example",
      "classificationSource": "example",
      "messageCount": 1,
      "worstVerdict": "example",
      "lastSeenAt": "example"
    }
  ],
  "microsoft515Count30d": 0
}
get/v1/mandate/messages

List probe-graded messages (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. Probe-graded messages for the workspace, newest first. ?domain= filters to one verified domain; ?limit= (default 25, max 100). Mirrors the MCP list_graded_messages tool's structured payload. Header excerpts are customer mail content and never appear in this payload.

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

domainstring
limitinteger
200Graded messages
messagesarray of objectrequired
idstringrequired
receivedAtstringrequired
domainstringnullablerequired
subjectstringnullablerequired
fromAddressstringrequired
verdictstringrequired
rulebookVersionintegerrequired
checksarray of objectrequired
idstringrequired
statusstringrequired
detailstringnullablerequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
429Rate limited
curl https://api.trustyourinbox.com/v1/mandate/messages?workspace=value&domain=value&limit=50 \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "messages": [
    {
      "id": "example",
      "receivedAt": "example",
      "domain": "acme.com",
      "subject": "example",
      "fromAddress": "example",
      "verdict": "Known sender",
      "rulebookVersion": 0,
      "checks": [
        {
          "id": "example",
          "status": "verified",
          "detail": "example"
        },
        {
          "id": "example",
          "status": "verified",
          "detail": "example"
        }
      ]
    },
    {
      "id": "example",
      "receivedAt": "example",
      "domain": "acme.com",
      "subject": "example",
      "fromAddress": "example",
      "verdict": "Known sender",
      "rulebookVersion": 0,
      "checks": [
        {
          "id": "example",
          "status": "verified",
          "detail": "example"
        },
        {
          "id": "example",
          "status": "verified",
          "detail": "example"
        }
      ]
    }
  ]
}

Senders#

get/v1/senders

List your custom senders (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. Every custom (source "user") sender in the workspace - including ones with no observed traffic yet - with ranges, optional icon URL, and trailing-30-day attributed volume. The same loader the dashboard's management card reads.

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200The workspace's custom senders
countintegerrequired
sendersarray of objectrequired
senderIdstring · uuidrequired
namestringrequired
categoryenumrequired
One of: email_provider · esp_marketing · esp_transactional · security · infrastructure · crm · other
rangesarray of stringrequired
iconUrlstringnullablerequired
volume30dnumberrequired
lastSeenstringnullablerequired
createdAtstringrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
403Plan does not include API access
429Rate limited
curl https://api.trustyourinbox.com/v1/senders?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "count": 3,
  "senders": [
    {
      "senderId": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
      "name": "acme.com",
      "category": "email_provider",
      "ranges": [
        "example",
        "example"
      ],
      "iconUrl": "example",
      "volume30d": 0,
      "lastSeen": "example",
      "createdAt": "example"
    },
    {
      "senderId": "2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
      "name": "shop.acme.com",
      "category": "email_provider",
      "ranges": [
        "example",
        "example"
      ],
      "iconUrl": "example",
      "volume30d": 0,
      "lastSeen": "example",
      "createdAt": "example"
    }
  ]
}
post/v1/senders

Identify a sending IP / CIDR as a named vendor (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Body { "ipOrCidr", "name", "category" } - labels a source so it counts as a known sender instead of an unknown source. Reuses identifySenderCore; audited "via API key X". Honors Idempotency-Key.

Requires a write-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

ipOrCidrstringrequired

An IP or CIDR, e.g. 198.2.132.1 or 198.2.128.0/18.

namestringrequired

The vendor / sender name, e.g. Mailchimp.

categoryenumrequired
One of: email_provider · esp_marketing · esp_transactional · security · infrastructure · crm · other
201Sender identified
senderIdstring · uuidrequired
namestringrequired
categoryenumrequired
One of: email_provider · esp_marketing · esp_transactional · security · infrastructure · crm · other
ipOrCidrstringrequired
400invalid_request (missing name / invalid category / invalid CIDR)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
409conflict (a sender with that name already exists)
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/senders?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6" \
  -d '{
  "ipOrCidr": "198.2.132.0/24",
  "name": "acme.com",
  "category": "email_provider"
}'
Response 201
{
  "senderId": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
  "name": "acme.com",
  "category": "email_provider",
  "ipOrCidr": "198.2.132.0/24"
}
patch/v1/senders/{id}

Update a custom sender (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Partial update of a custom sender you created - rename, recategorize, add an IP range (how you register a second IP of the same server), or remove one. Removing a range re-attributes its traffic (past reports included) back to the catalog vendor underneath, or back to unknown. Reuses modifySenderCore (the SAME composition the dashboard + MCP update_sender use); audited "via API key X". Honors Idempotency-Key.

Requires a write-scoped key (Bearer).
idstring · uuidrequired
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

namestring
categoryenum
One of: email_provider · esp_marketing · esp_transactional · security · infrastructure · crm · other
addRangestring

An IP or CIDR to add (widest /24 IPv4, /48 IPv6; max 16 ranges per sender).

removeRangestring

An existing range to remove (refused for the last range - delete the sender instead).

200Sender updated
senderIdstring · uuidrequired
namestringrequired
corpusOverlapsarray of objectrequired

Input ranges that sit inside a global catalog vendor's published ranges (warn-and-allow).

rangestringrequired
corpusSenderstringrequired
400invalid_request (nothing to do / invalid category / invalid or too-wide CIDR / range not found)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404Not this workspace's custom sender (catalog vendors are never editable)
409conflict (duplicate name or range, overlap with your own sender, range cap, last range)
429Rate limited
curl -X PATCH https://api.trustyourinbox.com/v1/senders/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6" \
  -d '{
  "name": "acme.com",
  "category": "email_provider",
  "addRange": "example",
  "removeRange": "example"
}'
Response 200
{
  "senderId": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
  "name": "acme.com",
  "corpusOverlaps": [
    {
      "range": "example",
      "corpusSender": "example"
    },
    {
      "range": "example",
      "corpusSender": "example"
    }
  ]
}
delete/v1/senders/{id}

Delete a custom sender (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Deletes a custom sender you created; its traffic - past reports included - re-attributes to the catalog vendor underneath, or back to unknown, and the workspace known-IP set reconverges. Reuses deleteSenderCore; audited "via API key X". Honors Idempotency-Key.

Requires a write-scoped key (Bearer).
idstring · uuidrequired
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

200Sender deleted
senderIdstring · uuidrequired
namestringrequired
deletedbooleanrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404Not this workspace's custom sender
429Rate limited
curl -X DELETE https://api.trustyourinbox.com/v1/senders/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "senderId": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
  "name": "acme.com",
  "deleted": true
}

Webhooks#

get/v1/webhooks

List your outbound webhook endpoints (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. Every outbound webhook endpoint in the workspace, with its URL, event filter, status, and failure streak. Never returns the signing secret, only its masked prefix. Requires the outboundWebhooks plan capability (Pro and up).

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200The workspace's webhook endpoints
countintegerrequired
webhooksarray of objectrequired
idstring · uuidrequired
urlstringrequired
descriptionstringnullablerequired
secretPrefixstringrequired
eventTypesarray of stringnullablerequired
statusenumrequired
One of: active · disabled
consecutiveFailuresintegerrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
403Plan does not include outbound webhooks
429Rate limited
curl https://api.trustyourinbox.com/v1/webhooks?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "count": 3,
  "webhooks": [
    {
      "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
      "url": "example",
      "description": "example",
      "secretPrefix": "example",
      "eventTypes": [
        "example",
        "example"
      ],
      "status": "active",
      "consecutiveFailures": 0
    },
    {
      "id": "2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
      "url": "example",
      "description": "example",
      "secretPrefix": "example",
      "eventTypes": [
        "example",
        "example"
      ],
      "status": "active",
      "consecutiveFailures": 0
    }
  ]
}
post/v1/webhooks

Register an outbound webhook endpoint (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Registers an https endpoint we POST a signed payload to on each critical event. Body { "url", "description"?, "eventTypes"? } - eventTypes omitted means all types. Returns the signing secret ONCE. Reuses createWebhookEndpointCore; audited "via API key X". Honors Idempotency-Key. Requires the outboundWebhooks capability (Pro and up).

Requires a write-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

urlstringrequired

The https endpoint URL to POST events to.

descriptionstring

Optional label, e.g. Prod SIEM.

eventTypesarray of string

Which events to receive; omit for all.

201Endpoint created (signing secret returned once)
idstring · uuidrequired
secretstringrequired

The signing secret - returned ONCE, not retrievable later.

secretPrefixstringrequired
400invalid_request (invalid URL / not https / private address / unknown event type)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data), or plan_required
409conflict (endpoint limit reached)
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/webhooks?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6" \
  -d '{
  "url": "example",
  "description": "example",
  "eventTypes": [
    "anomaly.crit",
    "anomaly.crit"
  ]
}'
Response 201
{
  "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
  "secret": "example",
  "secretPrefix": "example"
}
delete/v1/webhooks/{id}

Delete an outbound webhook endpoint (public REST API, write) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; WRITE scope. Removes an endpoint; we stop delivering to it immediately and its delivery log is cascaded. Reuses deleteWebhookEndpointCore; audited "via API key X". Honors Idempotency-Key.

Requires a write-scoped key (Bearer).
idstring · uuidrequired
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

200Endpoint deleted
idstring · uuidrequired
deletedbooleanrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
403forbidden (read-only key or role lacks edit_data)
404Not this workspace's webhook endpoint
429Rate limited
curl -X DELETE https://api.trustyourinbox.com/v1/webhooks/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
  "deleted": true
}
get/v1/webhooks/{id}/deliveries

Recent delivery attempts for an endpoint (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. The most recent delivery attempts for one endpoint (newest first) - the event type, status, HTTP response code, failure reason, and attempt number - for debugging your receiver.

Requires a read-scoped key (Bearer).
idstring · uuidrequired
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Recent delivery attempts
endpointIdstring · uuidrequired
countintegerrequired
deliveriesarray of objectrequired
idstring · uuidrequired
eventTypestringrequired
statusenumrequired
One of: pending · delivered · failed
responseCodeintegernullablerequired
errorstringnullablerequired
attemptintegerrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
404Not this workspace's webhook endpoint
429Rate limited
curl https://api.trustyourinbox.com/v1/webhooks/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6/deliveries?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "endpointId": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
  "count": 3,
  "deliveries": [
    {
      "id": "1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6",
      "eventType": "example",
      "status": "pending",
      "responseCode": 0,
      "error": "invalid_request",
      "attempt": 0
    },
    {
      "id": "2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
      "eventType": "example",
      "status": "pending",
      "responseCode": 0,
      "error": "invalid_request",
      "attempt": 0
    }
  ]
}

Workspace#

get/v1/workspace/health

Workspace-wide health summary (public REST API) #

Public REST API (api.trustyourinbox.com/v1). Bearer API key; read scope. Spoofer-adjusted alignment, trend, and totals - the same loader the dashboard hero uses. Rate-limited (120/60s per key).

Requires a read-scoped key (Bearer).
workspacestring · uuid

ORG-scoped keys only (the MSP partner API): the client workspace this call acts on. Ids come from GET /v1/msp/clients, or the Client workspace IDs table on /msp/api. REQUIRED when the bearer is an org key - omitting it answers 400 workspace_required. A workspace outside the key's own organization answers a flat 404 (no existence leak). A workspace-scoped key IGNORES this parameter and stays pinned to its own workspace.

200Workspace health summary
alignmentPctintegernullablerequired

Spoofer-adjusted workspace alignment %.

trendDeltaPpintegernullablerequired

Change in points vs the prior window.

totalMessagesintegerrequired
totalReportsintegerrequired
totalDomainsintegerrequired
400workspace_required (an org-scoped key called without ?workspace=)
401Missing or invalid API key
429Rate limited
curl https://api.trustyourinbox.com/v1/workspace/health?workspace=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "alignmentPct": 98,
  "trendDeltaPp": 2,
  "totalMessages": 1240,
  "totalReports": 14,
  "totalDomains": 6
}

MSP#

get/v1/msp/clients

The MSP book of business (partner API) #

Partner API (api.trustyourinbox.com/v1/msp). ORG-scoped bearer key (minted in the MSP console) with the msp:read scope; a workspace key answers 403 org_key_required. Every client workspace with its posture rollup - the console grid's exact loader, problems-first ordering. Rate-limited (120/60s per key).

Requires a read-scoped key (Bearer).
200The book of business
clientsarray of objectrequired
workspaceIdstringrequired
namestringrequired
createdAtstring · date-timerequired
archivedAtstring · date-timenullablerequired
contactEmailstringnullablerequired
domainsTotalintegerrequired
domainsVerifiedintegerrequired
sendingDomainsintegerrequired
enforcedSendingDomainsintegerrequired
openCritsintegerrequired
blockedSpoof30dintegerrequired
dataThroughstringnullablerequired

RUA data-through timestamp; null = no reports yet.

archivedarray of objectrequired
workspaceIdstringrequired
namestringrequired
createdAtstring · date-timerequired
archivedAtstring · date-timenullablerequired
contactEmailstringnullablerequired
domainsTotalintegerrequired
domainsVerifiedintegerrequired
sendingDomainsintegerrequired
enforcedSendingDomainsintegerrequired
openCritsintegerrequired
blockedSpoof30dintegerrequired
dataThroughstringnullablerequired

RUA data-through timestamp; null = no reports yet.

summaryobjectrequired
clientCountintegerrequired
domainCountintegerrequired
sendingDomainsintegerrequired
enforcedSendingDomainsintegerrequired
openCritsintegerrequired
blockedSpoof30dintegerrequired
workspaceLimitintegernullablerequired
401Missing or invalid API key
403org_key_required (workspace key) or plan_required
429Rate limited
curl https://api.trustyourinbox.com/v1/msp/clients \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "clients": [
    {
      "workspaceId": "example",
      "name": "acme.com",
      "createdAt": "2026-06-01T00:00:00Z",
      "archivedAt": "2026-06-01T00:00:00Z",
      "contactEmail": "example",
      "domainsTotal": 0,
      "domainsVerified": 0,
      "sendingDomains": 0,
      "enforcedSendingDomains": 0,
      "openCrits": 0,
      "blockedSpoof30d": 0,
      "dataThrough": "example"
    },
    {
      "workspaceId": "example",
      "name": "shop.acme.com",
      "createdAt": "2026-06-08T00:00:00Z",
      "archivedAt": "2026-06-08T00:00:00Z",
      "contactEmail": "example",
      "domainsTotal": 0,
      "domainsVerified": 0,
      "sendingDomains": 0,
      "enforcedSendingDomains": 0,
      "openCrits": 0,
      "blockedSpoof30d": 0,
      "dataThrough": "example"
    }
  ],
  "archived": [
    {
      "workspaceId": "example",
      "name": "acme.com",
      "createdAt": "2026-06-01T00:00:00Z",
      "archivedAt": "2026-06-01T00:00:00Z",
      "contactEmail": "example",
      "domainsTotal": 0,
      "domainsVerified": 0,
      "sendingDomains": 0,
      "enforcedSendingDomains": 0,
      "openCrits": 0,
      "blockedSpoof30d": 0,
      "dataThrough": "example"
    },
    {
      "workspaceId": "example",
      "name": "shop.acme.com",
      "createdAt": "2026-06-08T00:00:00Z",
      "archivedAt": "2026-06-08T00:00:00Z",
      "contactEmail": "example",
      "domainsTotal": 0,
      "domainsVerified": 0,
      "sendingDomains": 0,
      "enforcedSendingDomains": 0,
      "openCrits": 0,
      "blockedSpoof30d": 0,
      "dataThrough": "example"
    }
  ],
  "summary": {
    "clientCount": 3,
    "domainCount": 3,
    "sendingDomains": 0,
    "enforcedSendingDomains": 0,
    "openCrits": 0,
    "blockedSpoof30d": 0,
    "workspaceLimit": 0
  }
}
post/v1/msp/clients

Create a client workspace (partner API, write) #

Partner API. ORG-scoped key with msp:write AND the key creator's live role must allow org management (owner). Reuses the console's create-workspace core (capability gate, workspace cap, race-safe slug). Honors an optional Idempotency-Key at organization grain - the PSA-retry case. Audited "via API key X".

Requires a write-scoped key (Bearer).
Idempotency-Keystring

Optional client key; a retry with the same value replays the original response.

namestringrequired

The client's display name, e.g. Acme Roofing.

201Client workspace created
workspaceIdstringrequired
namestringrequired
slugstringrequired
400invalid_request (missing or over-long name)
401Missing or invalid API key
403forbidden (no msp:write, or the creator's role cannot manage the org)
409plan_limit (workspace ceiling)
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/msp/clients \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6" \
  -d '{
  "name": "acme.com"
}'
Response 201
{
  "workspaceId": "example",
  "name": "acme.com",
  "slug": "example"
}
get/v1/msp/clients/{id}

One client workspace's posture (partner API) #

Partner API. ORG-scoped key, msp:read. Domains with enforcement, workspace-scoped members, pending invites - the console detail's loader. A foreign or unknown id is a flat 404 (no existence leak).

Requires a read-scoped key (Bearer).
idstringrequired

the client workspace id (from GET /v1/msp/clients)

200The client detail
workspaceIdstringrequired
namestringrequired
createdAtstring · date-timerequired
archivedAtstring · date-timenullablerequired
internalbooleanrequired
contactEmailstringnullablerequired
domainsarray of objectrequired
namestringrequired
statusstringrequired
purposeenumrequired
One of: sending · monitor_only
policystringnullablerequired
pctintegernullablerequired
testModebooleanrequired
enforcedbooleanrequired
membersarray of objectrequired
emailstringrequired
rolestringrequired
createdAtstring · date-timerequired
orgLevelMemberCountintegerrequired
pendingInvitesarray of objectrequired
emailstringrequired
rolestringrequired
expiresAtstring · date-timerequired
401Missing or invalid API key
403org_key_required or plan_required
404No client workspace with that id in the key's organization
429Rate limited
curl https://api.trustyourinbox.com/v1/msp/clients/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6 \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "workspaceId": "example",
  "name": "acme.com",
  "createdAt": "2026-06-01T00:00:00Z",
  "archivedAt": "2026-06-01T00:00:00Z",
  "internal": true,
  "contactEmail": "example",
  "domains": [
    {
      "name": "acme.com",
      "status": "verified",
      "purpose": "sending",
      "policy": "reject",
      "pct": 98,
      "testMode": true,
      "enforced": true
    },
    {
      "name": "shop.acme.com",
      "status": "verified",
      "purpose": "sending",
      "policy": "reject",
      "pct": 94,
      "testMode": true,
      "enforced": true
    }
  ],
  "members": [
    {
      "email": "example",
      "role": "example",
      "createdAt": "2026-06-01T00:00:00Z"
    },
    {
      "email": "example",
      "role": "example",
      "createdAt": "2026-06-08T00:00:00Z"
    }
  ],
  "orgLevelMemberCount": 3,
  "pendingInvites": [
    {
      "email": "example",
      "role": "example",
      "expiresAt": "2026-06-01T00:00:00Z"
    },
    {
      "email": "example",
      "role": "example",
      "expiresAt": "2026-06-08T00:00:00Z"
    }
  ]
}
post/v1/msp/clients/{id}/archive

Archive a client (partner API, write) #

Partner API. ORG-scoped key, msp:write + live owner role. Workspace soft-state - keeps data and access, stops metering. Idempotent by nature (already-archived answers ok).

Requires a write-scoped key (Bearer).
idstringrequired
200Archived
workspaceIdstringrequired
archivedbooleanrequired
401Missing or invalid API key
403forbidden (scope or role)
404Unknown or foreign client id
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/msp/clients/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6/archive \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "workspaceId": "example",
  "archived": true
}
post/v1/msp/clients/{id}/restore

Restore an archived client (partner API, write) #

Partner API. The mirror of /archive - same core, same gates.

Requires a write-scoped key (Bearer).
idstringrequired
200Restored
workspaceIdstringrequired
archivedbooleanrequired
401Missing or invalid API key
403forbidden (scope or role)
404Unknown or foreign client id
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/msp/clients/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6/restore \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "workspaceId": "example",
  "archived": true
}
post/v1/msp/clients/{id}/domains

Bulk-add domains to a client (partner API, write) #

Partner API. ORG-scoped key, msp:write + live edit role. Runs the same per-domain core the console bulk paste uses (plan cap, AUP gate, provider detection, insert, audit) and answers a per-row outcome list - partial success is normal and explicit, never a transaction. Max 200 domains per call. Honors Idempotency-Key at organization grain.

Requires a write-scoped key (Bearer).
idstringrequired
Idempotency-Keystring
domainsarray of stringrequired

Domain names to add.

purposeenum

Defaults to sending.

One of: sending · monitor_only
200Per-row outcomes
addedintegerrequired
itemsarray of objectrequired
inputstringrequired
outcomeenumrequired
One of: added · restored · duplicate · invalid · aup_blocked · plan_limit · failed
domainstringnullablerequired
400invalid_request (empty, over 200 rows, or a non-string entry)
401Missing or invalid API key
403forbidden (scope or role)
404Unknown or foreign client id
409conflict (client is archived)
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/msp/clients/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6/domains \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6" \
  -d '{
  "domains": [
    "example",
    "example"
  ],
  "purpose": "sending"
}'
Response 200
{
  "added": 0,
  "items": [
    {
      "input": "example",
      "outcome": "added",
      "domain": "acme.com"
    },
    {
      "input": "example",
      "outcome": "added",
      "domain": "acme.com"
    }
  ]
}
post/v1/msp/clients/{id}/invites

Invite a client user (partner API, write) #

Partner API. ORG-scoped key, msp:write + live member-management role. Invites a workspace-SCOPED viewer or member into the client workspace - the console invite flow (duplicate refusals, seat gate, invite email, audit).

Requires a write-scoped key (Bearer).
idstringrequired
emailstringrequired
roleenumrequired
One of: viewer · member
201Invite sent
workspaceIdstringrequired
emailstringrequired
rolestringrequired
400invalid_request (email or role)
401Missing or invalid API key
403forbidden (scope or role)
404Unknown or foreign client id
409conflict (already a member, already invited, or archived) or plan_limit (seats)
429Rate limited
curl -X POST https://api.trustyourinbox.com/v1/msp/clients/1f2e3d4c-5b6a-7c8d-9e0f-a1b2c3d4e5f6/invites \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "example",
  "role": "viewer"
}'
Response 201
{
  "workspaceId": "example",
  "email": "example",
  "role": "example"
}
get/v1/msp/usage

A month of the usage ledger (partner API) #

Partner API. ORG-scoped key, msp:read. One calendar month of the daily usage ledger (?month=YYYY-MM, default the current UTC month): per-day billable and free counts, the month's billed peak, and the latest per-client breakdown - the PSA invoice-import shape. The ledger is what the Stripe invoice reconciles against, so this endpoint is the reconciliation surface.

Requires a read-scoped key (Bearer).
monthstring

Calendar month, YYYY-MM (UTC). Defaults to the current month.

200The month's ledger
monthstringrequired

YYYY-MM (UTC calendar month).

daysarray of objectrequired
usageDatestringrequired
billableintegerrequired
freeMonitorintegerrequired
nfrintegerrequired
monthPeakBillableintegerrequired
perClientarray of objectrequired
workspaceIdstringrequired
namestringrequired
billableintegerrequired
freeMonitorintegerrequired
nfrintegerrequired
sendinginteger

Billable SENDING domains alone, excluding monitor-only domains that overflowed the free allowance and are being billed. Optional: ledger rows written before 2026-08-17 do not carry it. Present, it explains the `billable` figure — `billable - sending` is the overflow — and it is the count the free-monitor allowance anchors to.

400invalid_request (malformed month)
401Missing or invalid API key
403org_key_required or plan_required
429Rate limited
curl https://api.trustyourinbox.com/v1/msp/usage?month=value \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "month": "example",
  "days": [
    {
      "usageDate": "example",
      "billable": 0,
      "freeMonitor": 0,
      "nfr": 0
    },
    {
      "usageDate": "example",
      "billable": 0,
      "freeMonitor": 0,
      "nfr": 0
    }
  ],
  "monthPeakBillable": 0,
  "perClient": [
    {
      "workspaceId": "example",
      "name": "acme.com",
      "billable": 0,
      "freeMonitor": 0,
      "nfr": 0,
      "sending": 0
    },
    {
      "workspaceId": "example",
      "name": "shop.acme.com",
      "billable": 0,
      "freeMonitor": 0,
      "nfr": 0,
      "sending": 0
    }
  ]
}
get/v1/msp/brand

The white-label brand profile (partner API) #

Partner API. ORG-scoped key, msp:read. Identity, colors, email-identity status, portal hostname status, chrome toggle. Statuses and names only - never storage keys or provider ids. A brandless org answers the honest null profile (configured=false), not a 404.

Requires a read-scoped key (Bearer).
200The brand profile
configuredbooleanrequired
productNamestringnullablerequired
colorsobjectnullablerequired
primarystring
accentstring
emailFromNamestringnullablerequired
emailFromAddressstringnullablerequired
emailDomainStatusstringrequired
portalHostnamestringnullablerequired
portalHostnameStatusstringrequired
skinOwnDashboardbooleanrequired
supportUrlstringnullablerequired
supportEmailstringnullablerequired
privacyUrlstringnullablerequired
termsUrlstringnullablerequired
401Missing or invalid API key
403org_key_required or plan_required
429Rate limited
curl https://api.trustyourinbox.com/v1/msp/brand \
  -H "Authorization: Bearer tyi_api_xxxxxxxxxxxxxxxxxxxxxxxx"
Response 200
{
  "configured": true,
  "productName": "example",
  "colors": {
    "primary": "example",
    "accent": "example"
  },
  "emailFromName": "example",
  "emailFromAddress": "example",
  "emailDomainStatus": "example",
  "portalHostname": "example",
  "portalHostnameStatus": "example",
  "skinOwnDashboard": true,
  "supportUrl": "example",
  "supportEmail": "example",
  "privacyUrl": "example",
  "termsUrl": "example"
}