openmail-sh Policy API

Correspondent policy — provider-enforced allow/block rules and allowlist mode, scoped per account, pod, or inbox. Account-wide key only.

Operations 6

GET /v1/policy Get correspondent policy #
PUT /v1/policy Replace correspondent policy #
GET /v1/policy/audit List correspondent policy audit events #
PUT /v1/policy/mode Set correspondent policy mode #
POST /v1/policy/rules Add correspondent policy rule #
DELETE /v1/policy/rules/{id} Delete correspondent policy rule #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/openmail-sh:openmail-sh-policy-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

openmail-sh-policy-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: OpenMail Policy API
  description: Email infrastructure API for AI agents. Create inboxes, send and receive email, and get real-time notifications via webhooks.
  version: 1.0.0
  license:
    name: Proprietary
servers:
- url: https://api.openmail.sh
security:
- bearerAuth: []
tags:
- name: Policy
  description: Correspondent policy — provider-enforced allow/block rules and allowlist mode, scoped per account, pod, or inbox. Account-wide key only.
paths:
  /v1/policy:
    get:
      operationId: getPolicy
      summary: Get correspondent policy
      tags:
      - Policy
      description: Read the correspondent policy for a scope (account by default, or a pod/inbox). Returns the mode this scope sets for each direction, the effective mode after inheritance, this scope's own rules, and the rules inherited from parent scopes. Inbox-scoped keys are rejected. A pod-scoped key may read its own pod or an inbox in that pod, never account-wide policy. Account-wide keys may read any scope.
      parameters:
      - schema:
          type: string
        in: query
        name: podId
        required: false
        description: Confine the operation to one pod's policy. Accepts the pod ID. Mutually exclusive with `inboxId`.
      - schema:
          type: string
        in: query
        name: inboxId
        required: false
        description: Confine the operation to one inbox's policy. Mutually exclusive with `podId`.
      responses:
        '200':
          description: The resolved policy for the scope
          content:
            application/json:
              schema:
                description: The resolved policy for the scope
                type: object
                additionalProperties: true
        '403':
          description: The authenticating key is scoped and cannot read policy (`forbidden`)
          content:
            application/json:
              schema:
                description: The authenticating key is scoped and cannot read policy (`forbidden`)
                allOf:
                - $ref: '#/components/schemas/Error'
        '404':
          description: Pod or inbox not found
          content:
            application/json:
              schema:
                description: Pod or inbox not found
                allOf:
                - $ref: '#/components/schemas/Error'
    put:
      operationId: replacePolicy
      summary: Replace correspondent policy
      tags:
      - Policy
      description: Declaratively set a scope's entire policy in one call — ideal for automated provisioning. Sets the inbound and/or outbound mode and REPLACES the scope's own rules for any direction you include. Rules created here are fail-closed (an empty allowlist denies all). Omitted directions are left untouched. Inbox-scoped keys are rejected. A pod-scoped key may mutate its own pod or an inbox in that pod, never account-wide policy. Pod keys cannot set `none` or extra allows on a parent allowlist.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                inbound:
                  type: object
                  additionalProperties: false
                  description: Inbound (who may send to this scope) policy to set. Omit to leave inbound untouched.
                  properties:
                    mode:
                      type: string
                      enum:
                      - none
                      - allowlist
                      - inherit
                      description: '`none` = no filtering; `allowlist` = only listed correspondents are permitted (empty allowlist denies all — fail closed); `inherit` = defer to the parent scope (pod, then account). Not valid at the account scope.'
                    rules:
                      type: array
                      maxItems: 500
                      description: Replaces this scope's own inbound rules. Omit to leave rules untouched; pass [] to clear them.
                      items:
                        type: object
                        additionalProperties: false
                        required:
                        - type
                        - value
                        properties:
                          type:
                            type: string
                            enum:
                            - allow
                            - block
                          value:
                            type: string
                            minLength: 3
                            maxLength: 255
                            description: An email address (`user@example.com`), a whole domain (`example.com`), or a domain and all its subdomains (`*.example.com`, which also covers `example.com` itself).
                outbound:
                  type: object
                  additionalProperties: false
                  description: Outbound (who this scope may send to) policy to set. Omit to leave outbound untouched.
                  properties:
                    mode:
                      type: string
                      enum:
                      - none
                      - allowlist
                      - inherit
                      description: '`none` = no filtering; `allowlist` = only listed correspondents are permitted (empty allowlist denies all — fail closed); `inherit` = defer to the parent scope (pod, then account). Not valid at the account scope.'
                    rules:
                      type: array
                      maxItems: 500
                      description: Replaces this scope's own outbound rules. Omit to leave rules untouched; pass [] to clear them.
                      items:
                        type: object
                        additionalProperties: false
                        required:
                        - type
                        - value
                        properties:
                          type:
                            type: string
                            enum:
                            - allow
                            - block
                          value:
                            type: string
                            minLength: 3
                            maxLength: 255
      parameters:
      - schema:
          type: string
        in: query
        name: podId
        required: false
        description: Confine the operation to one pod's policy. Accepts the pod ID. Mutually exclusive with `inboxId`.
      - schema:
          type: string
        in: query
        name: inboxId
        required: false
        description: Confine the operation to one inbox's policy. Mutually exclusive with `podId`.
      responses:
        '200':
          description: The resulting policy for the scope
          content:
            application/json:
              schema:
                description: The resulting policy for the scope
                type: object
                additionalProperties: true
        '403':
          description: The authenticating key is scoped and cannot manage policy
          content:
            application/json:
              schema:
                description: The authenticating key is scoped and cannot manage policy
                allOf:
                - $ref: '#/components/schemas/Error'
        '404':
          description: Pod or inbox not found
          content:
            application/json:
              schema:
                description: Pod or inbox not found
                allOf:
                - $ref: '#/components/schemas/Error'
        '422':
          description: Invalid mode for the scope, or an invalid rule value
          content:
            application/json:
              schema:
                description: Invalid mode for the scope, or an invalid rule value
                allOf:
                - $ref: '#/components/schemas/Error'
  /v1/policy/audit:
    get:
      operationId: getPolicyAudit
      summary: List correspondent policy audit events
      tags:
      - Policy
      description: 'Read the append-only audit trail for correspondent policy, newest first. Two kinds of event share one stream: `rule_added`, `rule_removed`, `mode_changed`, and `scope_deleted` record who moved the boundary and how (`scope_deleted` covers a pod or inbox being deleted, which cascade-deletes its policy — the row carries the modes and rules that were removed, so lifting a restriction by deleting its scope is not a silent operation). `send_rejected` and `inbound_rejected` record what the boundary refused: a send the outbound policy would not make, and inbound mail it would not accept. Both are deduped to one row per inbox + correspondent per hour, so neither a looping agent nor an outside sender can flood the trail. `inbound_rejected_no_inbox` records mail a verified custom domain accepted for an address with no inbox: it is dropped after SMTP, so the sender gets no bounce and this row is the only trace the domain''s owner can reach. It is deduped per address per hour and capped per organisation per hour. Rows are never updated or deleted. Inbox-scoped keys are rejected. A pod-scoped key may read the trail for its own pod or an inbox in that pod (`?podId=` / `?inboxId=`), never the unfiltered account-wide trail.'
      parameters:
      - schema:
          type: string
        in: query
        name: podId
        required: false
        description: Confine the operation to one pod's policy. Accepts the pod ID. Mutually exclusive with `inboxId`.
      - schema:
          type: string
        in: query
        name: inboxId
        required: false
        description: Confine the operation to one inbox's policy. Mutually exclusive with `podId`.
      - schema:
          type: string
        in: query
        name: action
        required: false
        description: 'Comma-separated actions to include: `rule_added`, `rule_removed`, `mode_changed`, `scope_deleted`, `send_rejected`, `inbound_rejected`, `inbound_rejected_no_inbox`. Omit for all.'
      - schema:
          type: string
          enum:
          - inbound
          - outbound
        in: query
        name: direction
        required: false
        description: '`inbound` governs who may send to the inbox; `outbound` governs who the inbox may send to (enforced across To, Cc, Bcc, and Reply-To on every send path).'
      - schema:
          type: string
        in: query
        name: since
        required: false
        description: ISO-8601 timestamp. Only events at or after this time (inclusive).
      - schema:
          type: string
        in: query
        name: until
        required: false
        description: ISO-8601 timestamp. Only events strictly before this time.
      - schema:
          type: string
        in: query
        name: limit
        required: false
        description: Page size, 1–100. Defaults to 50.
      - schema:
          type: string
        in: query
        name: offset
        required: false
        description: Rows to skip. Defaults to 0.
      responses:
        '200':
          description: 'A page of audit events plus the unpaginated `total`. Each event carries its scope (with the pod name / inbox address resolved at read time, or null if since deleted), the acting console user where there was one, and an action-specific `detail` object: `type`/`valueType`/`value` for rule events, `from`/`to` for mode changes, and `rejectedRecipient`/`reason`/`matchedScope` for rejected sends.'
          content:
            application/json:
              schema:
                description: 'A page of audit events plus the unpaginated `total`. Each event carries its scope (with the pod name / inbox address resolved at read time, or null if since deleted), the acting console user where there was one, and an action-specific `detail` object: `type`/`valueType`/`value` for rule events, `from`/`to` for mode changes, and `rejectedRecipient`/`reason`/`matchedScope` for rejected sends.'
                type: object
                additionalProperties: true
        '400':
          description: An unknown `action`, or a `since`/`until` that is not a valid timestamp
          content:
            application/json:
              schema:
                description: An unknown `action`, or a `since`/`until` that is not a valid timestamp
                allOf:
                - $ref: '#/components/schemas/Error'
        '403':
          description: The authenticating key is scoped and cannot read the audit trail (`forbidden`)
          content:
            application/json:
              schema:
                description: The authenticating key is scoped and cannot read the audit trail (`forbidden`)
                allOf:
                - $ref: '#/components/schemas/Error'
        '404':
          description: Pod or inbox not found
          content:
            application/json:
              schema:
                description: Pod or inbox not found
                allOf:
                - $ref: '#/components/schemas/Error'
  /v1/policy/mode:
    put:
      operationId: setPolicyMode
      summary: Set correspondent policy mode
      tags:
      - Policy
      description: Set the filtering mode for one direction of a scope's policy, without touching rules. Inbox-scoped keys are rejected. A pod-scoped key may mutate its own pod or an inbox in that pod, never account-wide policy. Pod keys cannot set `none`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
              - mode
              properties:
                mode:
                  type: string
                  enum:
                  - none
                  - allowlist
                  - inherit
                  description: '`none` = no filtering; `allowlist` = only listed correspondents are permitted (empty allowlist denies all — fail closed); `inherit` = defer to the parent scope (pod, then account). Not valid at the account scope.'
                direction:
                  type: string
                  enum:
                  - inbound
                  - outbound
                  description: '`inbound` governs who may send to the inbox; `outbound` governs who the inbox may send to (enforced across To, Cc, Bcc, and Reply-To on every send path).'
      parameters:
      - schema:
          type: string
        in: query
        name: podId
        required: false
        description: Confine the operation to one pod's policy. Accepts the pod ID. Mutually exclusive with `inboxId`.
      - schema:
          type: string
        in: query
        name: inboxId
        required: false
        description: Confine the operation to one inbox's policy. Mutually exclusive with `podId`.
      responses:
        '200':
          description: The updated mode
          content:
            application/json:
              schema:
                description: The updated mode
                type: object
                additionalProperties: true
        '403':
          description: The authenticating key is scoped and cannot manage policy
          content:
            application/json:
              schema:
                description: The authenticating key is scoped and cannot manage policy
                allOf:
                - $ref: '#/components/schemas/Error'
        '404':
          description: Pod or inbox not found
          content:
            application/json:
              schema:
                description: Pod or inbox not found
                allOf:
                - $ref: '#/components/schemas/Error'
        '422':
          description: Invalid mode for the scope
          content:
            application/json:
              schema:
                description: Invalid mode for the scope
                allOf:
                - $ref: '#/components/schemas/Error'
  /v1/policy/rules:
    post:
      operationId: addPolicyRule
      summary: Add correspondent policy rule
      tags:
      - Policy
      description: Add one allow/block rule for a direction of a scope's policy. Inbox-scoped keys are rejected. A pod-scoped key may mutate its own pod or an inbox in that pod, never account-wide policy. Pod keys cannot add allows on a parent allowlist (blocks are fine).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
              - type
              - value
              properties:
                type:
                  type: string
                  enum:
                  - allow
                  - block
                value:
                  type: string
                  minLength: 3
                  maxLength: 255
                  description: An email address (`user@example.com`), a whole domain (`example.com`), or a domain and all its subdomains (`*.example.com`, which also covers `example.com` itself).
                direction:
                  type: string
                  enum:
                  - inbound
                  - outbound
                  description: '`inbound` governs who may send to the inbox; `outbound` governs who the inbox may send to (enforced across To, Cc, Bcc, and Reply-To on every send path).'
      parameters:
      - schema:
          type: string
        in: query
        name: podId
        required: false
        description: Confine the operation to one pod's policy. Accepts the pod ID. Mutually exclusive with `inboxId`.
      - schema:
          type: string
        in: query
        name: inboxId
        required: false
        description: Confine the operation to one inbox's policy. Mutually exclusive with `podId`.
      responses:
        '201':
          description: Rule created
          content:
            application/json:
              schema:
                description: Rule created
                type: object
                additionalProperties: true
        '403':
          description: The authenticating key is scoped and cannot manage policy
          content:
            application/json:
              schema:
                description: The authenticating key is scoped and cannot manage policy
                allOf:
                - $ref: '#/components/schemas/Error'
        '404':
          description: Pod or inbox not found
          content:
            application/json:
              schema:
                description: Pod or inbox not found
                allOf:
                - $ref: '#/components/schemas/Error'
        '409':
          description: An identical rule already exists (`rule_exists`)
          content:
            application/json:
              schema:
                description: An identical rule already exists (`rule_exists`)
                allOf:
                - $ref: '#/components/schemas/Error'
        '422':
          description: The value is not a valid email or domain
          content:
            application/json:
              schema:
                description: The value is not a valid email or domain
                allOf:
                - $ref: '#/components/schemas/Error'
  /v1/policy/rules/{id}:
    delete:
      operationId: deletePolicyRule
      summary: Delete correspondent policy rule
      tags:
      - Policy
      description: Remove a single policy rule by its ID. Inbox-scoped keys are rejected. A pod-scoped key may delete a rule on its own pod or an inbox in that pod, never an account-wide rule.
      parameters:
      - schema:
          type: string
        in: path
        name: id
        required: true
        description: The rule ID to delete
      responses:
        '204':
          description: Rule deleted
        '403':
          description: The authenticating key is scoped and cannot manage policy
          content:
            application/json:
              schema:
                description: The authenticating key is scoped and cannot manage policy
                allOf:
                - $ref: '#/components/schemas/Error'
        '404':
          description: Rule not found
          content:
            application/json:
              schema:
                description: Rule not found
                allOf:
                - $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      additionalProperties: true
      properties:
        error:
          type: string
        message:
          type: string
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key