Skip to main content

update-customer-notification

dci update-customer-notification [body] [flags]

Partially updates an organization notification with an application/merge-patch+json body (RFC 7396). Omitted fields stay unchanged; nested objects are deep-merged; nested arrays (for example allocations.ids) are replaced when present. When destinations is present it replaces the whole destinations object; the nested emails, slackChannels, and teamsChannels arrays are the full lists. Optional resend fields are cleared with null (for example "settings":\{"costAnomalies":\{"repeat":null\}\}). minSeverity, minExcessCost, and allocations cannot be cleared. Requires the settings (Manage settings) permission and the If-Match header. The Idempotency-Key header is required. The same key, the same body, and the same If-Match replay the stored success. A different body or a different If-Match is 422 idempotency_key_reused. A 5xx response may leave the key reserved, so a retry returns 409 until the original request is released or about 30 minutes pass. dryRun=true does not reserve the key. With dryRun=true the request goes through the same checks as a real update and returns the notification as it would look after the patch, without changing anything. Reads are immediately consistent. After a completed update, a GET of that notification returns the new state.

Pass the request body as name: value arguments or pipe JSON on stdin — see Command structure.

Request​

Content-Type: application/merge-patch+json

FieldTypeRequiredDescription
namestringDisplay name of the notification (max 200 characters). The stored name is trimmed.
destinationsobjectReplacement destinations when present. Replaces the whole object; all three arrays are required and at least one must be non-empty.
destinations.emailsarray of string (email)yesEmail addresses that receive the notification, in the order sent. The array is required; an empty array means email is unused. Omitting the array is rejected. At least one of emails, slackChannels, or teamsChannels must be non-empty. Addresses are stored and returned lowercase. A duplicate or an invalid email is 422.
destinations.slackChannelsarray of stringyesSlack channel ids for Slack channels that receive the notification, in the order sent. The array is required; an empty array means Slack is unused. Omitting the array is rejected. At least one of emails, slackChannels, or teamsChannels must be non-empty. Accepts a public channel, a shared channel, or a private channel the caller is a member of when the DoiT app is also in that channel. A service account cannot add a private channel and receives the same 422 as an id outside the tenant. The caller supplies the id; this API does not look channels up. A duplicate or an id outside the tenant is 422 without saying whether it exists elsewhere. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected. That does not mean delivery still works.
destinations.teamsChannelsarray of stringyesMicrosoft Teams conversation ids for Microsoft Teams channels that receive the notification, in the order sent. The array is required; an empty array means Teams is unused. Omitting the array is rejected. At least one of emails, slackChannels, or teamsChannels must be non-empty. A duplicate or an id outside the tenant is 422 without saying whether it exists elsewhere. A Teams id is also 422 when the tenant has no Teams entitlement. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected, or the tenant loses Teams entitlement. That does not mean delivery still works.
settingsobjectMerge-patch for settings. Omit costAnomalies to leave settings unchanged. Only costAnomalies is accepted.
settings.costAnomaliesobjectMerge-patch for costAnomalies. Omitted fields stay unchanged. repeat may be null to clear all resend controls. minSeverity, minExcessCost, and allocations cannot be cleared — omit them or send a new value.
settings.costAnomalies.minSeveritystringwarning — warning and above. critical — critical only. Clients may send only warning or critical. A write of all is rejected with 422. One of: "warning", "critical".
settings.costAnomalies.minExcessCostobjectMinimum excess cost, as Money. Omit it to leave the current value; it cannot be cleared. currency must be USD; any other currency is rejected with 422. A negative amount is rejected with 422. A fractional amount is rejected with 422 (100.99 is not a whole number of dollars). 100 and 100.00 are both accepted. 0 and 0.00 are accepted. Amounts above 1,000,000,000 whole dollars, and forms such as Inf, exponents, a leading +, or underscores, are rejected with 422.
settings.costAnomalies.minExcessCost.amountstringyesDecimal monetary amount at ISO 4217 minor-unit precision (string).
settings.costAnomalies.minExcessCost.currencystringyesISO 4217 currency code.
settings.costAnomalies.allocationsobjectMerge-patch for allocations. Omit a field to leave it; when ids is present the array replaces the current list. A patch that sets mode: all together with a non-empty ids, or include / exclude together with an empty ids, is rejected with 422. The merged allocations follow the same rule: all carries an empty ids, and include or exclude carries at least one id.
settings.costAnomalies.allocations.modestringall — every allocation with anomaly detection enabled (and unallocated anomalies). include — only the listed ids. exclude — all enabled allocations except the listed ids. all cannot be paired with a non-empty ids. include and exclude cannot be paired with an empty ids. One of: "all", "include", "exclude".
settings.costAnomalies.allocations.idsarray of stringReplacement allocation ids when present, in the order sent. A read returns that same order. A duplicate id is rejected with 422. Empty when mode is all. Non-empty when mode is include or exclude.
settings.costAnomalies.repeatobjectResend controls, or null to clear them all.
settings.costAnomalies.repeat.everyHoursintegerResend until the anomaly is inactive, every N hours (1–24). Send null to clear.
settings.costAnomalies.repeat.whenCostGrowsobjectGrowth-based resend controls. Send null to clear this branch while leaving everyHours. Nested fields omitted — see the raw JSON schema.

