propgate docs

API reference › ProfilesCreate profile

Create a profile

POST/v1/profiles

A 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.

FieldTypeDescription
key*stringThe profile's identifier. Posting this key again does not change this version — it writes a new one. See Editing below.
requirements*arrayAt least one, at most 20. Each item names a check kind and the fields that kind needs — see Check kinds.
requirements[].key*stringA stable label you choose. Results are reported against it.
requirements[].check*stringOne of caa, delegation, dkim, dmarc, mx, spf. See /concepts/profiles for what each asserts.
requirements[].selectorstringRequired for check: dkim. The label before _domainkey.
requirements[].expectedPublicKeystringOptional, for check: dkim. The key you issued — turns "a valid key is published" into "your key is published".
requirements[].caaIssuerstringRequired for check: caa. The CA that must be authorised.
requirements[].includestringOptional, for check: spf. The include: token you publish.
requirements[].expectsMailbooleanOptional 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 dkim requirement with no selector, or two dkim requirements sharing one selector
  • a caa requirement with no caaIssuer
  • two requirements naming the same non-dkim check — dkim is 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.