/alerts/config - Save the caller's alerting layer

Add MCP server to your AI tool

Allow AI tools and LLMs to interact with the API documentation portal through MCP.

MCP server URL

https://api.my.nethesis.it/mcp

Standard setup for AI tools providing an mcp.json file

mcp.json
{
  "my.nethesis.it MCP server": {
    "url": "https://api.my.nethesis.it/mcp"
  }
}

Close
POST /alerts/config

Saves the CALLER's alerting configuration layer (one row per organization in alert_config_layers). The body is an AlertingConfigLayer: three channel toggles plus three recipient lists. Each recipient carries its own severities[]; email recipients additionally carry language and format.

After save, the effective per-tenant Mimir YAML is recomputed server-side (merge of all layers walking up to the Owner) and pushed to every tenant in the caller's hierarchy with bounded concurrency. Up to 10 tenants are pushed inside the request and per-tenant failures are returned in warnings[]; larger fan-outs run in the background (propagation: async) with retries, and their progress is reported by GET /alerts/config in propagation. The caller's layer is saved regardless of push outcome (Mimir can be reconciled by saving again).

Additive-only contract: descendants can ADD recipients but cannot disable channels enabled by ancestors. The server normalises any explicit false in enabled.{email,webhook,telegram} from non-Owner layers to null on storage.

Save+propagate is serialised per-organization (in-process mutex) to prevent two concurrent saves from racing at the Mimir push step. Body is capped at 1 MiB; oversized payloads are rejected with 413.

Requires manage:alerts permission.

application/json

Body Required

  • enabled object

    Per-layer enable/disable for each notification channel. Each value is tri-state:

    • true — explicitly enabled at this layer
    • false — explicitly disabled (Owner only; non-Owner false is normalised to null on save)
    • null — no opinion at this layer; effective state inherits from the merge of any ancestor layer that took a position. If no layer in the chain enables a channel, the channel stays off.
    Hide enabled attributes Show enabled attributes object
    • email boolean | null
    • webhook boolean | null
    • telegram boolean | null
  • email_recipients array[object]

    Not more than 50 elements.

    Hide email_recipients attributes Show email_recipients attributes object
    • address string(email) Required

      Maximum length is 320.

    • severities array[string]

      Severity scope for this recipient. Empty (or omitted) means "all severities" — the recipient lands on every per-severity receiver. A non-empty subset narrows delivery to those severities.

      Not more than 3 elements. Values are critical, warning, or info.

    • language string

      Rendering language for this recipient's email body and subject. Defaults to en when omitted.

      Values are en or it.

    • format string

      Body format preference. html (default) emits multipart with an html primary body and text alternative; plain emits only a text body.

      Values are html or plain.

    • scope object

      Narrows a recipient to the alerts of some organizations and/or some systems; an alert matches when it falls in any list. Omitted or all lists empty means every system the layer reaches. Every id must belong to the caller's hierarchy, otherwise the save fails with out_of_scope on <channel>_recipients.<i>.scope.

      Hide scope attributes Show scope attributes object
      • managed_organization_ids array[string]

        "Managed by": the systems of each organization and of its whole sub-tree (a distributor's resellers and customers, a reseller's customers).

        Not more than 100 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • organization_ids array[string] Deprecated

        Legacy name of managed_organization_ids, still accepted on input and never returned.

        Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • assigned_organization_ids array[string]

        Only the systems assigned to each organization itself, not those of the organizations it manages.

        Not more than 100 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • system_ids array[string]

        Not more than 500 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

  • webhook_recipients array[object]

    Not more than 20 elements.

    Hide webhook_recipients attributes Show webhook_recipients attributes object
    • name string Required

      Descriptive label for the webhook target (UI only).

      Maximum length is 100.

    • url string(uri) Required

      Webhook URL. Validation rejects non-public destinations (loopback, RFC1918, RFC6598 CGNAT, link-local, multicast, cloud metadata) and requires a canonical hostname (containing at least one letter) or a valid IP literal. Only http/https schemes are accepted; URLs cannot embed userinfo.

      Maximum length is 2048.

    • severities array[string]

      Not more than 3 elements. Values are critical, warning, or info.

    • scope object

      Narrows a recipient to the alerts of some organizations and/or some systems; an alert matches when it falls in any list. Omitted or all lists empty means every system the layer reaches. Every id must belong to the caller's hierarchy, otherwise the save fails with out_of_scope on <channel>_recipients.<i>.scope.

      Hide scope attributes Show scope attributes object
      • managed_organization_ids array[string]

        "Managed by": the systems of each organization and of its whole sub-tree (a distributor's resellers and customers, a reseller's customers).

        Not more than 100 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • organization_ids array[string] Deprecated

        Legacy name of managed_organization_ids, still accepted on input and never returned.

        Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • assigned_organization_ids array[string]

        Only the systems assigned to each organization itself, not those of the organizations it manages.

        Not more than 100 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • system_ids array[string]

        Not more than 500 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

  • telegram_recipients array[object]

    Not more than 20 elements.

    Hide telegram_recipients attributes Show telegram_recipients attributes object
    • bot_token string Required

      Maximum length is 256.

    • chat_id integer(int64) Required
    • message_thread_id integer(int64)

      Topic of a forum-enabled supergroup to post into. Omit to post in the General topic (or in the plain chat when topics are off).

      Minimum value is 1.

    • severities array[string]

      Not more than 3 elements. Values are critical, warning, or info.

    • scope object

      Narrows a recipient to the alerts of some organizations and/or some systems; an alert matches when it falls in any list. Omitted or all lists empty means every system the layer reaches. Every id must belong to the caller's hierarchy, otherwise the save fails with out_of_scope on <channel>_recipients.<i>.scope.

      Hide scope attributes Show scope attributes object
      • managed_organization_ids array[string]

        "Managed by": the systems of each organization and of its whole sub-tree (a distributor's resellers and customers, a reseller's customers).

        Not more than 100 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • organization_ids array[string] Deprecated

        Legacy name of managed_organization_ids, still accepted on input and never returned.

        Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • assigned_organization_ids array[string]

        Only the systems assigned to each organization itself, not those of the organizations it manages.

        Not more than 100 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

      • system_ids array[string]

        Not more than 500 elements. Format of each should match the following pattern: ^[A-Za-z0-9_-]{1,255}$.