Example body (JSON)​

{
"settings": {
"costAnomalies": {
"minSeverity": "critical"
}
}
}
Raw JSON schema
{
"type": "object",
"additionalProperties": false,
"minProperties": 1,
"description": "JSON Merge Patch (RFC 7396) for an organization notification. Omitted\nfields stay unchanged; nested objects are deep-merged; nested arrays\n(for example `allocations.ids`) are replaced when present. When\n`destinations` is present it replaces the whole destinations object.\nSend `null` to clear optional members such as `repeat`,\n`whenCostGrows`, `withinHours`, `percentIncrease`, and `minIncrease`.\n",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "Display name of the notification (max 200 characters). The stored name is trimmed.",
"example": "Anomaly alerts (updated)"
},
"destinations": {
"description": "Replacement destinations when present. Replaces the whole object;\nall three arrays are required and at least one must be non-empty.\n",
"allOf": [
{
"type": "object",
"additionalProperties": false,
"description": "Delivery targets for an organization notification. All three arrays are always present on read. An unused destination is an empty array, never omitted and never `null`. On create, and on a patch that includes `destinations`, all three arrays are required and at least one must be non-empty. An object whose three arrays are all empty is rejected with `422`. Each array is kept in the order sent; a later read returns that same order. Emails are trimmed and stored lowercase. Channel ids are trimmed and otherwise unchanged. A duplicate value inside one array is rejected with `422` (emails compared after lowercase; channel ids compared exactly after trim).",
"required": [
"emails",
"slackChannels",
"teamsChannels"
],
"properties": {
"emails": {
"type": "array",
"minItems": 0,
"description": "Email addresses that receive the notification, in the order sent. The array is required; an empty array means email is unused. Omitting the array is rejected. At least one of `emails`, `slackChannels`, or `teamsChannels` must be non-empty. Addresses are stored and returned lowercase. A duplicate or an invalid email is `422`.",
"items": {
"type": "string",
"format": "email",
"minLength": 1,
"x-doit-pii": true
},
"example": [
]
},
"slackChannels": {
"type": "array",
"minItems": 0,
"description": "Slack channel ids for Slack channels that receive the notification, in the order sent. The array is required; an empty array means Slack is unused. Omitting the array is rejected. At least one of `emails`, `slackChannels`, or `teamsChannels` must be non-empty. Accepts a public channel, a shared channel, or a private channel the caller is a member of when the DoiT app is also in that channel. A service account cannot add a private channel and receives the same `422` as an id outside the tenant. The caller supplies the id; this API does not look channels up. A duplicate or an id outside the tenant is `422` without saying whether it exists elsewhere. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected. That does not mean delivery still works.",
"items": {
"type": "string",
"minLength": 1
},
"example": [
"C0123ABCD"
]
},
"teamsChannels": {
"type": "array",
"minItems": 0,
"description": "Microsoft Teams conversation ids for Microsoft Teams channels that receive the notification, in the order sent. The array is required; an empty array means Teams is unused. Omitting the array is rejected. At least one of `emails`, `slackChannels`, or `teamsChannels` must be non-empty. A duplicate or an id outside the tenant is `422` without saying whether it exists elsewhere. A Teams id is also `422` when the tenant has no Teams entitlement. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected, or the tenant loses Teams entitlement. That does not mean delivery still works.",
"items": {
"type": "string",
"minLength": 1
},
"example": [
]
}
}
}
]
},
"settings": {
"type": "object",
"additionalProperties": false,
"description": "Merge-patch for `settings`. Omit `costAnomalies` to leave settings\nunchanged. Only `costAnomalies` is accepted.\n",
"properties": {
"costAnomalies": {
"type": "object",
"additionalProperties": false,
"description": "Merge-patch for `costAnomalies`. Omitted fields stay unchanged. `repeat` may be `null` to clear all\nresend controls. `minSeverity`, `minExcessCost`, and `allocations` cannot be cleared — omit them or\nsend a new value.\n",
"properties": {
"minSeverity": {
"type": "string",
"enum": [
"warning",
"critical"
],
"x-enumDescriptions": {
"warning": "Warning and above. A missing stored severity (Console \"All severity levels\") is also returned as `warning`.",
"critical": "Critical."
},
"description": "`warning` — warning and above. `critical` — critical only. Clients may send only `warning` or `critical`. A write of `all` is rejected with `422`."
},
"minExcessCost": {
"description": "Minimum excess cost, as Money. Omit it to leave the current value; it cannot be cleared. `currency`\nmust be `USD`; any other currency is rejected with `422`. A negative amount is rejected with `422`.\nA fractional amount is rejected with `422` (`100.99` is not a whole number of dollars). `100` and\n`100.00` are both accepted. `0` and `0.00` are accepted. Amounts above 1,000,000,000 whole dollars,\nand forms such as `Inf`, exponents, a leading `+`, or underscores, are rejected with `422`.\n",
"allOf": [
{
"type": "object",
"required": [
"amount",
"currency"
],
"properties": {
"amount": {
"type": "string",
"pattern": "^-?(0|[1-9]\\d*)(\\.\\d+)?$",
"description": "Decimal monetary amount at ISO 4217 minor-unit precision (string).",
"example": "100.00"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$",
"description": "ISO 4217 currency code.",
"example": "USD"
}
}
}
]
},
"allocations": {
"type": "object",
"additionalProperties": false,
"description": "Merge-patch for `allocations`. Omit a field to leave it; when `ids` is present the array replaces\nthe current list. A patch that sets `mode: all` together with a non-empty `ids`, or `include` /\n`exclude` together with an empty `ids`, is rejected with `422`. The merged allocations follow the same\nrule: `all` carries an empty `ids`, and `include` or `exclude` carries at least one id.\n",
"properties": {
"mode": {
"type": "string",
"enum": [
"all",
"include",
"exclude"
],
"x-enumDescriptions": {
"all": "Include all enabled allocations, including anomalies that are not tied to an allocation. Send an empty `ids`.",
"include": "Include specific allocations. Requires at least one id.",
"exclude": "Exclude specific allocations. Requires at least one id."
},
"description": "`all` — every allocation with anomaly detection enabled (and unallocated anomalies). `include` — only the listed ids. `exclude` — all enabled allocations except the listed ids. `all` cannot be paired with a non-empty `ids`. `include` and `exclude` cannot be paired with an empty `ids`."
},
"ids": {
"type": "array",
"description": "Replacement allocation ids when present, in the order sent. A read returns that same order. A\nduplicate id is rejected with `422`. Empty when `mode` is `all`. Non-empty when `mode` is\n`include` or `exclude`.\n",
"items": {
"type": "string",
"minLength": 1
}
}
}
},
"repeat": {
"description": "Resend controls, or `null` to clear them all.",
"allOf": [
{
"type": "object",
"additionalProperties": false,
"description": "Merge-patch for `repeat`. Nested `whenCostGrows` may be `null` to clear only that branch. Nulling the\nlast remaining control, for example `everyHours: null` when that is the only stored field, leaves\n`repeat: {}`. An empty `repeat` is rejected with `422`. To clear every resend control, send `null` for\n`costAnomalies.repeat` itself.\n",
"properties": {
"everyHours": {
"type": "integer",
"minimum": 1,
"maximum": 24,
"description": "Resend until the anomaly is inactive, every N hours (1–24). Send `null` to clear.\n",
"nullable": true
},
"whenCostGrows": {
"allOf": [
{
"type": "object",
"additionalProperties": false,
"description": "Merge-patch for `whenCostGrows`. Omit a field to leave it; send `null` to clear `match`,\n`percentIncrease`, `minIncrease`, or `withinHours`. After the merge, `percentIncrease` and/or\n`minIncrease` must still be set, and both amounts still require `match`. A merged object with only\n`withinHours`, only `match`, or neither amount is rejected with `422`.\n",
"properties": {
"match": {
"type": "string",
"enum": [
"or",
"and",
null
],
"x-enumDescriptions": {
"or": "Resend when either the percent increase or the dollar increase is reached.",
"and": "Resend only when both are reached."
},
"description": "How to combine percent and dollar growth when both are set. Send `null` to clear.",
"nullable": true
},
"percentIncrease": {
"type": "integer",
"minimum": 1,
"description": "Minimum percent cost increase that triggers a resend. Must be greater than 0. Send `null` to clear.\n",
"nullable": true
},
"minIncrease": {
"description": "Minimum cost growth, as Money. Must be a positive whole number of dollars. Send `null` to clear.\n`currency` must be `USD`; any other currency is rejected with `422`. `0`, `0.00`, and a negative\namount are rejected with `422`. A fractional amount is rejected with `422` (`150.99` is not a whole\nnumber of dollars). `150` and `150.00` are both accepted. Amounts above 1,000,000,000 whole dollars,\nand forms such as `Inf`, exponents, a leading `+`, or underscores, are rejected with `422`.\n",
"allOf": [
{
"type": "object",
"required": [
"amount",
"currency"
],
"properties": {
"amount": {
"type": "string",
"pattern": "^-?(0|[1-9]\\d*)(\\.\\d+)?$",
"description": "Decimal monetary amount at ISO 4217 minor-unit precision (string).",
"example": "100.00"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$",
"description": "ISO 4217 currency code.",
"example": "USD"
}
}
}
],
"nullable": true
},
"withinHours": {
"type": "integer",
"minimum": 1,
"maximum": 24,
"description": "Optional window in hours (1–24). Send `null` to clear.",
"nullable": true
}
}
}
],
"description": "Growth-based resend controls. Send `null` to clear this branch while leaving `everyHours`.\n",
"nullable": true
}
}
}
],
"nullable": true
}
}
}
}
}
},
"example": {
"settings": {
"costAnomalies": {
"minSeverity": "critical"
}
}
}
}

