Appearance
Domains
Manage domains in your organization.
Report ingest addresses
Every domain has its own report mailbox. Publish it in your DMARC rua/ruf tags and your TLS-RPT rua tag so reports reach MailShield.
The address is returned as a reporting object on every domain response (create, list, get and update), so a scripted onboarding can publish DNS in the same pass that creates the domain:
json
"reporting": {
"ruaAddress": "mailto:942d71ef@reports.mailshield.app",
"rufAddress": "mailto:942d71ef@reports.mailshield.app",
"tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
}All three currently resolve to the same mailbox. They are named separately so your integration binds to a per-report-type contract rather than to that fact.
WARNING
Use the address exactly as returned. A rua pointing at the wrong mailbox fails silently: reports are simply never delivered, with no error anywhere.
Customer
Every domain response shows the customer the domain is assigned to as customerId and customerName, both null when it has none. Assign or remove the customer with Update Domain, and list one customer's domains with the customerId filter.
List Domains
Returns a paginated list of all domains, newest first.
GET /api/v1/domainsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
limit | integer | 20 | Items per page, 1 to 100. Larger values return 100 |
customerId | string | Only the domains assigned to this customer, or none for the domains without a customer |
page and limit must be whole numbers; anything else returns 400. Keep requesting the next page while meta.pagination.hasMore is true.
A customerId that isn't one of your customers returns 404, and a value that's neither a customer ID nor none returns 400.
Response
json
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"domain": "example.com",
"verified": true,
"usageType": "sends-and-receives",
"testEmailLocalPart": "admin",
"customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"customerName": "Acme Corp",
"reporting": {
"ruaAddress": "mailto:942d71ef@reports.mailshield.app",
"rufAddress": "mailto:942d71ef@reports.mailshield.app",
"tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
},
"lastCheckedAt": "2024-01-15T10:30:00Z",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
],
"meta": {
"pagination": {
"page": 1,
"limit": 20,
"hasMore": false
}
}
}Example
bash
curl -H "Authorization: Bearer ms_your_token" \
"https://app.mailshield.app/api/v1/domains?limit=10"The domains of one customer:
bash
curl -H "Authorization: Bearer ms_your_token" \
"https://app.mailshield.app/api/v1/domains?customerId=7c9e6679-7425-40de-944b-e07fc1f90ae7"Create Domain
Add a new domain to your organization.
POST /api/v1/domainsRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | Domain name (e.g., "example.com"). Internationalized names are stored in their ASCII (punycode) form |
usageType | string | No | How the domain is used (default: "sends-and-receives") |
testEmailLocalPart | string | Conditional | The part before the @ of an address at the domain that accepts mail, such as postmaster. Required for domains that receive email |
customerId | string | No | The ID of a customer in your organization to assign the domain to. Another ID returns 400 |
Usage Types:
sends-and-receives- Domain sends and receives emailreceives-only- Domain only receives emailsends-only- Domain only sends emailparked- Domain is parked (no email)
Response (201 Created)
json
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"domain": "example.com",
"verified": false,
"usageType": "sends-and-receives",
"testEmailLocalPart": "admin",
"customerId": null,
"customerName": null,
"lastCheckedAt": null,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z",
"reporting": {
"ruaAddress": "mailto:942d71ef@reports.mailshield.app",
"rufAddress": "mailto:942d71ef@reports.mailshield.app",
"tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
},
"verificationToken": "abc123xyz",
"verificationRecord": {
"hostname": "_mailshield.example.com",
"type": "TXT",
"value": "mailshield-verify=abc123xyz"
}
}
}Publish verificationRecord in your DNS, then call Verify Domain. A new domain has no customer; assign one with Update Domain.
Example
bash
curl -X POST \
-H "Authorization: Bearer ms_your_token" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com", "testEmailLocalPart": "admin"}' \
https://app.mailshield.app/api/v1/domainsErrors
400- Invalid domain name, missing required fields, or a body that isn't valid JSON403- Domain limit reached (upgrade required), a payment is overdue, or the token is read-only409- The domain is already in your organization. Other organizations can monitor the same domain; that never causes an error.
Get Domain
Returns domain details with the latest DNS check results.
GET /api/v1/domains/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Domain ID. An ID that isn't a UUID returns 404 |
Response
json
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"domain": "example.com",
"verified": true,
"usageType": "sends-and-receives",
"testEmailLocalPart": "admin",
"customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"customerName": "Acme Corp",
"reporting": {
"ruaAddress": "mailto:942d71ef@reports.mailshield.app",
"rufAddress": "mailto:942d71ef@reports.mailshield.app",
"tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
},
"lastCheckedAt": "2024-01-15T10:30:00Z",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z",
"checks": {
"mx": { /* MX check results */ },
"spf": { /* SPF check results */ },
"dkim": [ /* DKIM check results */ ],
"dmarc": { /* DMARC check results */ },
"mtaSts": { /* MTA-STS check results */ },
"tlsRpt": { /* TLS-RPT check results */ },
"bimi": { /* BIMI check results */ },
"dnssec": { /* DNSSEC check results */ }
}
}
}Each check is the latest stored result, or null if that check hasn't run yet. dkim has the latest result for each known selector. See DNS Checks for the fields of each check.
Example
bash
curl -H "Authorization: Bearer ms_your_token" \
https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000Update Domain
Update domain settings, and assign the domain to a customer. Only the fields you send change.
PATCH /api/v1/domains/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Domain ID |
Request Body
| Field | Type | Description |
|---|---|---|
usageType | string | How the domain is used |
testEmailLocalPart | string or null | The part before the @ of an address at the domain that accepts mail. Can't be empty while the domain receives email |
customerId | uuid or null | Assigns the domain to this customer in your organization. null removes it from its customer |
Response
json
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"domain": "example.com",
"verified": true,
"usageType": "sends-only",
"testEmailLocalPart": null,
"customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"customerName": "Acme Corp",
"reporting": {
"ruaAddress": "mailto:942d71ef@reports.mailshield.app",
"rufAddress": "mailto:942d71ef@reports.mailshield.app",
"tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
},
"lastCheckedAt": "2024-01-15T10:30:00Z",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T12:00:00Z"
}
}Example
bash
curl -X PATCH \
-H "Authorization: Bearer ms_your_token" \
-H "Content-Type: application/json" \
-d '{"usageType": "sends-only"}' \
https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000Assign the domain to a customer:
bash
curl -X PATCH \
-H "Authorization: Bearer ms_your_token" \
-H "Content-Type: application/json" \
-d '{"customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"}' \
https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000Errors
400- Invalid fields, a change ofusageTypeortestEmailLocalPartthat leaves a domain that receives email withouttestEmailLocalPart, or acustomerIdthat isn't one of your customers404- Domain not found409- The domain is on passive monitoring, which is only for parked domains. Turn off passive monitoring in the domain's settings before changing its usage type
Delete Domain
Remove a domain and all associated data.
DELETE /api/v1/domains/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Domain ID |
Response
json
{
"data": {
"deleted": true
}
}Example
bash
curl -X DELETE \
-H "Authorization: Bearer ms_your_token" \
https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000WARNING
This action cannot be undone. All DNS checks, reports, and alerts for this domain will be permanently deleted.
Verify Domain
Check or perform domain ownership verification.
Get Verification Status
GET /api/v1/domains/{id}/verifyReturns the verification status and the required DNS record.
json
{
"data": {
"verified": false,
"verificationRecord": {
"hostname": "_mailshield.example.com",
"type": "TXT",
"value": "mailshield-verify=abc123xyz"
}
}
}Verify Domain
POST /api/v1/domains/{id}/verifyAttempts to verify the domain by checking for the DNS TXT record.
json
{
"data": {
"verified": true,
"message": "Domain verified successfully"
}
}If verification fails, the response is still a 200, with verified: false and a message that says why:
json
{
"data": {
"verified": false,
"message": "No TXT record found at _mailshield.example.com. Publish the record in \"expected\", then try again. New records can take a few minutes to appear.",
"expected": {
"hostname": "_mailshield.example.com",
"type": "TXT",
"value": "mailshield-verify=abc123xyz"
}
}
}When a record exists but doesn't match, found has its value. When the DNS lookup itself failed, the response has lookupFailed: true: the record couldn't be checked, so try again in a minute rather than changing DNS.