Policies

Policies organize two owner-scoped email controls: DNE records for exact email addresses and domain rules for exact domains. Create a policy group first, then include its group_id or group_name on every child-route request.

Authentication

Every route requires a bearer token for a user, admin, or root principal. The API injects the caller's owner ID; do not send owner.

Policy groups

Route Required fields Optional fields and behavior
POST /v1/members/policy/get id or name group_id is an alias for id; group_name is an alias for name.
POST /v1/members/policy/list None Exact filters: id, name; supports shared pagination.
POST /v1/members/policy/save name id updates an owned group; description and metadata are optional.
POST /v1/members/policy/delete id or name Deletes the owned group record.

Save a policy group

Field Required Type Description
id No UUID Existing owned group to update.
name Yes String Stable owner-scoped group name.
description No String or null Optional description.
metadata No Object or null Application-defined data.

Save writes the complete editable record, so an omitted description or metadata clears that field on update.

curl -sS https://api.post.m7.org/v1/members/policy/save \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "transactional-email",
    "description": "Rules for transactional recipients"
  }'
{
  "status": 1,
  "comment": "OK",
  "data": {
    "saved": true,
    "item": {
      "id": "POLICY_GROUP_UUID",
      "name": "transactional-email",
      "description": "Rules for transactional recipients"
    }
  }
}

Child policy scope

Every DNE and domain route requires one policy-group reference:

Field Required Type Behavior
group_id Conditional UUID Uses an owned policy-group ID.
group_name Conditional String Resolves an owned policy-group name to its ID.

Send either field. If both are supplied, they must resolve to the same group or the request fails with a conflict. The API applies the resolved group and the caller's ownership to every child lookup, including lookups by record ID.

DNE records

A DNE record suppresses one exact email address in a policy group.

Route Required fields Optional fields and behavior
POST /v1/members/policy/dne/get Group scope; id or email Returns data.item, which is null when no scoped record matches.
POST /v1/members/policy/dne/check Group scope; id or email Returns data.match and data.item.
POST /v1/members/policy/dne/list Group scope Exact filters: id, email, domain, type, source, reason_code; supports shared pagination.
POST /v1/members/policy/dne/save Group scope, email Creates or updates the record scoped to that group and email.
POST /v1/members/policy/dne/delete Group scope; id or email Deletes the scoped record.

DNE save fields

Field Required Type Description
email Yes String Email address. The API lowercases it and derives domain.
type No String soft (default) or hard.
source No String manual (default), bounce, deferred, complaint, import, or system.
reason_code No String or null Machine-readable reason.
reason No String or null Human-readable reason.
metadata No Object or null Application-defined data.

Save writes the complete editable DNE record. Omitted type and source use their defaults; omitted reason_code, reason, and metadata become null on update.

curl -sS https://api.post.m7.org/v1/members/policy/dne/save \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "group_name": "transactional-email",
    "email": "recipient@example.test",
    "type": "soft",
    "source": "manual",
    "reason_code": "user_request"
  }'

The response contains data.saved: true and data.item, including id, email, derived domain, group, type, and source.

Domain policies

A domain policy stores an allow or block decision for one exact domain in a policy group.

Route Required fields Optional fields and behavior
POST /v1/members/policy/domain/get Group scope; id or domain Returns data.item, which is null when no scoped record matches.
POST /v1/members/policy/domain/check Group scope; id or domain Returns data.match and data.item.
POST /v1/members/policy/domain/list Group scope Exact filters: id, domain, policy, include_subdomains, source, reason_code; supports shared pagination.
POST /v1/members/policy/domain/save Group scope, domain, policy Creates or updates the record scoped to that group and domain.
POST /v1/members/policy/domain/delete Group scope; id or domain Deletes the scoped record.

Domain-policy save fields

Field Required Type Description
domain Yes String Domain name without an @ or spaces. The API lowercases it.
policy Yes String allow or block.
include_subdomains No Boolean Defaults to true; stored with the record.
source No String manual (default), import, or system.
reason_code No String or null Machine-readable reason.
reason No String or null Human-readable reason.
metadata No Object or null Application-defined data.

Save writes the complete editable domain-policy record. Omitted include_subdomains defaults to true, source defaults to manual, and omitted reason_code, reason, and metadata become null on update.

curl -sS https://api.post.m7.org/v1/members/policy/domain/save \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "group_id": "POLICY_GROUP_UUID",
    "domain": "example.test",
    "policy": "block",
    "include_subdomains": true,
    "source": "manual"
  }'

The response contains data.saved: true and data.item, including id, group, domain, policy, and include_subdomains.

get and check match the exact requested domain. They do not expand a lookup to subdomains; use include_subdomains as the stored policy attribute.

Errors and scope

  • A missing, unowned, or mismatched group reference fails before the child operation.
  • A child record ID from another group is treated as not found.
  • get and check return a successful response with a null item or match: false when no scoped record exists; delete returns a not-found error in that case.