Account and billing
Notifications
Automatic account emails, and deployment, domain and backup events sent to email, webhooks, Slack, Discord or Telegram.
Updated
Cloud tells you about two kinds of thing. Notices about your account and your organizations' bills are always emailed to your account's address. Updates about deployments, domains and backups go wherever you choose, through channels you add. Both are under Settings, then Notifications, and both are yours rather than an organization's: they cover every organization you own.
Automatic account emails
The Automatic account emails card shows the address they go to, which is the email address of the Cahaves account you sign in with. "Billing and account safety notices are always sent by Cahaves Cloud.": they cannot be turned off, redirected or sent to a channel.
| Event | Sent when | Subject |
|---|---|---|
| Monthly limit | What an organization's month comes to, at the rate its services run now, reaches 80% of its monthly limit, once a month | Your Cahaves Cloud month for Kopi Tiga is on course to reach its limit, naming the organization |
| Charge failed | An organization's card charge for a month did not go through, once for that month | Your December 2026 charge for Kopi Tiga did not go through, naming the month and the organization |
| Card needed | An organization's month closed with something to pay and no card on the organization, once for that month | Add a card for Kopi Tiga to pay for December 2026 on Cahaves Cloud, naming the organization and the month |
| Stop scheduled | An unpaid month's grace period starts, once for that month, or the grace period for paid services run with no card on file, once each time it starts, unless the stop is due at once | Paid services in Kopi Tiga stop on 13 December 2026 at 12:00 UTC unless the month is paid, naming the organization and the date. For no card: Add a card to Kopi Tiga by 13 December 2026 at 12:00 UTC, or its paid services stop |
| Stopped for billing | An organization's paid services stop for billing, once for each stop | Paid services in Kopi Tiga are stopped for billing, naming the organization, and for an unpaid month or no card the date they are archived if they stay stopped |
| Starting again | Every service the stop stopped is back, once for each stop | Paid services in Kopi Tiga are starting again, naming the organization |
| Archive coming | A stop that lasts archives the organization's paid services in 7 days, and again in 1 day | The paid services of Kopi Tiga will be archived on 12 January 2027 at 12:00 UTC, naming the organization and the date |
| Archived for billing | Cloud archived the organization's paid services, once for each run | Paid services in Kopi Tiga are archived for billing, naming the organization |
| Backups expiring | An archive's final backups are deleted in 7 days | Final backups from Kopi Tiga are deleted on 11 February 2027 at 13:00 UTC, naming the organization and the date |
| Backups deleted | Cloud deleted an archive's final backups | Final backups from Kopi Tiga are deleted, naming the organization |
| Account suspended | Cahaves suspended the account, and with it every organization it owns | Your Cahaves Cloud account is suspended |
| Account reactivated | The account is active again | Your Cahaves Cloud account is active again |
An email about an organization's bill links to that organization's billing, and opening the link moves the console to it; the archived, expiring and deleted emails link to the Archived tab of its Storage instead, where the final backups are; the suspension email links to Support and the reactivation email to the Dashboard. Billing explains each one, and Archived for billing the four about an archive. Paddle sends its own receipt for a card charge, and an invoice comes from Cahaves' invoicing service. These deliveries appear in Delivery history under the channel "Account email", marked Automatic.
Service notifications
A channel is one destination with the events it should receive. Add as many as you need, for example failures to a chat room and every deployment to a webhook.
A channel is yours, so it receives its events from every organization you own. A message names the service, the domain or the backup, not the organization, and its link opens in the organization the event belongs to, moving the console to it first.
Events
| Event in the console | Name in a webhook | Sent when |
|---|---|---|
| Deployment succeeded | deployment.succeeded | A deployment ends Done. |
| Deployment failed | deployment.failed | A deployment ends Failed, including one Cloud stopped waiting for. A cancelled deployment sends nothing. |
| Domain verified | domain.verified | A domain reaches HTTPS active, and again each time a renewal check confirms its certificate. |
| Domain verification failed | domain.failed | A domain's checks give up, as DNS needs attention or HTTPS needs attention. |
| Backup completed | backup.completed | A backup is stored and Cloud has found the stored file. |
| Backup failed | backup.failed | A backup fails. A backup whose outcome Cloud cannot confirm sends neither event. |
Channel types
| Channel type | Fields | What Cloud accepts |
|---|---|---|
| Email address | Any valid address | |
| Webhook | Webhook URL, Signing secret | An HTTPS address on port 443; a secret of 16 to 256 characters |
| Slack | Webhook URL | A Slack incoming webhook on hooks.slack.com, whose path starts /services/ |
| Discord | Webhook URL | A Discord webhook on discord.com exactly, whose path starts /api/webhooks/ |
| Telegram | Bot token, Chat ID | The bot token Telegram issued for your bot, and a numeric chat id (negative for a group) or a public channel's @name |
Every webhook address, for a webhook, Slack or Discord channel, must be HTTPS on port 443, with no user name, password or #fragment in it. At delivery Cloud also checks that the host resolves only to public internet addresses, and it does not follow redirects.
Add a channel
Open the dialog
Under Service notifications, press Add channel.
Describe the channel
Choose a Channel type, give it a Name (up to 80 characters), leave Delivery on Enabled, and tick the Events it should receive. Deployment failed is ticked for you; at least one event is needed.
Connect it
Fill in the fields for its type from the table above, then press Save channel.
Connection details are stored encrypted and never displayed again, in the console or anywhere else. The channel's card shows its name, Enabled or Paused, its type and its events.
Test a channel
Send test on a channel's card sends one real notification down the same path every event takes, under the event name test, with the subject "Cahaves Cloud test notification" and the message "This is a test notification from Cahaves Cloud. If it reached you, this channel is configured correctly." It is signed, retried and listed in Delivery history as "Test notification", so a test that arrives proves the channel works end to end.
The button is disabled on a paused channel ("Turn this channel on to send a test."), and a channel takes one test at a time: a second is refused with "A test to this channel is still being sent. Wait for it to finish." until the first is answered.
Edit, pause or archive
Edit channel changes the name, the delivery setting and the events. The type cannot change. Connection details stays on Keep saved configuration unless you choose Replace configuration and enter new ones.
Setting Delivery to Paused stops the channel receiving anything. Events that happen while it is paused are not sent later.
Archive removes the channel after "Archive this channel?" and Archive channel. It stops receiving updates, its connection details are erased, and its delivery history is kept.
Delivery history
Delivery history lists every notification, newest first, 25 to a page with Previous and Next: its Event, Channel, Time (in UTC) and Status, with a sentence under the status when something went wrong. While a delivery is queued or sending, the page refreshes itself every 15 seconds.
| Status | Meaning |
|---|---|
queued | Waiting for its first attempt or its next one. |
sending | An attempt is under way. |
delivered | The receiving service accepted it. That is all it proves: not that a person read it. |
failed | The receiver refused it, or every attempt was used. |
| Outcome unknown | Cloud cannot tell whether it arrived, so it does not send it again. |
skipped | The channel was paused or archived before the notification went out. |
Cloud makes up to five attempts, 2, 4, 8 and 16 minutes apart, and only when the answer says to try again: a 429 or 5xx status, or a destination whose name did not resolve. Any other refusal fails at once. A request that timed out or lost its connection may have arrived, so it becomes Outcome unknown straight away rather than risk sending the same message twice.
What a channel receives
Email carries the subject, the message, the service or domain it concerns and when it happened, with a link to the page in the console. Slack, Discord and Telegram receive three lines of plain text: "Cahaves Cloud", the message, and the link. Discord posts under the name Cahaves Cloud with mentions turned off, and Slack and Telegram show no link previews.
Webhooks
A webhook channel receives a POST with a JSON body (Content-Type: application/json) for each event:
{
"source": "cahaves_cloud",
"event": "deployment.succeeded",
"occurred_at": "2026-09-23T08:30:00Z",
"resource": { "type": "Deployment", "id": "9d2c7e1b-4a6f-4b3e-8e0d-5f1a2c3b4d6e", "label": "web" },
"subject": "Deployment succeeded for web",
"message": "Cahaves Cloud deployed web successfully.",
"url": "https://cloud.cahaves.com/projects/shop/services/0b9e4d2a-7c13-4f6e-a8d5-3e1c9b7f2a40/deployments/9d2c7e1b-4a6f-4b3e-8e0d-5f1a2c3b4d6e",
"id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b"
}| Field | What it holds |
|---|---|
source | Always cahaves_cloud. |
event | One of the six names above, or test. |
occurred_at | When it happened, in UTC. |
resource | What the event is about: its type (Deployment, Domain or BackupRun, and User for a test), its id, and a label, which is the service's name or the domain's host. |
subject, message | The same words an email would carry. |
url | The page in the console that shows it. |
id | The event's id. Every channel that receives the same event gets the same id. |
Two headers come with it:
| Header | What it holds |
|---|---|
X-Cahaves-Delivery | The delivery's id. Retries of one delivery carry the same id, so use it to ignore a repeat. |
X-Cahaves-Signature | sha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with the channel's signing secret. |
Answer with any 2xx status as soon as you have the request. Cloud waits at most ten seconds for the answer, reads no more than 32 KB of it, and treats a slower answer as Outcome unknown. A 3xx is not followed and counts as a refusal.
The console asks for a signing secret when you add a webhook channel. Check the signature against the exact bytes you received, before parsing them:
import { createHmac, timingSafeEqual } from "node:crypto";
export function isFromCloud(rawBody, header, secret) {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const given = Buffer.from(header ?? "");
const wanted = Buffer.from(expected);
return given.length === wanted.length && timingSafeEqual(given, wanted);
}A test delivery has the same shape, with event set to test, so Send test is the way to check your receiver.