Responses

  • 200 application/json

    Layer saved (and propagation attempted)

    Hide response attributes Show response attributes object
    • code integer
    • message string
    • data object
      Hide data attributes Show data attributes object
      • affected_tenants integer

        Number of tenants in caller's hierarchy whose effective config was recomputed

      • propagation string

        sync when the tenants were pushed inside the request (up to 10); async when the push runs in the background (Owner and large distributors), with retries and failures logged server-side.

        Values are sync or async.

      • propagated_to integer

        Of affected_tenants, how many were successfully pushed to Mimir. Only with propagation=sync.

      • warnings array[string]

        Per-tenant push errors. Always present; empty when every push succeeded and always empty with propagation=async. Each entry: org <logto_id>: <error>.

  • 400 application/json

    Validation failed. data.type is always validation_error. data.errors[] lists per-field failures with key set to the JSON path (with dotted array indices, e.g. email_recipients.2.address), message to a stable machine code (required, invalid_format, invalid_value, invalid_scheme, host_not_allowed, must_be_future, ...) and value to the offending input when not sensitive.

    Hide response attributes Show response attributes object
    • code integer

      HTTP error code

    • message string

      Error message

    • data object
      Hide data attributes Show data attributes object
      • type string

        Type of error

        Values are validation_error or external_api_error.

      • errors array[object]
        Hide errors attributes Show errors attributes object
        • key string

          Field name that failed validation

        • message string

          Error code or message

        • value string

          Value that failed validation

      • details

        Additional error details

  • 401 application/json

    Unauthorized - invalid or missing token

    Hide response attributes Show response attributes object
    • code integer
    • message string
    • data object | null
  • 403 application/json

    Forbidden - insufficient permissions

    Hide response attributes Show response attributes object
    • code integer
    • message string
    • data object | null
  • 413 application/json

    Request body exceeds the configured maximum (1 MiB).

    Hide response attributes Show response attributes object
    • code integer
    • message string
  • 500 application/json

    Internal server error

    Hide response attributes Show response attributes object
    • code integer
    • message string
    • data object | null
