API reference › Profiles › Create profile
Create a profile
/v1/profilesA profile is what you expect of a domain's records: a named list of requirements, each with a key you choose. Results are reported against those keys, so pick ones you can switch on.
| Field | Type | Description |
|---|---|---|
| key* | string | The profile's identifier. Posting this key again does not change this version — it writes a new one. See Editing below. |
| requirements* | array | At least one, at most 20. Each item names a check kind and the fields that kind needs — see Check kinds. |
| requirements[].key* | string | A stable label you choose. Results are reported against it. |
| requirements[].check* | string | One of caa, delegation, dkim, dmarc, mx, spf. See /concepts/profiles for what each asserts. |
| requirements[].selector | string | Required for check: dkim. The label before _domainkey. |
| requirements[].expectedPublicKey | string | Optional, for check: dkim. The key you issued — turns "a valid key is published" into "your key is published". |
| requirements[].caaIssuer | string | Required for check: caa. The CA that must be authorised. |
| requirements[].include | string | Optional, for check: spf. The include: token you publish. |
| requirements[].expectsMail | boolean | Optional and tri-state, for check: mx. Omit if unknown; false asserts the domain receives no mail. |
curl -s -X POST https://api.propgate.dev/v1/profiles \
-H "authorization: Bearer pg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H 'content-type: application/json' -d '{
"key": "sending",
"requirements": [
{ "key": "ns", "check": "delegation" },
{ "key": "spf", "check": "spf", "include": "_spf.google.com" },
{ "key": "dkim", "check": "dkim", "selector": "google" },
{ "key": "dmarc", "check": "dmarc" },
{ "key": "mail", "check": "mx", "expectsMail": true }
]
}'No CLI command yet — a profile is created over the API only.
{
"data": {
"id": "019fcf6b-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
"key": "sending",
"object": "profile",
"requirements": [
{
"key": "ns",
"check": "delegation"
},
{
"key": "spf",
"check": "spf",
"include": "_spf.google.com"
},
{
"key": "dkim",
"check": "dkim",
"selector": "google"
},
{
"key": "dmarc",
"check": "dmarc"
},
{
"key": "mail",
"check": "mx",
"expectsMail": true
}
],
"version": 1
},
"error": null,
"meta": null
}Editing writes a new version
Posting the same key again never changes this version — it writes the next
one, and every domain already registered against sending stays pinned to
whichever version it was registered against. Full reasoning, and what "pinned"
means for a domain mid-flight, is at
Profiles and versions.
Rejected at write time
A definition is refused before it is ever stored if a requirement inside it could never be answered:
- no requirements, or more than 20
- a duplicate requirement key
- a
dkimrequirement with noselector, or twodkimrequirements sharing oneselector - a
caarequirement with nocaaIssuer - two requirements naming the same non-
dkimcheck —dkimis the one check that answers a question per selector rather than per domain, so it is the one allowed to repeat
curl -s -X POST https://api.propgate.dev/v1/profiles \
-H "authorization: Bearer pg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H 'content-type: application/json' -d '{
"key": "sending",
"requirements": [
{ "key": "dkim", "check": "dkim" }
]
}'{
"data": null,
"error": {
"message": "requirement \"dkim\" checks dkim and must name a selector"
},
"meta": null
}Accepting a definition like this and failing later, once a customer already
relies on it, would be a promise this API took and could not keep. A 422 at
write time is the same finding delivered while it is still cheap to fix.