Skip to content

Governance ​

Routes are relative to <PUBLIC_BASE_URL>; request and response bodies are JSON unless stated otherwise. Authentication, scopes, pagination and the error format are described in the REST API guides.

GET /api/v1/admin/scope ​

Read the organisation scope

Access — Member session or API key with scope admin:read (administrator role required).

Responses

200 — The organisation scope.

FieldTypeRequired
scopeobjectyes
JSON Schema
json
{
  "type": "object",
  "properties": {
    "scope": {
      "type": "object",
      "properties": {
        "excludedDomains": {
          "maxItems": 500,
          "type": "array",
          "items": { "type": "string", "minLength": 1, "maxLength": 320 }
        },
        "excludedEmails": {
          "maxItems": 500,
          "type": "array",
          "items": { "type": "string", "minLength": 1, "maxLength": 320 }
        }
      },
      "required": [ "excludedDomains", "excludedEmails" ],
      "additionalProperties": false
    }
  },
  "required": [ "scope" ],
  "additionalProperties": false
}

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

PUT /api/v1/admin/scope ​

Replace the organisation scope

Replaces both lists. The response is the normalised form (lower case, leading @ removed, duplicates merged): exactly what evaluation compares. Applies to future ingestion only.

Access — Member session or API key with scope admin:write (administrator role required).

Request body (application/json)

FieldTypeRequired
excludedDomainsstring[]no
excludedEmailsstring[]no
JSON Schema
json
{
  "type": "object",
  "properties": {
    "excludedDomains": {
      "default": [],
      "maxItems": 500,
      "type": "array",
      "items": { "type": "string", "minLength": 1, "maxLength": 320 }
    },
    "excludedEmails": {
      "default": [],
      "maxItems": 500,
      "type": "array",
      "items": { "type": "string", "minLength": 1, "maxLength": 320 }
    }
  }
}

Responses

200 — The organisation scope, normalised.

FieldTypeRequired
scopeobjectyes

Same schema as GET /api/v1/admin/scope.

400 — The request does not match its schema.

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

Error codes — request.bad_request. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.

GET /api/v1/admin/node-policy ​

Read the node policy

One entry per catalogue type: allowed, forbidden, or restricted to administrators.

Access — Member session or API key with scope admin:read (administrator role required).

Responses

200 — The policy.

FieldTypeRequired
entriesobject[]yes
JSON Schema
json
{
  "type": "object",
  "properties": {
    "entries": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "nodeType": { "type": "string" },
          "allowed": { "type": "boolean" },
          "restrictedToRole": {
            "anyOf": [ { "type": "string", "const": "admin" }, { "type": "null" } ]
          },
          "configured": { "type": "boolean" },
          "group": { "type": "string" },
          "category": { "type": "string" },
          "effect": { "type": "string" }
        },
        "required": [
          "nodeType",
          "allowed",
          "restrictedToRole",
          "configured",
          "group",
          "effect"
        ],
        "additionalProperties": false
      }
    }
  },
  "required": [ "entries" ],
  "additionalProperties": false
}

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

PUT /api/v1/admin/node-policy ​

Update the node policy

Partial: only the listed types change. The response is the complete policy, not the delta. A type unknown to the catalogue is refused.

Access — Member session or API key with scope admin:write (administrator role required).

Request body (application/json)

FieldTypeRequired
entriesobject[]yes
JSON Schema
json
{
  "type": "object",
  "properties": {
    "entries": {
      "minItems": 1,
      "maxItems": 200,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "nodeType": { "type": "string", "minLength": 1, "maxLength": 120 },
          "allowed": { "default": true, "type": "boolean" },
          "restrictedToRole": {
            "default": null,
            "anyOf": [ { "type": "string", "const": "admin" }, { "type": "null" } ]
          }
        },
        "required": [ "nodeType" ]
      }
    }
  },
  "required": [ "entries" ]
}

Responses

200 — The policy, complete.

FieldTypeRequired
entriesobject[]yes

Same schema as GET /api/v1/admin/node-policy.

400 — The request does not match its schema.

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

Error codes — request.bad_request, governance.unknown_node_type. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.

GET /api/v1/admin/business-calendar ​

Read the business calendar

Time zone, working days and hours, holiday region and closed days, with the computed public holidays for this year and next and the instance’s maximum wait.

Access — Member session or API key with scope admin:read (administrator role required).

Responses

200 — The calendar.

FieldTypeRequired
calendarobjectyes
maxWaitDaysintegeryes
holidaysobject[]yes
JSON Schema
json
{
  "type": "object",
  "properties": {
    "calendar": {
      "type": "object",
      "properties": {
        "timezone": { "type": "string", "minLength": 1, "maxLength": 100 },
        "workdays": {
          "minItems": 1,
          "maxItems": 7,
          "type": "array",
          "items": { "type": "integer", "minimum": 1, "maximum": 7 }
        },
        "hours": {
          "type": "object",
          "properties": {
            "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" },
            "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" }
          },
          "required": [ "start", "end" ],
          "additionalProperties": false
        },
        "holidayRegion": { "type": "string", "enum": [ "none", "FR", "BE" ] },
        "closedDays": {
          "maxItems": 400,
          "type": "array",
          "items": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }
        }
      },
      "required": [ "timezone", "workdays", "hours", "holidayRegion", "closedDays" ],
      "additionalProperties": false
    },
    "maxWaitDays": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 },
    "holidays": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "day": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
          "year": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          }
        },
        "required": [ "day", "year" ],
        "additionalProperties": false
      }
    }
  },
  "required": [ "calendar", "maxWaitDays", "holidays" ],
  "additionalProperties": false
}

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