Flags​

FlagTypeDefaultExampleDescription
--dry-runbooleanfalseIf true, validates the request and returns the would-be result without applying it. The response then carries the X-Dry-Run header.

Every command also accepts the CLI-wide flags for output shaping — see Output formats and Table output options.

Output​

OK - Notification updated. The updated example is a completed patch: updateTime and etag change. The dryRun example is the preview when dryRun=true: the merged settings, with the current updateTime and etag left unchanged.

By default dci renders the result as a table. Use --output json to get the full structure described below — see Output formats.

FieldTypeDescription
idstringServer-assigned notification id. null only on a dry-run create.
namestringDisplay name of the notification (max 200 characters). The stored name is trimmed.
createTimestring (date-time)When the config was created. null only on a dry-run create.
updateTimestring (date-time)When the config was last changed. null only on a dry-run create.
etagstringCurrent strong ETag as bare SHA-256 hex. The ETag response header and If-Match wrap this value in double quotes. Send that quoted form unchanged on update or delete. null only on a dry-run create.
destinationsobjectDelivery targets. Always includes emails, slackChannels, and teamsChannels. Unused lists are empty arrays.
destinations.emailsarray of string (email)Email addresses that receive the notification, in the order sent. The array is required; an empty array means email is unused. Omitting the array is rejected. At least one of emails, slackChannels, or teamsChannels must be non-empty. Addresses are stored and returned lowercase. A duplicate or an invalid email is 422.
destinations.slackChannelsarray of stringSlack channel ids for Slack channels that receive the notification, in the order sent. The array is required; an empty array means Slack is unused. Omitting the array is rejected. At least one of emails, slackChannels, or teamsChannels must be non-empty. Accepts a public channel, a shared channel, or a private channel the caller is a member of when the DoiT app is also in that channel. A service account cannot add a private channel and receives the same 422 as an id outside the tenant. The caller supplies the id; this API does not look channels up. A duplicate or an id outside the tenant is 422 without saying whether it exists elsewhere. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected. That does not mean delivery still works.
destinations.teamsChannelsarray of stringMicrosoft Teams conversation ids for Microsoft Teams channels that receive the notification, in the order sent. The array is required; an empty array means Teams is unused. Omitting the array is rejected. At least one of emails, slackChannels, or teamsChannels must be non-empty. A duplicate or an id outside the tenant is 422 without saying whether it exists elsewhere. A Teams id is also 422 when the tenant has no Teams entitlement. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected, or the tenant loses Teams entitlement. That does not mean delivery still works.
settingsobjectSubscribed notification settings. Only costAnomalies is accepted; any other notification type is rejected.
settings.costAnomaliesobjectCost-anomaly notification settings: minimum severity, excess-cost threshold, allocation scope, and optional resend controls.
settings.costAnomalies.minSeveritystringwarning — warning and above. critical — critical only. There is no information or all value; a write of all is rejected with 422. Clients may send only warning or critical. Responses return only warning or critical. A missing or empty stored severity (console "All severity levels") is returned as warning. critical is stored and returned as critical. One of: "warning", "critical".
settings.costAnomalies.minExcessCostobjectMinimum excess cost, as Money. Notify when excess cost is above this amount, not total spend. 100.00 USD means $100. currency must be USD; any other currency is rejected with 422. A negative amount is rejected with 422. A fractional amount is rejected with 422 (100.99 is not a whole number of dollars). 100 and 100.00 are both accepted. 0 and 0.00 are accepted. Amounts above 1,000,000,000 whole dollars, and forms such as Inf, exponents, a leading +, or underscores, are rejected with 422. Responses return the amount as "100.00".
settings.costAnomalies.minExcessCost.amountstringDecimal monetary amount at ISO 4217 minor-unit precision (string).
settings.costAnomalies.minExcessCost.currencystringISO 4217 currency code.
settings.costAnomalies.allocationsobjectAllocation scope for cost-anomaly notifications. ids are allocation ids from GET /analytics/v1/allocations. An id outside the caller's tenant is rejected with 422 without saying whether it exists elsewhere. mode: all means every allocation with anomaly detection enabled, including anomalies that are not tied to an allocation, and it carries an empty ids. include and exclude require at least one id. mode: all with a non-empty ids, and include or exclude with an empty ids, are rejected with 422. ids are an ordered list: the server stores and returns them in the order sent, and it does not sort or drop entries. A duplicate id is rejected with 422.
settings.costAnomalies.allocations.modestringall — every allocation with anomaly detection enabled (and unallocated anomalies). include — only the listed ids. exclude — all enabled allocations except the listed ids. all cannot be sent with a non-empty ids. include and exclude cannot be sent with an empty ids. One of: "all", "include", "exclude".
settings.costAnomalies.allocations.idsarray of stringAllocation ids, in the order sent. A read returns that same order. A duplicate id is rejected with 422. Empty when mode is all. Non-empty when mode is include or exclude.
settings.costAnomalies.repeatobjectResend controls for an active cost anomaly. Omit the whole repeat object when neither control is set. An empty object is rejected with 422.
settings.costAnomalies.repeat.everyHoursintegerResend until the anomaly is inactive, every N hours (1–24).
settings.costAnomalies.repeat.whenCostGrowsobjectResend when the anomaly's cost grows. At least one of percentIncrease or minIncrease is required. An object with only withinHours, only match, or neither amount is rejected with 422. - both percentIncrease and minIncrease present → match is required (or or and) - exactly one of percentIncrease or minIncrease present → omit match (percentage-only or value-only) - neither amount present → rejected with 422 percentIncrease is an integer percent (10 means 10 percent) and must be at least 1. Omit withinHours when the time window is off. Nested fields omitted — see the raw JSON schema.

