{"openapi":"3.1.0","info":{"title":"LaserData Cloud Notifier API","description":"Notification channels, subscriptions, and delivery.\n\nPublic REST API for the LaserData Cloud notifier service.\n\n## Authentication\n\nEvery endpoint accepts either of two auth methods:\n- **API key** (machine / CI / SDK): send in the `ld-api-key` header.\n- **Session cookie** (browser / console): obtained from `POST /account/sign_in` on the control plane.\n\n## Idempotency\n\n`POST`, `PUT`, and `PATCH` requests authenticated by an API key may include an `idempotency-key: <opaque>` header (max 255 characters, UUIDv4 recommended). The server caches the first response for 10 minutes per `(api_key, key)` pair and replays it on retries. A reuse with a *different* request body returns `409 idempotency_error`. Replays carry an `idempotent-replayed: true` header.\n\n## Pagination\n\nList endpoints return a `Paged<T>` body (`page`, `total_pages`, `total_results`, `items`) and a `link` header (RFC 8288).\n\n## Errors\n\nError responses follow RFC 7807 `application/problem+json` with `type`, `title`, `code`, `reason`, `instance`, `status`, `retryable`, and optional `field` / `field_issues`. `retryable` is `true` for 408, 425, 429, 500, 502, 503, 504. `POST /channels/{channel_id}/test` returns `retry-after: 10` (seconds) on 429.\n\n## Response headers\n\n- `ld-request`: request ID. Include it when reporting issues.\n- `link`: pagination relations.\n- `retry-after`: wait hint on 429 / 503.\n- `idempotent-replayed`: set to `true` when the body is a cached idempotent replay.","termsOfService":"https://laserdata.com/terms","contact":{"name":"LaserData Support","url":"https://docs.laserdata.com","email":"support@laserdata.com"},"license":{"name":"Proprietary"},"version":"0.0.93","x-logo":{"altText":"LaserData","href":"https://laserdata.com","url":"https://assets.laserdata.com/laserdata_dark.png"}},"servers":[{"url":"https://api.laserdata.cloud","description":"Production"}],"paths":{"/notifications/types":{"get":{"tags":["Notifications"],"summary":"List notification types","description":"Returns public notification event types that can be subscribed to by tenants, divisions, and users.","operationId":"get_notification_types","responses":{"200":{"description":"Notification type catalog","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationTypeInfo"}}}}}}}},"/tenants/{tenant_id}/channels":{"get":{"tags":["Notification Channels"],"summary":"List tenant notification channels","description":"Returns paged tenant-owned channels. Supports filtering by channel kind.","operationId":"get_tenant_channels","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":1},{"name":"results","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":10},{"name":"channel","in":"query","required":false,"schema":{"oneOf":[{"$ref":"#/components/schemas/NotificationChannelKind"},{"type":"null"}]}}],"responses":{"200":{"description":"Paged channels","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paged_NotificationChannelInfo"}}}},"403":{"description":"Insufficient permissions"}}},"post":{"tags":["Notification Channels"],"summary":"Create tenant notification channel","description":"Creates a tenant-owned notification channel such as Slack, webhook, email, or SMS. Destination validation depends on the chosen channel kind.","operationId":"create_tenant_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}}],"requestBody":{"description":"Channel type, destination, name, optional settings and remarks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannel"}}},"required":true},"responses":{"201":{"description":"Channel created"},"400":{"description":"Invalid channel configuration"},"403":{"description":"Insufficient permissions"},"409":{"description":"Channel already exists or limit reached"}}}},"/tenants/{tenant_id}/channels/{channel_id}":{"get":{"tags":["Notification Channels"],"summary":"Get tenant notification channel","description":"Returns configuration and metadata for one tenant-owned notification channel.","operationId":"get_tenant_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"responses":{"200":{"description":"Channel details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationChannelDetails"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"put":{"tags":["Notification Channels"],"summary":"Update tenant notification channel","description":"Partially updates a tenant-owned notification channel. Omitted fields are left unchanged.","operationId":"update_tenant_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"requestBody":{"description":"Partial channel update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChannel"}}},"required":true},"responses":{"204":{"description":"Channel updated"},"400":{"description":"Invalid channel configuration"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"delete":{"tags":["Notification Channels"],"summary":"Delete tenant notification channel","description":"Deletes a tenant-owned notification channel and all subscriptions attached to it.","operationId":"delete_tenant_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"responses":{"204":{"description":"Channel deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}}},"/tenants/{tenant_id}/channels/{channel_id}/notifications":{"get":{"tags":["Notifications"],"summary":"List tenant channel notifications","description":"Returns notifications already delivered to a tenant-owned channel. Supports pagination and optional filtering by notification message type.","operationId":"get_tenant_notifications","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"page","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":1},{"name":"results","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":10},{"name":"message_type","in":"path","required":true,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paged notifications for tenant channel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paged_NotificationInfo"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Tenant or channel not found"}}}},"/tenants/{tenant_id}/channels/{channel_id}/subscriptions":{"get":{"tags":["Notification Subscriptions"],"summary":"List tenant notification subscriptions","description":"Returns paged subscription entries configured for a tenant-owned channel. Supports pagination and optional message-type filtering.","operationId":"get_tenant_subscriptions","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":1},{"name":"results","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":10},{"name":"message_type","in":"query","required":false,"schema":{"oneOf":[{"$ref":"#/components/schemas/NotificationMessageType"},{"type":"null"}]}}],"responses":{"200":{"description":"Paged subscriptions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paged_NotificationSubscriptionInfo"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"put":{"tags":["Notification Subscriptions"],"summary":"Replace tenant notification subscriptions","description":"Atomically replaces all subscriptions for a tenant-owned channel with the supplied list.","operationId":"set_tenant_subscriptions","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"requestBody":{"description":"Complete subscription set for the channel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSubscriptions"}}},"required":true},"responses":{"204":{"description":"Subscriptions set"},"400":{"description":"Invalid notification types"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"post":{"tags":["Notification Subscriptions"],"summary":"Create tenant notification subscription","description":"Adds one subscription entry for a tenant-owned channel. The subscription can be scoped to selected tenants, divisions, environments, or deployments.","operationId":"create_tenant_subscription","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"requestBody":{"description":"Message types and optional scope filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscription"}}},"required":true},"responses":{"201":{"description":"Subscription created"},"400":{"description":"Invalid notification type"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"},"409":{"description":"Subscription already exists or limit reached"}}}},"/tenants/{tenant_id}/channels/{channel_id}/subscriptions/{subscription_id}":{"get":{"tags":["Notification Subscriptions"],"summary":"Get tenant notification subscription","description":"Returns one subscription entry configured for a tenant-owned channel.","operationId":"get_tenant_subscription","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"subscription_id","in":"path","description":"Subscription identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationSubscriptionId"}}],"responses":{"200":{"description":"Subscription details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationSubscriptionDetails"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Subscription not found"}}},"delete":{"tags":["Notification Subscriptions"],"summary":"Delete tenant notification subscription","description":"Deletes one subscription entry from a tenant-owned channel.","operationId":"delete_tenant_subscription","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"subscription_id","in":"path","description":"Subscription identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationSubscriptionId"}}],"responses":{"204":{"description":"Subscription deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Subscription not found"}}}},"/tenants/{tenant_id}/channels/{channel_id}/test":{"post":{"tags":["Notification Channels"],"summary":"Send test tenant notification","description":"Sends a test message through a tenant-owned notification channel. Rate limited to prevent abuse.","operationId":"test_tenant_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"responses":{"204":{"description":"Test notification sent"},"400":{"description":"Channel disabled or cannot send to private address"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"},"429":{"description":"Test channel rate limited"}}}},"/tenants/{tenant_id}/divisions/{division_id}/channels":{"get":{"tags":["Notification Channels"],"summary":"List division notification channels","description":"Returns paged division-owned channels. Supports filtering by channel kind.","operationId":"get_division_channels","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":1},{"name":"results","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":10},{"name":"channel","in":"query","required":false,"schema":{"oneOf":[{"$ref":"#/components/schemas/NotificationChannelKind"},{"type":"null"}]}}],"responses":{"200":{"description":"Paged channels","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paged_NotificationChannelInfo"}}}},"403":{"description":"Insufficient permissions"}}},"post":{"tags":["Notification Channels"],"summary":"Create division notification channel","description":"Creates a division-owned notification channel using the same payload contract as tenant channels.","operationId":"create_division_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}}],"requestBody":{"description":"Channel type, destination, name, optional settings and remarks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannel"}}},"required":true},"responses":{"201":{"description":"Channel created"},"400":{"description":"Invalid channel configuration"},"403":{"description":"Insufficient permissions"},"409":{"description":"Channel already exists or limit reached"}}}},"/tenants/{tenant_id}/divisions/{division_id}/channels/{channel_id}":{"get":{"tags":["Notification Channels"],"summary":"Get division notification channel","description":"Returns configuration and metadata for one division-owned notification channel.","operationId":"get_division_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"responses":{"200":{"description":"Channel details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationChannelDetails"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"put":{"tags":["Notification Channels"],"summary":"Update division notification channel","description":"Partially updates a division-owned notification channel. Omitted fields are left unchanged.","operationId":"update_division_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"requestBody":{"description":"Partial channel update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChannel"}}},"required":true},"responses":{"204":{"description":"Channel updated"},"400":{"description":"Invalid channel configuration"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"delete":{"tags":["Notification Channels"],"summary":"Delete division notification channel","description":"Deletes a division-owned notification channel and all subscriptions attached to it.","operationId":"delete_division_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"responses":{"204":{"description":"Channel deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}}},"/tenants/{tenant_id}/divisions/{division_id}/channels/{channel_id}/notifications":{"get":{"tags":["Notifications"],"summary":"List division channel notifications","description":"Returns notifications delivered to a division-owned channel. Supports pagination and optional filtering by notification message type.","operationId":"get_division_notifications","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"page","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":1},{"name":"results","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":10},{"name":"message_type","in":"path","required":true,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paged notifications for division channel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paged_NotificationInfo"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Tenant, division, or channel not found"}}}},"/tenants/{tenant_id}/divisions/{division_id}/channels/{channel_id}/subscriptions":{"get":{"tags":["Notification Subscriptions"],"summary":"List division notification subscriptions","description":"Returns paged subscription entries configured for a division-owned channel. Supports pagination and optional message-type filtering.","operationId":"get_division_subscriptions","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":1},{"name":"results","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":10},{"name":"message_type","in":"query","required":false,"schema":{"oneOf":[{"$ref":"#/components/schemas/NotificationMessageType"},{"type":"null"}]}}],"responses":{"200":{"description":"Paged subscriptions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paged_NotificationSubscriptionInfo"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"put":{"tags":["Notification Subscriptions"],"summary":"Replace division notification subscriptions","description":"Atomically replaces all subscriptions for a division-owned channel with the supplied list.","operationId":"set_division_subscriptions","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"requestBody":{"description":"Complete subscription set for the channel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSubscriptions"}}},"required":true},"responses":{"204":{"description":"Subscriptions set"},"400":{"description":"Invalid notification types"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"}}},"post":{"tags":["Notification Subscriptions"],"summary":"Create division notification subscription","description":"Adds one subscription entry for a division-owned channel. The subscription can be scoped to selected tenants, divisions, environments, or deployments.","operationId":"create_division_subscription","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"requestBody":{"description":"Message types and optional scope filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscription"}}},"required":true},"responses":{"201":{"description":"Subscription created"},"400":{"description":"Invalid notification type"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"},"409":{"description":"Subscription already exists or limit reached"}}}},"/tenants/{tenant_id}/divisions/{division_id}/channels/{channel_id}/subscriptions/{subscription_id}":{"get":{"tags":["Notification Subscriptions"],"summary":"Get division notification subscription","description":"Returns one subscription entry configured for a division-owned channel.","operationId":"get_division_subscription","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"subscription_id","in":"path","description":"Subscription identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationSubscriptionId"}}],"responses":{"200":{"description":"Subscription details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationSubscriptionDetails"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Subscription not found"}}},"delete":{"tags":["Notification Subscriptions"],"summary":"Delete division notification subscription","description":"Deletes one subscription entry from a division-owned channel.","operationId":"delete_division_subscription","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"subscription_id","in":"path","description":"Subscription identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationSubscriptionId"}}],"responses":{"204":{"description":"Subscription deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Subscription not found"}}}},"/tenants/{tenant_id}/divisions/{division_id}/channels/{channel_id}/test":{"post":{"tags":["Notification Channels"],"summary":"Send test division notification","description":"Sends a test message through a division-owned notification channel. Rate limited to prevent abuse.","operationId":"test_division_channel","parameters":[{"name":"tenant_id","in":"path","description":"Tenant identifier","required":true,"schema":{"$ref":"#/components/schemas/TenantId"}},{"name":"division_id","in":"path","description":"Division identifier","required":true,"schema":{"$ref":"#/components/schemas/DivisionId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}}],"responses":{"204":{"description":"Test notification sent"},"400":{"description":"Channel disabled or cannot send to private address"},"403":{"description":"Insufficient permissions"},"404":{"description":"Channel not found"},"429":{"description":"Test channel rate limited"}}}},"/users/{user_id}/channels/{channel_id}/notifications":{"get":{"tags":["Notifications"],"summary":"List user channel notifications","description":"Returns notifications delivered to a user-owned notification channel. Supports pagination and optional filtering by notification message type.","operationId":"get_user_notifications","parameters":[{"name":"user_id","in":"path","description":"User identifier","required":true,"schema":{"$ref":"#/components/schemas/UserId"}},{"name":"channel_id","in":"path","description":"Channel identifier","required":true,"schema":{"$ref":"#/components/schemas/NotificationChannelId"}},{"name":"page","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":1},{"name":"results","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64","minimum":1},"example":10},{"name":"message_type","in":"path","required":true,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paged notifications for user channel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paged_NotificationInfo"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"User or channel not found"}}}}},"components":{"schemas":{"ChannelSettings":{"type":"object","properties":{"slack":{"oneOf":[{"$ref":"#/components/schemas/SlackSettings"},{"type":"null"}]},"sms":{"oneOf":[{"$ref":"#/components/schemas/SmsSettings"},{"type":"null"}]},"webhook":{"oneOf":[{"$ref":"#/components/schemas/WebhookSettings"},{"type":"null"}]}}},"CreateChannel":{"type":"object","required":["channel","name","destination"],"properties":{"channel":{"$ref":"#/components/schemas/NotificationChannelKind"},"destination":{"type":"string","example":"https://hooks.example.com/laserdata/ops"},"name":{"$ref":"#/components/schemas/NotificationChannelName"},"remarks":{"type":["string","null"],"example":"Primary production incident sink"},"settings":{"oneOf":[{"$ref":"#/components/schemas/ChannelSettings"},{"type":"null"}]}}},"CreateSubscription":{"type":"object","required":["message_types"],"properties":{"message_types":{"type":"array","items":{"$ref":"#/components/schemas/NotificationMessageType"}},"scope_deployment_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}},"scope_division_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}},"scope_environment_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}},"scope_tenant_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}}}},"DeploymentId":{"type":"integer","format":"int64","example":7261845127892140000,"minimum":0},"DivisionId":{"type":"integer","format":"int64","example":7261844974723780000,"minimum":0},"EnvironmentId":{"type":"integer","format":"int64","example":7261845066528310000,"minimum":0},"ErrorResponse":{"type":"object","required":["title","code","reason"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code (snake_case)."},"field":{"type":["string","null"]},"field_issues":{"type":"array","items":{"$ref":"#/components/schemas/FieldIssue"}},"instance":{"type":["string","null"],"description":"RFC 7807 instance URI identifying the specific occurrence; mirrors the `ld-request` header value."},"reason":{"type":"string","description":"RFC 7807 detail string. Long-form human explanation of this occurrence."},"resolution":{"type":["string","null"],"description":"Concrete guidance an automated client or operator can use to recover."},"retryable":{"type":["boolean","null"],"description":"`true` for retryable conditions (408, 425, 429, 500, 502, 503, 504), `false` otherwise."},"status":{"type":["integer","null"],"format":"int32","description":"Mirror of HTTP status code. Agents can branch on the body without re-reading the response status.","minimum":0},"title":{"type":"string","description":"RFC 7807 short, human-readable title for the error class."},"type":{"type":"string","description":"RFC 7807 type URI identifying the error class. `about:blank` when no type is registered."}}},"FieldIssue":{"type":"object","required":["code","reason"],"properties":{"code":{"type":"string"},"path":{"type":["string","null"]},"reason":{"type":"string"}}},"NotificationChannelDestination":{"type":"string","example":"https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"},"NotificationChannelDetails":{"allOf":[{"$ref":"#/components/schemas/NotificationChannelInfo"},{"type":"object","required":["destination"],"properties":{"destination":{"$ref":"#/components/schemas/NotificationChannelDestination"},"remarks":{"type":["string","null"]},"settings":{"oneOf":[{"$ref":"#/components/schemas/ChannelSettings"},{"type":"null"}]}}}]},"NotificationChannelId":{"type":"integer","format":"int64","example":7261845612345670000,"minimum":0},"NotificationChannelInfo":{"type":"object","required":["id","owner_kind","owner_id","channel","name","enabled","created_at","updated_at"],"properties":{"channel":{"$ref":"#/components/schemas/NotificationChannelKind"},"created_at":{"type":"string","format":"date-time"},"enabled":{"type":"boolean"},"id":{"$ref":"#/components/schemas/NotificationChannelId"},"name":{"$ref":"#/components/schemas/NotificationChannelName"},"owner_id":{"type":"integer","format":"int64","example":7261845022003200001,"minimum":0},"owner_kind":{"$ref":"#/components/schemas/OwnerKind"},"updated_at":{"type":"string","format":"date-time"}},"example":{"channel":"email","created_at":"2026-05-20T10:00:00Z","enabled":true,"id":7261845330120500000,"name":"ops-team-email","owner_id":7261845022003200001,"owner_kind":"tenant","updated_at":"2026-05-20T10:00:00Z"}},"NotificationChannelKind":{"type":"string","enum":["slack","webhook","sms","email"]},"NotificationChannelName":{"type":"string","example":"ops-webhook"},"NotificationId":{"type":"integer","format":"int64","example":7261845612345672000,"minimum":0},"NotificationInfo":{"type":"object","required":["id","message_type","content","created_at"],"properties":{"content":{"type":"string","example":"Deployment ld-prod-01 created successfully"},"created_at":{"type":"string","format":"date-time","description":"Resource creation timestamp (RFC 3339 UTC).","example":"2026-05-20T10:00:00Z"},"deployment_id":{"oneOf":[{"$ref":"#/components/schemas/DeploymentId"},{"type":"null"}]},"division_id":{"oneOf":[{"$ref":"#/components/schemas/DivisionId"},{"type":"null"}]},"environment_id":{"oneOf":[{"$ref":"#/components/schemas/EnvironmentId"},{"type":"null"}]},"id":{"$ref":"#/components/schemas/NotificationId"},"message_type":{"$ref":"#/components/schemas/NotificationMessageType"},"tenant_id":{"oneOf":[{"$ref":"#/components/schemas/TenantId"},{"type":"null"}]}},"example":{"content":"Deployment ld-prod-01 created successfully","created_at":"2026-05-20T10:00:00Z","deployment_id":7261845127892140000,"division_id":7261844974723780000,"environment_id":7261845066528310000,"id":7261845478998350000,"message_type":"deployment_created","tenant_id":7261845022003200001}},"NotificationMessageType":{"type":"string","enum":["deployment_created","deployment_initialized","deployment_upgraded","deployment_deleted","invitation_accepted","invitation_rejected","high_cpu_usage","high_memory_usage","high_disk_usage","node_unreachable","cpu_usage_resolved","memory_usage_resolved","disk_usage_resolved","node_reachable","plane_condition","plane_condition_resolved","certificate_expiring","billing_limit_reached","runtime_degraded","runtime_recovered","invoice_created","invoice_paid","invoice_payment_failed","payment_method_added","payment_method_removed","tenant_created","tenant_deleted","user_created","user_deleted","division_created","division_deleted","environment_created","environment_deleted","cert_refresh_failed","deployment_certificates_rotated","deployment_secrets_rotated","tenant_updated","division_updated","environment_updated","invitation_created","resource_code_requested","deployment_inactive","tenant_join_requested","member_joined","shared_host_drained","shared_host_near_capacity"]},"NotificationSubscriptionDetails":{"allOf":[{"$ref":"#/components/schemas/NotificationSubscriptionInfo"}]},"NotificationSubscriptionId":{"type":"integer","format":"int64","example":7261845612345671000,"minimum":0},"NotificationSubscriptionInfo":{"type":"object","required":["id","channel_id","message_types","created_at","updated_at"],"properties":{"channel_id":{"$ref":"#/components/schemas/NotificationChannelId"},"created_at":{"type":"string","format":"date-time"},"id":{"$ref":"#/components/schemas/NotificationSubscriptionId"},"message_types":{"type":"array","items":{"$ref":"#/components/schemas/NotificationMessageType"}},"scope_deployments":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_DeploymentId"}},"scope_divisions":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_DivisionId"}},"scope_environments":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_EnvironmentId"}},"scope_tenants":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_TenantId"}},"updated_at":{"type":"string","format":"date-time"}},"example":{"channel_id":7261845330120500000,"created_at":"2026-05-20T10:00:00Z","id":7261845404510330000,"message_types":["deployment_created","deployment_initialized"],"scope_environments":[{"id":7261845066528310000,"name":"production"}],"scope_tenants":[{"id":7261845022003200001,"name":"Acme"}],"updated_at":"2026-05-20T10:00:00Z"}},"NotificationTypeInfo":{"type":"object","required":["type","name"],"properties":{"name":{"type":"string","example":"Deployment created"},"type":{"type":"string","example":"deployment_created"}}},"OwnerKind":{"type":"string","enum":["user","tenant","division","system"]},"Paged_NotificationChannelInfo":{"type":"object","required":["total_pages","total_results","page","items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","owner_kind","owner_id","channel","name","enabled","created_at","updated_at"],"properties":{"channel":{"$ref":"#/components/schemas/NotificationChannelKind"},"created_at":{"type":"string","format":"date-time"},"enabled":{"type":"boolean"},"id":{"$ref":"#/components/schemas/NotificationChannelId"},"name":{"$ref":"#/components/schemas/NotificationChannelName"},"owner_id":{"type":"integer","format":"int64","example":7261845022003200001,"minimum":0},"owner_kind":{"$ref":"#/components/schemas/OwnerKind"},"updated_at":{"type":"string","format":"date-time"}},"example":{"channel":"email","created_at":"2026-05-20T10:00:00Z","enabled":true,"id":7261845330120500000,"name":"ops-team-email","owner_id":7261845022003200001,"owner_kind":"tenant","updated_at":"2026-05-20T10:00:00Z"}}},"page":{"type":"integer","format":"int64","example":1,"minimum":1},"total_pages":{"type":"integer","format":"int64","example":4,"minimum":0},"total_results":{"type":"integer","format":"int64","example":137,"minimum":0}}},"Paged_NotificationInfo":{"type":"object","required":["total_pages","total_results","page","items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","message_type","content","created_at"],"properties":{"content":{"type":"string","example":"Deployment ld-prod-01 created successfully"},"created_at":{"type":"string","format":"date-time","description":"Resource creation timestamp (RFC 3339 UTC).","example":"2026-05-20T10:00:00Z"},"deployment_id":{"oneOf":[{"$ref":"#/components/schemas/DeploymentId"},{"type":"null"}]},"division_id":{"oneOf":[{"$ref":"#/components/schemas/DivisionId"},{"type":"null"}]},"environment_id":{"oneOf":[{"$ref":"#/components/schemas/EnvironmentId"},{"type":"null"}]},"id":{"$ref":"#/components/schemas/NotificationId"},"message_type":{"$ref":"#/components/schemas/NotificationMessageType"},"tenant_id":{"oneOf":[{"$ref":"#/components/schemas/TenantId"},{"type":"null"}]}},"example":{"content":"Deployment ld-prod-01 created successfully","created_at":"2026-05-20T10:00:00Z","deployment_id":7261845127892140000,"division_id":7261844974723780000,"environment_id":7261845066528310000,"id":7261845478998350000,"message_type":"deployment_created","tenant_id":7261845022003200001}}},"page":{"type":"integer","format":"int64","example":1,"minimum":1},"total_pages":{"type":"integer","format":"int64","example":4,"minimum":0},"total_results":{"type":"integer","format":"int64","example":137,"minimum":0}}},"Paged_NotificationSubscriptionInfo":{"type":"object","required":["total_pages","total_results","page","items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","channel_id","message_types","created_at","updated_at"],"properties":{"channel_id":{"$ref":"#/components/schemas/NotificationChannelId"},"created_at":{"type":"string","format":"date-time"},"id":{"$ref":"#/components/schemas/NotificationSubscriptionId"},"message_types":{"type":"array","items":{"$ref":"#/components/schemas/NotificationMessageType"}},"scope_deployments":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_DeploymentId"}},"scope_divisions":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_DivisionId"}},"scope_environments":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_EnvironmentId"}},"scope_tenants":{"type":"array","items":{"$ref":"#/components/schemas/ScopeEntry_TenantId"}},"updated_at":{"type":"string","format":"date-time"}},"example":{"channel_id":7261845330120500000,"created_at":"2026-05-20T10:00:00Z","id":7261845404510330000,"message_types":["deployment_created","deployment_initialized"],"scope_environments":[{"id":7261845066528310000,"name":"production"}],"scope_tenants":[{"id":7261845022003200001,"name":"Acme"}],"updated_at":"2026-05-20T10:00:00Z"}}},"page":{"type":"integer","format":"int64","example":1,"minimum":1},"total_pages":{"type":"integer","format":"int64","example":4,"minimum":0},"total_results":{"type":"integer","format":"int64","example":137,"minimum":0}}},"ScopeEntry_DeploymentId":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64","example":7261845127892140000,"minimum":0},"name":{"type":"string","example":"production"}}},"ScopeEntry_DivisionId":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64","example":7261844974723780000,"minimum":0},"name":{"type":"string","example":"production"}}},"ScopeEntry_EnvironmentId":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64","example":7261845066528310000,"minimum":0},"name":{"type":"string","example":"production"}}},"ScopeEntry_TenantId":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64","example":7261845022003200001,"minimum":0},"name":{"type":"string","example":"production"}}},"SetSubscriptions":{"type":"object","required":["subscriptions"],"properties":{"subscriptions":{"type":"array","items":{"$ref":"#/components/schemas/SubscriptionEntry"}}}},"SlackSettings":{"type":"object","properties":{"channel":{"type":["string","null"],"example":"laser-alerts"},"icon_emoji":{"type":["string","null"],"example":":rotating_light:"},"username":{"type":["string","null"],"example":"LaserData Cloud"}}},"SmsSettings":{"type":"object","properties":{"sender_id":{"type":["string","null"],"example":"LaserData"}}},"SubscriptionEntry":{"type":"object","required":["message_types"],"properties":{"message_types":{"type":"array","items":{"$ref":"#/components/schemas/NotificationMessageType"}},"scope_deployment_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}},"scope_division_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}},"scope_environment_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}},"scope_tenant_ids":{"type":["array","null"],"items":{"type":"integer","format":"int64","minimum":0}}}},"TenantId":{"type":"integer","format":"int64","example":7261845022003200001,"minimum":0},"UpdateChannel":{"type":"object","properties":{"destination":{"type":["string","null"],"example":"https://hooks.example.com/laserdata/ops-v2"},"enabled":{"type":["boolean","null"]},"name":{"oneOf":[{"$ref":"#/components/schemas/NotificationChannelName"},{"type":"null"}]},"remarks":{"type":["string","null"],"example":"Migrated to rotated webhook URL"},"settings":{"oneOf":[{"$ref":"#/components/schemas/ChannelSettings"},{"type":"null"}]}}},"UserId":{"type":"integer","format":"int64","example":7261844898910240000,"minimum":0},"WebhookSettings":{"type":"object","properties":{"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"method":{"type":["string","null"],"example":"POST"}},"example":{"headers":{"Authorization":"Bearer secret-token"},"method":"POST"}}},"securitySchemes":{"ld_api_key":{"type":"apiKey","in":"header","name":"ld-api-key","description":"Tenant API key sent in the ld-api-key request header. Tenant-scoped only."},"session_cookie":{"type":"apiKey","in":"cookie","name":"session","description":"Browser session cookie issued by POST /account/sign_in on core."}}},"security":[{"ld_api_key":[]},{"session_cookie":[]}],"tags":[{"name":"Notification Channels","description":"Notification channels (email, slack, webhook)"},{"name":"Notification Subscriptions","description":"Channel subscriptions to notification types"},{"name":"Notifications","description":"Notifications listing"}],"externalDocs":{"url":"https://docs.laserdata.com","description":"LaserData Cloud documentation"}}