POST /alerts/config
curl \
 --request POST 'https://my.nethesis.it/backend/api/alerts/config' \
 --header "Authorization: Bearer $ACCESS_TOKEN" \
 --header "Content-Type: application/json" \
 --data '{
  "enabled": {
    "email": true,
    "webhook": true,
    "telegram": false
  },
  "email_recipients": [
    {
      "address": "noc@msp.example",
      "severities": [],
      "language": "it",
      "format": "html"
    }
  ],
  "webhook_recipients": [
    {
      "name": "central-siem",
      "url": "https://siem.example/api/alerts",
      "severities": []
    }
  ],
  "telegram_recipients": []
}'
Request examples
Owner enables email + webhook globally, sets a NOC recipient on all severities in Italian HTML, plus a SIEM webhook on every severity. Every descendant inherits.
{
  "enabled": {
    "email": true,
    "webhook": true,
    "telegram": false
  },
  "email_recipients": [
    {
      "address": "noc@msp.example",
      "severities": [],
      "language": "it",
      "format": "html"
    }
  ],
  "webhook_recipients": [
    {
      "name": "central-siem",
      "url": "https://siem.example/api/alerts",
      "severities": []
    }
  ],
  "telegram_recipients": []
}
Reseller does NOT touch channel toggles (null = "no opinion"); it just adds a local NOC mailbox in English for critical+warning. Merged with Owner's recipients.
{
  "enabled": {
    "email": null,
    "webhook": null,
    "telegram": null
  },
  "email_recipients": [
    {
      "address": "noc@reseller.example",
      "severities": [
        "critical",
        "warning"
      ],
      "language": "en",
      "format": "html"
    }
  ],
  "webhook_recipients": [],
  "telegram_recipients": []
}
Different recipients can request different bodies. The on-call inbox wants plain text (alerts piped into a ticketing tool); the manager wants HTML in Italian.
{
  "enabled": {
    "email": null,
    "webhook": null,
    "telegram": null
  },
  "email_recipients": [
    {
      "address": "oncall@customer.example",
      "severities": [
        "critical"
      ],
      "language": "en",
      "format": "plain"
    },
    {
      "address": "manager@customer.example",
      "severities": [],
      "language": "it",
      "format": "html"
    }
  ],
  "webhook_recipients": [],
  "telegram_recipients": []
}
The NOC follows everything managed by one reseller (its customers included); the distributor's technician only the systems assigned to the distributor itself, plus one system.
{
  "enabled": {
    "email": true,
    "webhook": null,
    "telegram": null
  },
  "email_recipients": [
    {
      "address": "noc@distributor.example",
      "severities": [
        "critical"
      ],
      "language": "en",
      "format": "html",
      "scope": {
        "managed_organization_ids": [
          "reseller_logto_id"
        ]
      }
    },
    {
      "address": "tech@distributor.example",
      "severities": [],
      "language": "it",
      "format": "html",
      "scope": {
        "assigned_organization_ids": [
          "distributor_logto_id"
        ],
        "system_ids": [
          "1e3f8790-0c66-4727-9139-59a4dc50f41b"
        ]
      }
    }
  ],
  "webhook_recipients": [],
  "telegram_recipients": []
}
Customer adds a Slack webhook scoped to critical. The rendered Alertmanager route puts this webhook only on the critical receiver.
{
  "enabled": {
    "email": null,
    "webhook": null,
    "telegram": null
  },
  "email_recipients": [],
  "webhook_recipients": [
    {
      "name": "ops-slack",
      "url": "https://hooks.slack.com/services/T000/B000/XXX",
      "severities": [
        "critical"
      ]
    }
  ],
  "telegram_recipients": []
}
Single Telegram bot pushing to a channel for every severity (severities=[]). Telegram messages are currently always rendered in English.
{
  "enabled": {
    "email": null,
    "webhook": null,
    "telegram": true
  },
  "email_recipients": [],
  "webhook_recipients": [],
  "telegram_recipients": [
    {
      "bot_token": "123456:ABC-DEF1234ghIkl",
      "chat_id": -1001234567890,
      "severities": []
    }
  ]
}
Saving an empty layer is meaningful: it just records audit metadata (who/when) without contributing recipients or toggles.
{
  "enabled": {
    "email": null,
    "webhook": null,
    "telegram": null
  },
  "email_recipients": [],
  "webhook_recipients": [],
  "telegram_recipients": []
}
Response examples (200)
{
  "code": 200,
  "message": "alerting configuration updated successfully",
  "data": {
    "affected_tenants": 42,
    "propagation": "sync",
    "propagated_to": 42,
    "warnings": [
      "string"
    ]
  }
}
Response examples (400)
{
  "code": 400,
  "message": "validation failed",
  "data": {
    "type": "validation_error",
    "errors": [
      {
        "key": "email_recipients.2.address",
        "message": "invalid_format",
        "value": "wwwwwww"
      }
    ]
  }
}
{
  "code": 400,
  "message": "validation failed",
  "data": {
    "type": "validation_error",
    "errors": [
      {
        "key": "webhook_recipients.0.url",
        "message": "invalid_scheme",
        "value": "asdf"
      }
    ]
  }
}
{
  "code": 400,
  "message": "validation failed",
  "data": {
    "type": "validation_error",
    "errors": [
      {
        "key": "webhook_recipients.0.name",
        "message": "required"
      }
    ]
  }
}
{
  "code": 400,
  "message": "validation failed",
  "data": {
    "type": "validation_error",
    "errors": [
      {
        "key": "email_recipients.0.severities.0",
        "message": "invalid_value",
        "value": "fatal"
      }
    ]
  }
}
Response examples (401)
{
  "code": 401,
  "message": "invalid token",
  "data": {}
}
Response examples (403)
{
  "code": 403,
  "message": "insufficient permissions",
  "data": {}
}
Response examples (413)
{
  "code": 413,
  "message": "request body exceeds the configured maximum"
}
Response examples (500)
{
  "code": 500,
  "message": "internal server error",
  "data": {}
}