Example response (--output json)​

{
"id": "notif_01HX9P2KQVJ8Z3M4T5N6V7W8Y9",
"name": "Anomaly alerts",
"createTime": "2026-10-01T08:00:00Z",
"updateTime": "2026-10-12T09:30:00Z",
"etag": "9b2e4d6f8a0c1e3b5d7f9a1c3e5b7d9f1a3c5e7a9b1d3f5a7c9e1b3d5f7a9c1e",
"destinations": {
"emails": [
],
"slackChannels": [
"C0123ABCD"
],
"teamsChannels": []
},
"settings": {
"costAnomalies": {
"minSeverity": "critical",
"minExcessCost": {
"amount": "100.00",
"currency": "USD"
},
"allocations": {
"mode": "include",
"ids": [
"alloc_abc",
"alloc_def"
]
}
}
}
}
Raw JSON schema
{
"type": "object",
"additionalProperties": false,
"description": "Organization-wide notification config. Create and read return the full\nresource with the same field names. Update and delete require\n`If-Match` against the strong `etag`.\n",
"required": [
"id",
"name",
"createTime",
"updateTime",
"etag",
"destinations",
"settings"
],
"properties": {
"id": {
"type": "string",
"readOnly": true,
"x-terraform-computed": true,
"description": "Server-assigned notification id. `null` only on a dry-run create.",
"nullable": true,
"example": "notif_01HX9P2KQVJ8Z3M4T5N6V7W8Y9"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "Display name of the notification (max 200 characters). The stored name is trimmed.",
"example": "Anomaly alerts"
},
"createTime": {
"type": "string",
"format": "date-time",
"readOnly": true,
"x-terraform-computed": true,
"description": "When the config was created. `null` only on a dry-run create.",
"nullable": true,
"example": "2026-10-01T08:00:00Z"
},
"updateTime": {
"type": "string",
"format": "date-time",
"readOnly": true,
"x-terraform-computed": true,
"description": "When the config was last changed. `null` only on a dry-run create.",
"nullable": true,
"example": "2026-10-01T08:00:00Z"
},
"etag": {
"type": "string",
"readOnly": true,
"x-terraform-computed": true,
"description": "Current strong ETag as bare SHA-256 hex. The `ETag` response header\nand `If-Match` wrap this value in double quotes. Send that quoted\nform unchanged on update or delete. `null` only on a dry-run create.\n",
"nullable": true,
"example": "3f7a1c9e2b4d6f8a0c1e3a5b7d9f1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e"
},
"destinations": {
"description": "Delivery targets. Always includes `emails`, `slackChannels`, and\n`teamsChannels`. Unused lists are empty arrays.\n",
"allOf": [
{
"type": "object",
"additionalProperties": false,
"description": "Delivery targets for an organization notification. All three arrays are always present on read. An unused destination is an empty array, never omitted and never `null`. On create, and on a patch that includes `destinations`, all three arrays are required and at least one must be non-empty. An object whose three arrays are all empty is rejected with `422`. Each array is kept in the order sent; a later read returns that same order. Emails are trimmed and stored lowercase. Channel ids are trimmed and otherwise unchanged. A duplicate value inside one array is rejected with `422` (emails compared after lowercase; channel ids compared exactly after trim).",
"required": [
"emails",
"slackChannels",
"teamsChannels"
],
"properties": {
"emails": {
"type": "array",
"minItems": 0,
"description": "Email addresses that receive the notification, in the order sent. The array is required; an empty array means email is unused. Omitting the array is rejected. At least one of `emails`, `slackChannels`, or `teamsChannels` must be non-empty. Addresses are stored and returned lowercase. A duplicate or an invalid email is `422`.",
"items": {
"type": "string",
"format": "email",
"minLength": 1,
"x-doit-pii": true
},
"example": [
]
},
"slackChannels": {
"type": "array",
"minItems": 0,
"description": "Slack channel ids for Slack channels that receive the notification, in the order sent. The array is required; an empty array means Slack is unused. Omitting the array is rejected. At least one of `emails`, `slackChannels`, or `teamsChannels` must be non-empty. Accepts a public channel, a shared channel, or a private channel the caller is a member of when the DoiT app is also in that channel. A service account cannot add a private channel and receives the same `422` as an id outside the tenant. The caller supplies the id; this API does not look channels up. A duplicate or an id outside the tenant is `422` without saying whether it exists elsewhere. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected. That does not mean delivery still works.",
"items": {
"type": "string",
"minLength": 1
},
"example": [
"C0123ABCD"
]
},
"teamsChannels": {
"type": "array",
"minItems": 0,
"description": "Microsoft Teams conversation ids for Microsoft Teams channels that receive the notification, in the order sent. The array is required; an empty array means Teams is unused. Omitting the array is rejected. At least one of `emails`, `slackChannels`, or `teamsChannels` must be non-empty. A duplicate or an id outside the tenant is `422` without saying whether it exists elsewhere. A Teams id is also `422` when the tenant has no Teams entitlement. After a channel is accepted, get and list keep returning that id even if the channel is later deleted, archived, or disconnected, or the tenant loses Teams entitlement. That does not mean delivery still works.",
"items": {
"type": "string",
"minLength": 1
},
"example": [
]
}
}
}
]
},
"settings": {
"description": "Subscribed notification settings. Only `costAnomalies` is accepted; any other notification type is rejected.",
"allOf": [
{
"type": "object",
"additionalProperties": false,
"description": "Subscribed notification settings. Only `costAnomalies` is accepted.\nSettings for any other type are rejected; omitting `costAnomalies` is\nrejected.\n",
"required": [
"costAnomalies"
],
"properties": {
"costAnomalies": {
"type": "object",
"additionalProperties": false,
"description": "Cost-anomaly notification settings: minimum severity, excess-cost threshold, allocation scope, and\noptional resend controls.\n",
"required": [
"minSeverity",
"minExcessCost",
"allocations"
],
"properties": {
"minSeverity": {
"type": "string",
"enum": [
"warning",
"critical"
],
"x-enumDescriptions": {
"warning": "Warning and above. A missing stored severity (Console \"All severity levels\") is also returned as `warning`.",
"critical": "Critical."
},
"description": "`warning` — warning and above. `critical` — critical only. There is no `information` or `all` value; a write of `all` is rejected with `422`. Clients may send only `warning` or `critical`. Responses return only `warning` or `critical`. A missing or empty stored severity (console \"All severity levels\") is returned as `warning`. `critical` is stored and returned as `critical`.",
"example": "warning"
},
"minExcessCost": {
"description": "Minimum excess cost, as Money. Notify when excess cost is above this amount, not total spend.\n`100.00` USD means $100. `currency` must be `USD`; any other currency is rejected with `422`. A\nnegative amount is rejected with `422`. A fractional amount is rejected with `422` (`100.99` is not a\nwhole number of dollars). `100` and `100.00` are both accepted. `0` and `0.00` are accepted. Amounts\nabove 1,000,000,000 whole dollars, and forms such as `Inf`, exponents, a leading `+`, or underscores,\nare rejected with `422`. Responses return the amount as `\"100.00\"`.\n",
"allOf": [
{
"type": "object",
"required": [
"amount",
"currency"
],
"properties": {
"amount": {
"type": "string",
"pattern": "^-?(0|[1-9]\\d*)(\\.\\d+)?$",
"description": "Decimal monetary amount at ISO 4217 minor-unit precision (string).",
"example": "100.00"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$",
"description": "ISO 4217 currency code.",
"example": "USD"
}
}
}
]
},
"allocations": {
"type": "object",
"additionalProperties": false,
"description": "Allocation scope for cost-anomaly notifications. `ids` are allocation ids from `GET\n/analytics/v1/allocations`. An id outside the caller's tenant is rejected with `422` without saying\nwhether it exists elsewhere.\n\n`mode: all` means every allocation with anomaly detection enabled, including anomalies that are not\ntied to an allocation, and it carries an empty `ids`. `include` and `exclude` require at least one\nid. `mode: all` with a non-empty `ids`, and `include` or `exclude` with an empty `ids`, are rejected\nwith `422`. `ids` are an ordered list: the server stores and returns them in the order sent, and it does\nnot sort or drop entries. A duplicate id is rejected with `422`.\n",
"required": [
"mode",
"ids"
],
"properties": {
"mode": {
"type": "string",
"enum": [
"all",
"include",
"exclude"
],
"x-enumDescriptions": {
"all": "Include all enabled allocations, including anomalies that are not tied to an allocation. Send an empty `ids`.",
"include": "Include specific allocations. Requires at least one id.",
"exclude": "Exclude specific allocations. Requires at least one id."
},
"description": "`all` — every allocation with anomaly detection enabled (and unallocated anomalies). `include` — only the listed ids. `exclude` — all enabled allocations except the listed ids. `all` cannot be sent with a non-empty `ids`. `include` and `exclude` cannot be sent with an empty `ids`.",
"example": "include"
},
"ids": {
"type": "array",
"description": "Allocation ids, in the order sent. A read returns that same order. A duplicate id is rejected\nwith `422`. Empty when `mode` is `all`. Non-empty when `mode` is `include` or `exclude`.\n",
"items": {
"type": "string",
"minLength": 1
},
"example": [
"alloc_abc",
"alloc_def"
]
}
}
},
"repeat": {
"type": "object",
"additionalProperties": false,
"minProperties": 1,
"description": "Resend controls for an active cost anomaly. Omit the whole `repeat` object when neither control is\nset. An empty object is rejected with `422`.\n",
"properties": {
"everyHours": {
"type": "integer",
"minimum": 1,
"maximum": 24,
"description": "Resend until the anomaly is inactive, every N hours (1–24).\n",
"example": 24
},
"whenCostGrows": {
"type": "object",
"additionalProperties": false,
"minProperties": 1,
"description": "Resend when the anomaly's cost grows. At least one of `percentIncrease` or `minIncrease` is required.\nAn object with only `withinHours`, only `match`, or neither amount is rejected with `422`.\n\n- both `percentIncrease` and `minIncrease` present → `match` is\n required (`or` or `and`)\n- exactly one of `percentIncrease` or `minIncrease` present → omit\n `match` (percentage-only or value-only)\n- neither amount present → rejected with `422`\n\n`percentIncrease` is an integer percent (`10` means 10 percent) and must be at least 1. Omit\n`withinHours` when the time window is off.",
"properties": {
"match": {
"type": "string",
"enum": [
"or",
"and"
],
"x-enumDescriptions": {
"or": "Resend when either the percent increase or the dollar increase is reached.",
"and": "Resend only when both are reached."
},
"description": "How to combine percent and dollar growth when both are set. Required when both amounts are present; omit when only one amount is present.",
"example": "or"
},
"percentIncrease": {
"type": "integer",
"minimum": 1,
"description": "Minimum percent cost increase that triggers a resend. `10` means 10 percent. Must be greater than 0.\n",
"example": 10
},
"minIncrease": {
"description": "Minimum cost growth that triggers a resend, as Money. Must be a positive whole number of dollars.\n`150.00` USD means $150. `currency` must be `USD`; any other currency is rejected with `422`. `0`,\n`0.00`, and a negative amount are rejected with `422`. A fractional amount is rejected with `422`\n(`150.99` is not a whole number of dollars). `150` and `150.00` are both accepted. Amounts above\n1,000,000,000 whole dollars, and forms such as `Inf`, exponents, a leading `+`, or underscores, are\nrejected with `422`. Responses return the amount as `\"150.00\"`.\n",
"allOf": [
{
"type": "object",
"required": [
"amount",
"currency"
],
"properties": {
"amount": {
"type": "string",
"pattern": "^-?(0|[1-9]\\d*)(\\.\\d+)?$",
"description": "Decimal monetary amount at ISO 4217 minor-unit precision (string).",
"example": "100.00"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$",
"description": "ISO 4217 currency code.",
"example": "USD"
}
}
}
]
},
"withinHours": {
"type": "integer",
"minimum": 1,
"maximum": 24,
"description": "Optional window in hours for the growth check (1–24).",
"example": 6
}
}
}
}
}
}
}
}
}
]
}
}
}

Errors​

On failure, dci prints a single error message — with a hint when one is available — and exits with a typed code your scripts can branch on. See Errors and exit codes for the full contract.

HTTP status to exit code mapping
HTTP statusExit codeError codeMeaning
400, 42230VALIDATION_ERRORThe arguments or request body were rejected. Review the command's flags and payload.
40110AUTHENTICATION_FAILEDNot signed in, or the API token is invalid. Run dci login or check DCI_API_KEY.
40311PERMISSION_DENIEDThe DoiT user or the active customer context does not have access.
40420RESOURCE_NOT_FOUNDThe requested resource does not exist. Check the identifier argument.
40921RESOURCE_CONFLICTThe operation conflicts with the resource's current state.
412, 415, 4281API_ERRORThe request failed; the printed error message has details.
50040API_SERVER_ERRORThe API failed to process the request. Retryable; contact DoiT support if it persists.

Aliases: updatecustomernotification