{"openapi":"3.1.0","info":{"title":"Chainitor API","version":"1.0.0","description":"Chainitor blockchain monitoring API. Manage monitors, alerts, notification channels, and more. Authenticate with a Bearer API key (`cm_...`) or a browser session cookie.","contact":{"name":"Chainitor Support","url":"https://chainitor.com/contact/","email":"hello@chainitor.com"}},"externalDocs":{"description":"API reference","url":"https://chainitor.com/docs/api/"},"servers":[{"url":"/api/v1","description":"V1 API"}],"security":[{"bearerAuth":[]}],"paths":{"/auth/me":{"get":{"operationId":"getMe","summary":"Get current identity","description":"Returns the authenticated user's profile. Use this to verify your API key works and check which organization you're scoped to.","tags":["Auth"],"responses":{"200":{"description":"Current user identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"},"example":{"data":{"id":"uuid","email":"user@example.com","name":"Alice","currentOrganizationId":"uuid","organizations":[{"id":"uuid","name":"My Org","role":"owner"}],"subscriptionStatus":"active","authMethod":"api_key"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/monitors":{"get":{"operationId":"listMonitors","summary":"List all monitors for the organization","description":"Returns all monitors in the current organization. Supports filtering by group, chain, status, and type.","tags":["Monitors"],"parameters":[{"name":"group","in":"query","schema":{"type":"string"},"description":"Filter by monitor group name"},{"name":"chain","in":"query","schema":{"type":"string","enum":["ethereum","ethereum-sepolia","polygon","polygon-amoy","bsc","bsc-testnet","arbitrum","arbitrum-sepolia","optimism","optimism-sepolia","base","base-sepolia","robinhood","local"]},"description":"Filter by blockchain"},{"name":"status","in":"query","schema":{"type":"string","enum":["enabled","disabled"]},"description":"Filter by enabled/disabled"},{"name":"type","in":"query","schema":{"type":"string","enum":["balance","transaction_count","erc20_balance","event_emitted","failed_transaction","transaction_value","function_call","safe_threshold_changed","safe_owner_added","safe_owner_removed","safe_guard_changed","safe_module_enabled","safe_module_disabled","safe_pending_config_change","safe_activity"]},"description":"Filter by monitor type"}],"responses":{"200":{"description":"List of monitors","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Monitor"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"createMonitor","summary":"Create a new monitor","description":"Creates a new blockchain monitor. The `config` object shape depends on the `type` field. Refer to the config schemas for each monitor type. Returns 403 when the monitor limit is reached, or when the monitor type reads every block (`function_call`, `failed_transaction`, `transaction_value`) and the chain is a fast one (Arbitrum, Arbitrum Sepolia, Robinhood), which requires the Pro plan (plans below Pro are refused).","tags":["Monitors"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"},"example":{"name":"ETH Balance Watch","type":"balance","chain":"ethereum","intervalMinutes":5,"config":{"address":"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18","threshold":"1.0","comparisonType":"less_than"},"channelIds":["uuid-of-channel"]}}}},"responses":{"201":{"description":"Monitor created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Monitor"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Not allowed: monitor limit reached, or a block-scan monitor type (`function_call`, `failed_transaction`, `transaction_value`) on a plan below Pro (block-scan types are Pro-only on every chain). The message names the monitor type and chain.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"FORBIDDEN","message":"Function Call monitors on Arbitrum One require the Pro plan: they read every block, and this chain produces many."}}}}}}}},"/monitors/{id}":{"get":{"operationId":"getMonitor","summary":"Get a single monitor","description":"Returns a monitor by ID, including its config, channels, and recent alerts.","tags":["Monitors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Monitor details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Monitor"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateMonitor","summary":"Update a monitor","description":"Partially updates a monitor. Only included fields are changed.","tags":["Monitors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMonitorRequest"},"example":{"name":"Updated Name","intervalMinutes":10}}}},"responses":{"200":{"description":"Updated monitor","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Monitor"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteMonitor","summary":"Delete a monitor","description":"Permanently deletes a monitor and all its associated alerts and execution history.","tags":["Monitors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Monitor deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/monitors/{id}/execute":{"post":{"operationId":"executeMonitor","summary":"Trigger immediate monitor execution","description":"Sends a request to the monitor service to execute this monitor immediately, outside its normal schedule.","tags":["Monitors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Execution result"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/monitors/{id}/enable":{"post":{"operationId":"enableMonitor","summary":"Enable a monitor","description":"Re-enables a disabled monitor. Its next run is scheduled based on its interval. Safe monitors are rejected with 400 if the organization has no Safe API key or the monitor no longer fits its Safe API quota. Block-scan monitors (`function_call`, `failed_transaction`, `transaction_value`) cannot be re-enabled on plans below Pro and are rejected with 403; monitors that are already enabled are left alone.","tags":["Monitors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Monitor enabled"},"400":{"$ref":"#/components/responses/ValidationError"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/monitors/{id}/disable":{"post":{"operationId":"disableMonitor","summary":"Disable a monitor","description":"Disables a monitor so it stops executing on its schedule.","tags":["Monitors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Monitor disabled"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/monitors/{id}/executions":{"get":{"operationId":"listMonitorExecutions","summary":"Get execution history for a monitor","description":"Returns historical execution data and performance statistics for a monitor.","tags":["Monitors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"days","in":"query","schema":{"type":"integer","default":7},"description":"Number of days of history"},{"name":"limit","in":"query","schema":{"type":"integer","default":100},"description":"Maximum number of executions"}],"responses":{"200":{"description":"Execution history and stats"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/alerts":{"get":{"operationId":"listAlerts","summary":"List all alerts for the organization","description":"Returns alerts across all monitors in the organization. Filter by monitor_id to see alerts for a specific monitor, or by type. `meta.pagination.stats` carries org-wide counts per alert type, independent of the filters.","tags":["Alerts"],"parameters":[{"name":"monitor_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filter by monitor ID"},{"name":"status","in":"query","schema":{"type":"string"},"description":"Filter by alert status"},{"name":"type","in":"query","schema":{"type":"string","enum":["critical","recovery","info"]},"description":"Filter by alert type. An unknown value returns 400. `critical`: a breach. `recovery`: the monitor is healthy again; it closes the preceding `critical`. `info` (added October 2026): an event worth knowing that is neither, for example a Safe proposal or signature; it never closes anything. Integrations that switch on `critical`/`recovery` must handle or ignore `info`."},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Page number"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100},"description":"Items per page"}],"responses":{"200":{"description":"Paginated list of alerts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Alert"}},"meta":{"type":"object","properties":{"pagination":{"allOf":[{"$ref":"#/components/schemas/Pagination"},{"type":"object","properties":{"stats":{"$ref":"#/components/schemas/AlertStats"}}}]}}}}}}}}}}},"/alerts/{id}":{"get":{"operationId":"getAlert","summary":"Get a single alert","tags":["Alerts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Alert details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Alert"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/alerts/archive":{"post":{"operationId":"archiveAlerts","summary":"Bulk archive (delete) alerts","description":"Permanently removes the specified alerts. Only alerts belonging to the current organization are affected.","tags":["Alerts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"}}}},"example":{"ids":["uuid-1","uuid-2"]}}}},"responses":{"200":{"description":"Number of archived alerts"}}}},"/channels":{"get":{"operationId":"listChannels","summary":"List notification channels","tags":["Channels"],"responses":{"200":{"description":"List of channels","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}}}}}}}},"post":{"operationId":"createChannel","summary":"Create a notification channel","description":"Creates a new notification channel. The `config` shape depends on the `type` field.","tags":["Channels"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannelRequest"},"example":{"name":"Ops Slack","type":"slack","config":{"webhook_url":"https://hooks.slack.com/services/...","channel":"#alerts"}}}}},"responses":{"201":{"description":"Channel created"},"400":{"$ref":"#/components/responses/ValidationError"}}}},"/channels/{id}":{"get":{"operationId":"getChannel","summary":"Get a single channel","tags":["Channels"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Channel details"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateChannel","summary":"Update a notification channel","tags":["Channels"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChannelRequest"}}}},"responses":{"200":{"description":"Updated channel"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteChannel","summary":"Delete a notification channel","tags":["Channels"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Channel deleted"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/channels/{id}/test":{"post":{"operationId":"testChannel","summary":"Send a test notification","description":"Sends a test message through the channel to verify it's configured correctly.","tags":["Channels"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Test notification sent"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/channels/{id}/set-default":{"post":{"operationId":"setDefaultChannel","summary":"Set channel as organization default","tags":["Channels"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Channel set as default"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/address-book":{"get":{"operationId":"listAddresses","summary":"List saved addresses","tags":["Address Book"],"parameters":[{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by label or address"}],"responses":{"200":{"description":"List of addresses","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AddressBookEntry"}}}}}}}}},"post":{"operationId":"createAddress","summary":"Create an address book entry","tags":["Address Book"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAddressRequest"},"example":{"label":"Treasury","address":"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"}}}},"responses":{"201":{"description":"Address created"},"409":{"description":"Label already exists"}}}},"/address-book/{id}":{"get":{"operationId":"getAddress","summary":"Get a single address book entry","tags":["Address Book"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Address details"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateAddress","summary":"Update an address book entry","tags":["Address Book"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAddressRequest"}}}},"responses":{"200":{"description":"Updated address"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteAddress","summary":"Delete an address book entry","tags":["Address Book"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Address deleted"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/organization":{"get":{"operationId":"getOrganization","summary":"Get current organization","description":"Returns the organization the API key is scoped to.","tags":["Organization"],"responses":{"200":{"description":"Organization details"}}}},"/organization/integrations":{"get":{"operationId":"getIntegrations","summary":"Get integration settings","description":"Returns integration configuration (e.g., Safe API key presence). Secrets are never exposed.","tags":["Organization"],"responses":{"200":{"description":"Integration settings (redacted)"}}},"patch":{"operationId":"updateIntegrations","summary":"Update integration settings","description":"A Safe API key is checked with Safe before it is saved. A key Safe does not recognise is refused with 400 and not saved. If Safe cannot be reached, the key is saved unverified.","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated integration settings"},"400":{"$ref":"#/components/responses/ValidationError"}}}},"/organization/groups":{"get":{"operationId":"listGroups","summary":"List monitor groups","tags":["Organization"],"responses":{"200":{"description":"List of group names"}}},"post":{"operationId":"createGroup","summary":"Create a monitor group","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["groupName"],"properties":{"groupName":{"type":"string"}}}}}},"responses":{"201":{"description":"Group created"},"409":{"description":"Group already exists"}}}},"/organization/groups/{name}":{"delete":{"operationId":"deleteGroup","summary":"Delete a monitor group","tags":["Organization"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Group deleted"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api-keys":{"get":{"operationId":"listApiKeys","summary":"List API keys for the organization","description":"Returns all API keys. The key hash is never returned — only the prefix for identification.","tags":["API Keys"],"responses":{"200":{"description":"List of API keys","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}}}},"post":{"operationId":"createApiKey","summary":"Create a new API key","description":"Creates a new API key. The raw key is returned exactly once in the response — store it securely, as it cannot be retrieved later.","tags":["API Keys"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"},"example":{"name":"CI Pipeline"}}}},"responses":{"201":{"description":"API key created — includes the raw key (shown only once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"},"example":{"data":{"id":"uuid","name":"CI Pipeline","key":"cm_a1b2c3d4e5f6...","keyPrefix":"cm_a1b2c3d","isActive":true,"createdAt":"2026-02-27T00:00:00.000Z"}}}}}}}},"/api-keys/{id}":{"patch":{"operationId":"updateApiKey","summary":"Update an API key name","tags":["API Keys"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":100}}}}}},"responses":{"200":{"description":"Updated API key"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"revokeApiKey","summary":"Revoke an API key","description":"Deactivates an API key. Revoked keys immediately stop working.","tags":["API Keys"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"API key revoked"},"404":{"$ref":"#/components/responses/NotFound"}}}}},"webhooks":{"alert":{"post":{"operationId":"alertWebhook","summary":"Alert delivered to a webhook channel","description":"POSTed to the channel URL with `Content-Type: application/json` and `User-Agent: Chainitor-Webhooks/1.0`, signed per [Standard Webhooks](https://www.standardwebhooks.com/): `webhook-id` (stable per alert, use it to deduplicate), `webhook-timestamp` (Unix seconds; reject values more than 5 minutes from your clock) and `webhook-signature: v1,<base64 HMAC-SHA256 of \"{webhook-id}.{webhook-timestamp}.{raw body}\">`. The key is the channel secret: pass `whsec_` + base64 of the secret's characters to any Standard Webhooks library (the app shows it in that form). Compare signatures in constant time. The legacy `X-Webhook-Signature: sha256=<hex HMAC-SHA256 of the raw body>` header is still sent, keyed with the same secret, but carries no replay protection. Redirects are not followed and private or internal addresses are refused. Any 2xx response within 10 seconds counts as delivered. `critical`: a breach. `recovery`: the monitor is healthy again; it closes the preceding `critical`. `info` (added October 2026): an event worth knowing that is neither, for example a Safe proposal or signature; it never closes anything. Integrations that switch on `critical`/`recovery` must handle or ignore `info`.","tags":["Channels"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookAlertPayload"}}}},"responses":{"200":{"description":"Any 2xx acknowledges delivery."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key in format `cm_` followed by 64 hex characters. Pass as `Authorization: Bearer cm_xxx`."}},"schemas":{"Monitor":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"ETH Balance Watch"},"type":{"type":"string","enum":["balance","transaction_count","erc20_balance","event_emitted","failed_transaction","transaction_value","function_call","safe_threshold_changed","safe_owner_added","safe_owner_removed","safe_guard_changed","safe_module_enabled","safe_module_disabled","safe_pending_config_change","safe_activity"]},"chain":{"type":"string","enum":["ethereum","ethereum-sepolia","polygon","polygon-amoy","bsc","bsc-testnet","arbitrum","arbitrum-sepolia","optimism","optimism-sepolia","base","base-sepolia","robinhood","local"]},"intervalMinutes":{"type":"integer","example":5},"isEnabled":{"type":"boolean"},"config":{"type":"object","description":"Monitor-type-specific configuration"},"group":{"type":"string","nullable":true},"lastStatus":{"type":"string","nullable":true},"lastBalance":{"type":"string","nullable":true},"organizationId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateMonitorRequest":{"type":"object","required":["name","type","chain","intervalMinutes","config","channelIds"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"type":{"type":"string","enum":["balance","transaction_count","erc20_balance","event_emitted","failed_transaction","transaction_value","function_call","safe_threshold_changed","safe_owner_added","safe_owner_removed","safe_guard_changed","safe_module_enabled","safe_module_disabled","safe_pending_config_change","safe_activity"]},"chain":{"type":"string","enum":["ethereum","ethereum-sepolia","polygon","polygon-amoy","bsc","bsc-testnet","arbitrum","arbitrum-sepolia","optimism","optimism-sepolia","base","base-sepolia","robinhood","local"]},"intervalMinutes":{"type":"integer","minimum":1,"maximum":1440},"group":{"type":"string","maxLength":100},"config":{"type":"object","description":"Shape depends on `type`. See documentation for each monitor type."},"channelIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1}}},"UpdateMonitorRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"intervalMinutes":{"type":"integer","minimum":1,"maximum":1440},"config":{"type":"object"},"channelIds":{"type":"array","items":{"type":"string","format":"uuid"}},"group":{"type":"string","maxLength":100,"nullable":true}}},"Alert":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"monitorId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["critical","recovery","info"],"description":"`critical`: a breach. `recovery`: the monitor is healthy again; it closes the preceding `critical`. `info` (added October 2026): an event worth knowing that is neither, for example a Safe proposal or signature; it never closes anything. Integrations that switch on `critical`/`recovery` must handle or ignore `info`."},"status":{"type":"string"},"message":{"type":"string"},"details":{"type":"object"},"createdAt":{"type":"string","format":"date-time"}}},"AlertStats":{"type":"object","description":"Org-wide alert counts. `total` in the pagination block counts every type, including `info`.","properties":{"critical":{"type":"integer"},"recovery":{"type":"integer"},"info":{"type":"integer"},"emailsSent":{"type":"integer"}}},"WebhookAlertPayload":{"type":"object","required":["alertId","monitorId","monitorName","alertType","severity","timestamp","monitor","metadata"],"properties":{"alertId":{"type":"string"},"monitorId":{"type":"string"},"monitorName":{"type":"string"},"alertType":{"type":"string","enum":["critical","recovery","info"],"description":"`critical`: a breach. `recovery`: the monitor is healthy again; it closes the preceding `critical`. `info` (added October 2026): an event worth knowing that is neither, for example a Safe proposal or signature; it never closes anything. Integrations that switch on `critical`/`recovery` must handle or ignore `info`."},"severity":{"type":"string","enum":["critical","warning","info"],"description":"`critical` for critical alerts; `info` for recovery and info alerts."},"timestamp":{"type":"string","format":"date-time"},"monitor":{"type":"object","properties":{"type":{"type":"string","enum":["balance","transaction_count","erc20_balance","event_emitted","failed_transaction","transaction_value","function_call","safe_threshold_changed","safe_owner_added","safe_owner_removed","safe_guard_changed","safe_module_enabled","safe_module_disabled","safe_pending_config_change","safe_activity"]},"chain":{"type":"string"},"address":{"type":"string"}}},"results":{"type":"array","items":{}},"metadata":{"type":"object","additionalProperties":true,"properties":{"currentValue":{"type":"string"},"threshold":{"type":"string"},"tokenSymbol":{"type":"string"},"chainName":{"type":"string"},"message":{"type":"string"}}}}},"Channel":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["slack","telegram","email","webhook","pagerduty"]},"isEnabled":{"type":"boolean"},"isVerified":{"type":"boolean"},"isDefault":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}},"CreateChannelRequest":{"type":"object","required":["name","type","config"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"type":{"type":"string","enum":["slack","telegram","email","webhook","pagerduty"]},"config":{"type":"object","description":"Shape depends on `type`."}}},"UpdateChannelRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"config":{"type":"object"}}},"AddressBookEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"address":{"type":"string"},"organizationId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateAddressRequest":{"type":"object","required":["label","address"],"properties":{"label":{"type":"string"},"address":{"type":"string","description":"Ethereum address (EIP-55)"}}},"UpdateAddressRequest":{"type":"object","properties":{"label":{"type":"string"},"address":{"type":"string"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"keyPrefix":{"type":"string","example":"cm_a1b2c3d","description":"First 11 characters for identification"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date-time","nullable":true},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"description":"API key metadata. The key hash is never returned."},"ApiKeyCreated":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"key":{"type":"string","description":"The raw API key — shown only once. Store it securely."},"keyPrefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"expiresAt":{"type":"string","format":"date-time","nullable":true},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}}}},"CreateApiKeyRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Human-readable label, e.g. \"CI Pipeline\""},"expiresAt":{"type":"string","format":"date-time","description":"Optional expiration date"},"scopes":{"type":"array","items":{"type":"string"},"description":"Future use — currently all keys get full access"}}},"MeResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string"},"currentOrganizationId":{"type":"string","format":"uuid"},"organizations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":"string"}}}},"subscriptionStatus":{"type":"string"},"authMethod":{"type":"string","enum":["session","api_key"]}}}}},"Pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"pages":{"type":"integer"}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["UNAUTHORIZED","FORBIDDEN","NOT_FOUND","VALIDATION_FAILED","RATE_LIMITED","SUBSCRIPTION_REQUIRED","INTERNAL_ERROR"]},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}}}}}},"meta":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"}}}}}},"responses":{"Unauthorized":{"description":"Authentication required — provide a valid API key or session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"UNAUTHORIZED","message":"Authentication required"}}}}},"Forbidden":{"description":"Insufficient permissions or subscription required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"FORBIDDEN","message":"Access denied"}}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"NOT_FOUND","message":"Resource not found"}}}}},"ValidationError":{"description":"Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"VALIDATION_FAILED","message":"Request validation failed","details":[{"field":"name","message":"Required"}]}}}}}}},"tags":[{"name":"Auth","description":"Authentication and identity"},{"name":"Monitors","description":"Blockchain monitors — create, update, execute, and manage monitoring rules"},{"name":"Alerts","description":"Alerts generated when monitor thresholds are breached"},{"name":"Channels","description":"Notification channels — where alerts are sent (Slack, email, webhook, etc.)"},{"name":"Address Book","description":"Saved blockchain addresses for quick reference"},{"name":"Organization","description":"Organization settings, integrations, and monitor groups"},{"name":"API Keys","description":"Manage API keys for programmatic access"}]}