PUT /api/v1/admin/business-calendar ​

Replace the business calendar

A full replacement. An unknown time zone, an empty working window or an invalid closed day is refused with wait.calendar_invalid. Recorded in the audit log.

Access — Member session or API key with scope admin:write (administrator role required).

Request body (application/json)

FieldTypeRequired
timezonestringyes
workdaysinteger[]yes
hoursobjectyes
holidayRegion"none" | "FR" | "BE"yes
closedDaysstring[]yes
JSON Schema
json
{
  "type": "object",
  "properties": {
    "timezone": { "type": "string", "minLength": 1, "maxLength": 100 },
    "workdays": {
      "minItems": 1,
      "maxItems": 7,
      "type": "array",
      "items": { "type": "integer", "minimum": 1, "maximum": 7 }
    },
    "hours": {
      "type": "object",
      "properties": {
        "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" },
        "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" }
      },
      "required": [ "start", "end" ]
    },
    "holidayRegion": { "type": "string", "enum": [ "none", "FR", "BE" ] },
    "closedDays": {
      "maxItems": 400,
      "type": "array",
      "items": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }
    }
  },
  "required": [ "timezone", "workdays", "hours", "holidayRegion", "closedDays" ]
}

Responses

200 — The calendar, after write.

FieldTypeRequired
calendarobjectyes
maxWaitDaysintegeryes
holidaysobject[]yes

Same schema as GET /api/v1/admin/business-calendar.

400 — The request does not match its schema.

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

Error codes — wait.bad_request, wait.calendar_invalid. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.

GET /api/v1/admin/instance ​

The instance and its control plane link

The state of the link to the control plane, the plan and entitlements received, and the origin of each brand field (control plane, environment or default).

Access — Member session or API key with scope admin:read (administrator role required).

Responses

200 — The status.

FieldTypeRequired
controlPlaneobjectyes
brandingobjectyes
brandFieldsobject[]yes
JSON Schema
json
{
  "type": "object",
  "properties": {
    "controlPlane": {
      "type": "object",
      "properties": {
        "configured": { "type": "boolean" },
        "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
        "instanceId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
        "instanceStatus": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
        "heartbeat": {
          "type": "object",
          "properties": {
            "lastSuccessAt": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            },
            "lastAttemptAt": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            },
            "lastError": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "code": { "type": "string" },
                    "status": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        { "type": "null" }
                      ]
                    },
                    "at": {
                      "type": "string",
                      "format": "date-time",
                      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                    }
                  },
                  "required": [ "code", "status", "at" ],
                  "additionalProperties": false
                },
                { "type": "null" }
              ]
            }
          },
          "required": [ "lastSuccessAt", "lastAttemptAt", "lastError" ],
          "additionalProperties": false
        },
        "usage": {
          "type": "object",
          "properties": {
            "lastSuccessAt": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            },
            "lastAttemptAt": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            },
            "lastError": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "code": { "type": "string" },
                    "status": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        { "type": "null" }
                      ]
                    },
                    "at": {
                      "type": "string",
                      "format": "date-time",
                      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                    }
                  },
                  "required": [ "code", "status", "at" ],
                  "additionalProperties": false
                },
                { "type": "null" }
              ]
            },
            "pendingPeriods": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
            "oldestPendingPeriod": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            }
          },
          "required": [
            "lastSuccessAt",
            "lastAttemptAt",
            "lastError",
            "pendingPeriods",
            "oldestPendingPeriod"
          ],
          "additionalProperties": false
        },
        "config": {
          "type": "object",
          "properties": {
            "lastSuccessAt": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            },
            "lastAttemptAt": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            },
            "lastError": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "code": { "type": "string" },
                    "status": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        { "type": "null" }
                      ]
                    },
                    "at": {
                      "type": "string",
                      "format": "date-time",
                      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                    }
                  },
                  "required": [ "code", "status", "at" ],
                  "additionalProperties": false
                },
                { "type": "null" }
              ]
            },
            "etag": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
            "receivedAt": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                },
                { "type": "null" }
              ]
            }
          },
          "required": [
            "lastSuccessAt",
            "lastAttemptAt",
            "lastError",
            "etag",
            "receivedAt"
          ],
          "additionalProperties": false
        },
        "plan": {
          "anyOf": [
            {
              "type": "object",
              "properties": {
                "key": { "type": "string" },
                "name": { "type": "string" },
                "version": {
                  "anyOf": [
                    {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    { "type": "null" }
                  ]
                },
                "since": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
                "until": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
              },
              "required": [ "key", "name", "version", "since", "until" ],
              "additionalProperties": false
            },
            { "type": "null" }
          ]
        },
        "entitlements": {
          "anyOf": [
            {
              "type": "object",
              "propertyNames": { "type": "string" },
              "additionalProperties": {}
            },
            { "type": "null" }
          ]
        }
      },
      "required": [
        "configured",
        "url",
        "instanceId",
        "instanceStatus",
        "heartbeat",
        "usage",
        "config",
        "plan",
        "entitlements"
      ],
      "additionalProperties": false
    },
    "branding": {
      "type": "object",
      "properties": {
        "name": { "type": "string", "minLength": 1 },
        "source": { "type": "string", "enum": [ "control_plane", "environment" ] },
        "logo": {
          "type": "object",
          "properties": {
            "light": {
              "anyOf": [ { "type": "string", "format": "uri" }, { "type": "null" } ]
            },
            "dark": {
              "anyOf": [ { "type": "string", "format": "uri" }, { "type": "null" } ]
            }
          },
          "required": [ "light", "dark" ],
          "additionalProperties": false
        },
        "favicon": {
          "anyOf": [ { "type": "string", "format": "uri" }, { "type": "null" } ]
        },
        "colors": {
          "type": "object",
          "properties": {
            "primary": {
              "anyOf": [
                { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
                { "type": "null" }
              ]
            },
            "onPrimary": {
              "anyOf": [
                { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
                { "type": "null" }
              ]
            },
            "accent": {
              "anyOf": [
                { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
                { "type": "null" }
              ]
            },
            "onAccent": {
              "anyOf": [
                { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
                { "type": "null" }
              ]
            }
          },
          "required": [ "primary", "onPrimary", "accent", "onAccent" ],
          "additionalProperties": false
        },
        "supportUrl": {
          "anyOf": [ { "type": "string", "format": "uri" }, { "type": "null" } ]
        },
        "poweredBy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
        "login": {
          "type": "object",
          "properties": {
            "welcome": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": { "en": { "type": "string" }, "fr": { "type": "string" } },
                  "additionalProperties": false
                },
                { "type": "null" }
              ]
            },
            "image": {
              "anyOf": [ { "type": "string", "format": "uri" }, { "type": "null" } ]
            }
          },
          "required": [ "welcome", "image" ],
          "additionalProperties": false
        },
        "instance": {
          "type": "object",
          "properties": { "suspended": { "type": "boolean" } },
          "required": [ "suspended" ],
          "additionalProperties": false
        }
      },
      "required": [
        "name",
        "source",
        "logo",
        "favicon",
        "colors",
        "supportUrl",
        "poweredBy",
        "login",
        "instance"
      ],
      "additionalProperties": false
    },
    "brandFields": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "enum": [
              "name",
              "logoLight",
              "logoDark",
              "favicon",
              "primaryColor",
              "accentColor",
              "supportUrl",
              "poweredBy",
              "customDomain",
              "emailFromName",
              "emailFooter",
              "loginWelcome",
              "loginImage"
            ]
          },
          "value": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
          "origin": {
            "type": "string",
            "enum": [ "control_plane", "environment", "default" ]
          },
          "variable": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
        },
        "required": [ "field", "value", "origin", "variable" ],
        "additionalProperties": false
      }
    }
  },
  "required": [ "controlPlane", "branding", "brandFields" ],
  "additionalProperties": false
}

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

GET /api/v1/admin/send-settings ​

Read the sending guard-rails

The kill switch and the hourly rate of the organisation. lockedByInstance says whether SEND_ENABLED=false overrides the setting.

Access — Member session or API key with scope admin:read (administrator role required).

Responses

200 — The settings.

FieldTypeRequired
settingsobjectyes
lockedByInstancebooleanyes
JSON Schema
json
{
  "type": "object",
  "properties": {
    "settings": {
      "type": "object",
      "properties": {
        "enabled": { "type": "boolean" },
        "maxPerHour": { "type": "integer", "minimum": 1, "maximum": 10000 }
      },
      "required": [ "enabled", "maxPerHour" ],
      "additionalProperties": false
    },
    "lockedByInstance": { "type": "boolean" }
  },
  "required": [ "settings", "lockedByInstance" ],
  "additionalProperties": false
}

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.

PUT /api/v1/admin/send-settings ​

Change the sending guard-rails

Partial replacement: cutting sending is { "enabled": false }, nothing else is touched.

Access — Member session or API key with scope admin:write (administrator role required).

Request body (application/json)

FieldTypeRequired
enabledbooleanno
maxPerHourintegerno
JSON Schema
json
{
  "type": "object",
  "properties": {
    "enabled": { "type": "boolean" },
    "maxPerHour": { "type": "integer", "minimum": 1, "maximum": 10000 }
  }
}

Responses

200 — The settings, after.

FieldTypeRequired
settingsobjectyes
lockedByInstancebooleanyes

Same schema as GET /api/v1/admin/send-settings.

400 — The request does not match its schema.

401 — No valid session or API key (auth.unauthenticated).

403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).

429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.