# sunucu.com API Reference (v1.15, 2026-08-16)

- **Base URL:** `https://api.sunucu.com/v1`
- **Auth:** `Authorization: Bearer snc_…` (or `X-API-Key`). Mint keys in the dashboard → Account → API Keys.
- **Format:** JSON. Destructive server operations require the opt-in `servers:destroy` scope.
- **Idempotency:** snapshot-create, reinstall and ticket-create accept an `Idempotency-Key` header (deduped 24h).
- **Rate limit:** 120 requests/minute per API key. Responses carry `X-RateLimit-Limit/-Remaining/-Reset`; a 429 carries `Retry-After`.

## Scopes

| Scope | Description |
|---|---|
| `account:read` | Read your account profile. |
| `servers:read` | List servers and read details, stats, snapshots, and IPs (reverse DNS). |
| `servers:write` | Power actions, create/delete snapshots, set/clear reverse DNS (PTR). |
| `servers:destroy` | Reinstall, revert a snapshot, or terminate (destructive; not in defaults). |
| `hosting:read` | List hosting accounts and read details. |
| `hosting:write` | Attach, verify, and remove a custom domain. |
| `hosting:manage` | Full site control panel: files, databases, backups, cron, PHP, SSL, protected dirs, WAF, SSH terminal, git. Powerful; opt-in, not in defaults. |
| `mail:read` | List mail domains, mailboxes, aliases; read mail-setup DNS. |
| `mail:write` | Add/remove mail domains, mailboxes, and aliases; reset mailbox passwords. |
| `domains:read` | List domains and read details. |
| `domains:write` | Update auto-renew, transfer lock, WHOIS privacy, nameservers. |
| `billing:read` | Read invoices, transactions, and wallet balance. |
| `billing:write` | Configure wallet auto-recharge. Opt-in, not in defaults. |
| `tickets:read` | List tickets and read messages. |
| `tickets:write` | Open tickets, post replies, and close them. |
| `webhooks:read` | List webhook subscriptions and delivery history. |
| `webhooks:write` | Create, edit, delete webhooks; rotate secrets; redeliver. |

## Endpoints

### Account

#### `GET /v1/account` — Get account

Returns the authenticated account profile.

_Scope:_ `account:read`

_Response:_

```json
{
  "id": "ee0d1f04-…",
  "email": "you@example.com",
  "name": "Jane Doe",
  "country": "TR",
  "email_verified": true,
  "created_at": "2026-01-01T00:00:00.000Z"
}
```

### Servers

#### `GET /v1/servers` — List servers

List every server on the account.

_Scope:_ `servers:read`

#### `GET /v1/servers/:id` — Get server

Server detail (backbone-scrubbed — no upstream provider, no provisioning logs).

_Scope:_ `servers:read`

#### `GET /v1/servers/:id/stats` — Live stats

Live CPU / memory / network / disk usage.

_Scope:_ `servers:read`

#### `GET /v1/servers/:id/snapshots` — List snapshots

Disk snapshots (restore points) for the server.

_Scope:_ `servers:read`

#### `GET /v1/servers/:id/ips` — List IPs & reverse DNS

Every IP on the server with its current PTR record. `zoneHosted: false` means the reverse zone is not on our DNS and the PTR cannot be managed here.

_Scope:_ `servers:read`

_Response:_

```json
[
  {
    "ip": "46.31.78.44",
    "primary": true,
    "gateway": "46.31.78.1",
    "netmask": "255.255.255.0",
    "cidr": "46.31.78.0/24",
    "ptr": "mail.example.com",
    "zoneHosted": true
  }
]
```

#### `GET /v1/servers/:id/plan-options` — List plan options

Plans this server can resize to — same family, same disk size (a plan change never alters disk). Returns the current plan and the switchable options, cheapest first.

_Scope:_ `servers:read`

_Response:_

```json
{
  "current": { "id": "...", "name": "Cloud Router S", "vcpu": 1, "ramMb": 1024, "diskGb": 10, "monthlyPrice": 5.99 },
  "options": [ { "id": "...", "name": "Cloud Router M", "vcpu": 2, "ramMb": 2048, "diskGb": 10, "monthlyPrice": 11.99 } ]
}
```

#### `POST /v1/servers/:id/power/:action` — Power action

Power the server start, stop, or reboot. `:action` ∈ {start,stop,reboot}.

_Scope:_ `servers:write`

#### `POST /v1/servers/:id/sso` — Dashboard SSO

Issue a short-lived URL that logs into the dashboard for this server.

_Scope:_ `servers:read`

_Request body:_

```json
{ "next": "/optional/path" }
```

#### `POST /v1/servers/:id/change-plan` — Change plan (resize)

Switch to another plan in the same family with the same disk size — an in-place vCPU/RAM resize. The server reboots (~1 min) to apply; disk is never changed. Only the recurring price changes: no proration on an up-switch, no credit on a down-switch — the next renewal bills the new plan. Use GET /servers/:id/plan-options for valid targets.

_Scope:_ `servers:write`

_Request body:_

```json
{ "productId": "..." }
```

#### `GET /v1/servers/:id/addons` — List add-ons

Add-ons this server's plan offers — extra IPs, /24 class blocks, the SEO IP Pack (7 dedicated IPs, each from a different /24, for SEO hosting and sender-reputation isolation) and backups. Prices are in cents: `monthly_usd_cents` recurs, `prorated_usd_cents` is what a purchase costs today. Only ONE add-on per type can be active, so `owned_by_type: true` means not orderable until the active one is removed. `available: false` with a `stock_note` means temporarily out of stock.

_Scope:_ `servers:read`

#### `POST /v1/servers/:id/addons` — Purchase add-on

Attach an add-on to a running server. Debits your prepaid balance **immediately**, prorated to the end of the current cycle, and the add-on then renews with the server every month. For IP add-ons the addresses are routed to your server but must be configured inside the guest OS yourself. Returns 400 if an add-on of the same type is already active (remove it first), if stock is short, or if your balance will not cover it.

_Scope:_ `servers:write`

_Request body:_

```json
{ "addonId": "seoip7pk" }
```

#### `DELETE /v1/servers/:id/addons/:addonId` — Remove add-on

Cancel an add-on. **No refund** is issued for the remainder of the current period — the recurring price drops from the next renewal. For IP add-ons this is immediate and disruptive: the addresses are released and stop routing to your server, so anything bound to them (sites, SSL, mail) breaks — unconfigure them first. Changing tier (8 IPs to 16 IPs) is a DELETE followed by a POST.

_Scope:_ `servers:write`

#### `POST /v1/servers/:id/snapshots` — Create snapshot

Take a disk snapshot. Honours an optional Idempotency-Key header.

_Scope:_ `servers:write`

_Request body:_

```json
{ "name": "pre-upgrade", "description": "before kernel bump" }
```

#### `DELETE /v1/servers/:id/snapshots/:snapshotId` — Delete snapshot

Remove a snapshot (non-destructive to the live disk).

_Scope:_ `servers:write`

#### `PUT /v1/servers/:id/ips/:ip/ptr` — Set reverse DNS (PTR)

Point the IP's PTR record at a hostname (e.g. `mail.example.com`). Idempotent upsert.

_Scope:_ `servers:write`

_Request body:_

```json
{ "hostname": "mail.example.com" }
```

#### `DELETE /v1/servers/:id/ips/:ip/ptr` — Clear reverse DNS (PTR)

Remove the PTR record for the IP.

_Scope:_ `servers:write`

#### `POST /v1/servers/:id/reinstall` — Reinstall OS

DESTRUCTIVE — wipe the disk and rebuild from an OS template. Honours Idempotency-Key.

_Scope:_ `servers:destroy`

_Request body:_

```json
{ "osTemplate": "ubuntu-22.04", "os": "ubuntu" }
```

#### `POST /v1/servers/:id/snapshots/:snapshotId/revert` — Revert snapshot

DESTRUCTIVE — roll the live disk back to a snapshot.

_Scope:_ `servers:destroy`

#### `DELETE /v1/servers/:id` — Terminate server

DESTRUCTIVE — permanently terminate the server.

_Scope:_ `servers:destroy`

### Capacity pools

#### `GET /v1/pools/catalogue` — List pool products

Capacity-pool products with their per-unit prices (in cents) and the range each slider may move between. A capacity pool is a block of vCPU / RAM / disk / IPv4 bought ONCE — you then build as many servers inside it as the quota allows, and **those servers are free**: no price of their own, no renewal, and they never appear on a bill. ⚑ Units are counts of BLOCKS, not of the underlying resource: `ram2gb` counts 2 GB blocks and `ip16` counts blocks of sixteen addresses, so `ram2gb: 16` is 32 GB.

_Scope:_ `servers:read`

#### `POST /v1/pools/quote` — Price a selection

Monthly price for a pool shape, with a per-unit breakdown and the resolved figures (vCPU, GB, addresses) so you can show the customer what they are actually getting. Nothing is charged. The purchase re-prices server-side, so a total worked out client-side is displayed but never trusted.

_Scope:_ `servers:read`

_Request body:_

```json
{ "productId": "...", "vcpu": 16, "ram2gb": 16, "disk100": 10, "ip16": 1 }
```

#### `GET /v1/pools` — List your pools

Every capacity pool on the account, with its quotas, status, monthly price and renewal date.

_Scope:_ `servers:read`

#### `GET /v1/pools/:id` — Get a pool

One pool plus live `usage` — the vCPU, RAM, disk, IPs and server count currently committed inside it — and the servers we know are in it. Usage counts PROVISIONED resources, not live consumption: a powered-off server still holds its allocation, because you can switch it back on. Also returns `bounds` (the range a resize may move each unit between, from the live catalogue) and, on the pool itself, `rates_cents` — the per-unit prices this pool was SOLD at, which is what a resize is charged at.

_Scope:_ `servers:read`

#### `POST /v1/pools` — Buy a pool

Buys a capacity pool and provisions it. Debits your prepaid balance immediately for the first month. Returns 400 if your balance will not cover it or the selection falls outside the product bounds. Once active, build free servers into it with POST /v1/pools/:id/servers.

_Scope:_ `servers:write`

_Request body:_

```json
{ "productId": "...", "label": "prod-cluster", "vcpu": 16, "ram2gb": 16, "disk100": 10, "ip16": 1 }
```

#### `POST /v1/pools/:id/resize-quote` — Price a resize

Prices a new shape without applying it: the new monthly, the difference, and `charge_now_usd_cents` — the prorated amount taken immediately for the days left in the cycle. Priced at the rates the pool was SOLD at, never at today's catalogue, so the figure matches what PATCH will charge.

_Scope:_ `servers:read`

_Request body:_

```json
{ "vcpu": 32, "ram2gb": 32, "disk100": 20, "ip16": 2 }
```

#### `PATCH /v1/pools/:id` — Resize a pool

Changes the pool's shape. Takes the WHOLE shape in absolute units, not deltas — to add 8 vCPU to a 16-vCPU pool, send 24. **Growing is a purchase**: charged immediately, prorated, at the rates the pool was sold at. **Shrinking is not refunded** and lowers the price from the next renewal. Refuses to shrink below what the pool's servers already hold — delete servers first.

_Scope:_ `servers:write`

_Request body:_

```json
{ "vcpu": 32, "ram2gb": 32, "disk100": 20, "ip16": 2 }
```

#### `POST /v1/pools/:id/servers` — Build a free server in the pool

Creates a server inside the pool. **It is free** — no charge now, no monthly price, no renewal; the pool carries the bill, and the server is checked against its quota instead of your balance. ⚑ `ipCount` chooses how many of the pool's own public addresses it takes (default 1). **`ipCount: 0` is private-only: no public interface, no default route, and no internet at all** — reachable from the pool's other servers on its private network and through the web console. Linux only.

_Scope:_ `servers:write`

_Request body:_

```json
{ "productId": "...", "label": "web-1", "os": "ubuntu", "osTemplate": "ubuntu-24.04", "ipCount": 1 }
```

#### `GET /v1/pools/:id/ips` — List the pool's IP block

Every IPv4 address the pool owns, with its PTR and which server holds it (`assignedTo: null` means free in the block). These came with the pool, so assigning one costs nothing — to get MORE, resize the pool's `ip16`.

_Scope:_ `servers:read`

#### `POST /v1/pools/:id/ips/apply` — Move addresses in the block

Assign, move or return addresses within the pool's own block, in ONE batch. `serverId` names a server INSIDE this pool; `null` returns the address to the block. Free. Addresses never leave the block. The set is validated whole and refused entire if any entry names a server that is not in this pool. ⚑ The guest OS is not reconfigured for you, and moving an address away stops it routing at once — anything bound to it breaks. Rate limited to 6 calls per minute: each call reprograms the router once regardless of batch size, so send every change together rather than looping.

_Scope:_ `servers:write`

_Request body:_

```json
{ "changes": [ { "ip": "203.0.113.10", "serverId": "uuid" }, { "ip": "203.0.113.11", "serverId": null } ] }
```

#### `DELETE /v1/pools/:id` — Terminate a pool

DESTRUCTIVE — every server in the pool is powered off (preserved, not destroyed), the whole IP block is returned and the private network is deleted. **No refund** for the remainder of the cycle.

_Scope:_ `servers:destroy`

### Hosting

#### `GET /v1/hosting` — List hosting

List web-hosting accounts.

_Scope:_ `hosting:read`

#### `GET /v1/hosting/:id` — Get hosting

Hosting account detail (connection info, backbone-scrubbed).

_Scope:_ `hosting:read`

#### `PUT /v1/hosting/:id/custom-domain` — Set custom domain

Attach a custom domain to a hosting account.

_Scope:_ `hosting:write`

_Request body:_

```json
{ "domain": "example.com" }
```

#### `POST /v1/hosting/:id/custom-domain/verify` — Verify custom domain

Re-check DNS and attach the custom domain once it points to us.

_Scope:_ `hosting:write`

#### `DELETE /v1/hosting/:id/custom-domain` — Remove custom domain

Detach the custom domain from the hosting account.

_Scope:_ `hosting:write`

### Hosting control panel

#### `GET /v1/hosting/:id/stats` — Site stats

Disk usage, inode count, bandwidth, and mailbox count for the account.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/logs` — Tail logs

Tail the access or error log. Query: `kind` ∈ {access,error}, `lines`.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/cert/retry` — Re-issue SSL

Retry the Let's Encrypt certificate issue now.

_Scope:_ `hosting:manage`

#### `PUT /v1/hosting/:id/php-version` — Set PHP version

Switch the account's PHP-FPM version.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "php_version": "8.3" }
```

#### `GET /v1/hosting/:id/cron` — Get cron

Read the crontab (header + jobs).

_Scope:_ `hosting:manage`

#### `PUT /v1/hosting/:id/cron` — Set cron

Replace the crontab.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "jobs": [ { "schedule": "0 3 * * *", "command": "php cron.php" } ] }
```

#### `GET /v1/hosting/:id/protected-dirs` — List protected dirs

Password-protected directories (htpasswd).

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/protected-dirs` — Protect a dir

Add or update a password-protected directory.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "path": "/admin", "basic_user": "u", "password": "…" }
```

#### `DELETE /v1/hosting/:id/protected-dirs` — Unprotect a dir

Remove protection. Query: `path`.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/waf` — WAF status

ModSecurity WAF status for the account.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/waf/access` — WAF access status

Whether temporary WAF-log access is active.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/waf/access` — Request WAF access

Request temporary access to WAF logs.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/ssh-terminal/access` — SSH access status

Whether browser-SSH terminal access is enabled.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/ssh-terminal/access` — Request SSH access

Enable browser-SSH terminal access.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/ssh-terminal/launch` — Launch SSH terminal

Start a browser-SSH session; returns a session URL/token.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/ssh-terminal/stop` — Stop SSH terminal

Stop the browser-SSH session.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/git` — Git status

Git-deploy status for the account.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/git/deploy-key` — Git deploy key

The SSH deploy key to add to your repo.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/git/webhook` — Git webhook

The push-to-deploy webhook URL/secret.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/git/webhook` — Enable git webhook

Enable push-to-deploy.

_Scope:_ `hosting:manage`

#### `DELETE /v1/hosting/:id/git/webhook` — Disable git webhook

Disable push-to-deploy.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/git/deploy` — Git deploy

Clone/deploy a repo into the site.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "repo_url": "git@…", "branch": "main", "subdir": "" }
```

#### `POST /v1/hosting/:id/git/pull` — Git pull

Pull the latest commit for the deployed repo.

_Scope:_ `hosting:manage`

#### `DELETE /v1/hosting/:id/git` — Git disconnect

Disconnect git deploy from the site.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/files` — List files

List a directory. Query: `path` (default /public_html).

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/files/read` — Read file

Read a text file's contents. Query: `path`.

_Scope:_ `hosting:manage`

#### `PUT /v1/hosting/:id/files` — Write file

Create or overwrite a text file.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "path": "/public_html/x.txt", "content": "…" }
```

#### `DELETE /v1/hosting/:id/files` — Delete file/dir

Delete a file or directory. Query: `path`, `recursive`.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/files/download` — Download file

Stream a file as an attachment. Query: `path`.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/files/upload` — Upload file

Upload a file (multipart form field `file`). Query: `path`.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/files/mkdir` — Make directory

Create a directory.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "path": "/public_html/new" }
```

#### `POST /v1/hosting/:id/files/rename` — Rename/move

Rename or move a file/directory.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "from": "/a", "to": "/b" }
```

#### `GET /v1/hosting/:id/backups` — List backups

Site backups (restore points).

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/backups` — Create backup

Create a new site backup.

_Scope:_ `hosting:manage`

#### `DELETE /v1/hosting/:id/backups/:bid` — Delete backup

Delete a backup.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/backups/:bid/restore` — Restore backup

Restore the site from a backup.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/backups/:bid/download` — Download backup

Stream a backup archive (gzip).

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/visitor-stats` — Visitor stats

Visitor statistics. Query: `period` ∈ {24h,7d,30d}.

_Scope:_ `hosting:manage`

#### `GET /v1/hosting/:id/databases` — List databases

Extra MySQL databases on the account.

_Scope:_ `hosting:manage`

#### `POST /v1/hosting/:id/databases` — Add database

Create an extra MySQL database.

_Scope:_ `hosting:manage`

_Request body:_

```json
{ "suffix": "wp2" }
```

#### `DELETE /v1/hosting/:id/databases/:name` — Remove database

Delete an extra MySQL database.

_Scope:_ `hosting:manage`

### Mail

#### `GET /v1/mail/setup` — Mail setup (DNS)

The DNS records to add so mail for a domain routes to us, plus the webmail address. Pass ?domain=example.com to get them composed for that zone — the MX is mail.<your domain>, so without one there is nothing to name.

_Scope:_ `mail:read`

#### `GET /v1/mail/domains` — List mail domains

Every mail domain on the account.

_Scope:_ `mail:read`

#### `POST /v1/mail/domains` — Add mail domain

Enable email hosting for a domain.

_Scope:_ `mail:write`

_Request body:_

```json
{ "domain": "example.com" }
```

#### `DELETE /v1/mail/domains/:id` — Remove mail domain

Disable email hosting for a domain (removes its mailboxes and aliases).

_Scope:_ `mail:write`

#### `GET /v1/mail/domains/:id/mailboxes` — List domain mailboxes

Mailboxes under one mail domain.

_Scope:_ `mail:read`

#### `GET /v1/mail/domains/:id/aliases` — List domain aliases

Forwarding aliases under one mail domain.

_Scope:_ `mail:read`

#### `GET /v1/mail/mailboxes` — List mailboxes

Every mailbox across all your mail domains.

_Scope:_ `mail:read`

#### `POST /v1/mail/mailboxes` — Create mailbox

Create a mailbox on a mail domain.

_Scope:_ `mail:write`

_Request body:_

```json
{ "domain_id": 12, "local_part": "info", "password": "…", "quota_mb": 2048 }
```

#### `PATCH /v1/mail/mailboxes/:id/password` — Reset mailbox password

Set a new password for a mailbox.

_Scope:_ `mail:write`

_Request body:_

```json
{ "password": "…" }
```

#### `DELETE /v1/mail/mailboxes/:id` — Delete mailbox

Permanently delete a mailbox and its mail.

_Scope:_ `mail:write`

#### `POST /v1/mail/aliases` — Create alias

Create a forwarding alias (source → destination).

_Scope:_ `mail:write`

_Request body:_

```json
{ "domain_id": 12, "source_local": "sales", "destination": "info@example.com" }
```

#### `DELETE /v1/mail/aliases/:id` — Delete alias

Remove a forwarding alias.

_Scope:_ `mail:write`

### Domains

#### `GET /v1/domains` — List domains

List registered domains.

_Scope:_ `domains:read`

#### `GET /v1/domains/:id` — Get domain

Domain detail.

_Scope:_ `domains:read`

#### `PATCH /v1/domains/:id` — Update domain

Update auto-renew, transfer lock, WHOIS privacy, or nameservers.

_Scope:_ `domains:write`

_Request body:_

```json
{ "auto_renew": true, "transfer_lock": true, "nameservers": ["ns1.example.com","ns2.example.com"] }
```

### Billing

#### `GET /v1/billing/invoices` — List invoices

Paginated invoice list. Query: page, limit.

_Scope:_ `billing:read`

#### `GET /v1/billing/invoices/:id` — Get invoice

Single invoice with line items.

_Scope:_ `billing:read`

#### `GET /v1/billing/wallet` — Get wallet

Prepaid wallet balance and state.

_Scope:_ `billing:read`

#### `GET /v1/billing/wallet/transactions` — Wallet transactions

Recent wallet transactions. Query: limit.

_Scope:_ `billing:read`

#### `PATCH /v1/billing/wallet/auto-recharge` — Set auto-recharge

Configure automatic wallet top-up when the balance drops below a threshold. Returns the updated wallet state.

_Scope:_ `billing:write`

_Request body:_

```json
{ "enabled": true, "threshold_usd_cents": 500, "amount_usd_cents": 2000 }
```

### Support tickets

#### `GET /v1/tickets` — List tickets

List support tickets.

_Scope:_ `tickets:read`

#### `GET /v1/tickets/:id` — Get ticket

Ticket detail with the message thread.

_Scope:_ `tickets:read`

#### `POST /v1/tickets` — Open ticket

Open a support ticket. Honours Idempotency-Key.

_Scope:_ `tickets:write`

_Request body:_

```json
{ "subject": "Need help", "message": "…", "department": "technical", "priority": "medium" }
```

#### `POST /v1/tickets/:id/reply` — Reply to ticket

Post a customer reply on a ticket.

_Scope:_ `tickets:write`

_Request body:_

```json
{ "body": "Thanks, that worked." }
```

#### `POST /v1/tickets/:id/close` — Close ticket

Close the ticket.

_Scope:_ `tickets:write`

### Webhooks

#### `GET /v1/webhooks` — List webhooks

List webhook subscriptions.

_Scope:_ `webhooks:read`

#### `POST /v1/webhooks` — Create webhook

Subscribe a URL to events. Secret returned ONCE.

_Scope:_ `webhooks:write`

_Request body:_

```json
{ "url": "https://example.com/hooks", "events": ["*"], "description": "prod" }
```

#### `GET /v1/webhooks/:id` — Get webhook

Webhook subscription detail (secret masked).

_Scope:_ `webhooks:read`

#### `PATCH /v1/webhooks/:id` — Update webhook

Change url, events, description, or pause/resume (isActive).

_Scope:_ `webhooks:write`

#### `DELETE /v1/webhooks/:id` — Delete webhook

Delete a subscription.

_Scope:_ `webhooks:write`

#### `POST /v1/webhooks/:id/rotate-secret` — Rotate secret

Issue a fresh signing secret (returned ONCE). Old secret stops immediately.

_Scope:_ `webhooks:write`

#### `GET /v1/webhooks/:id/deliveries` — Delivery log

Recent delivery attempts. Query: limit.

_Scope:_ `webhooks:read`

#### `POST /v1/webhooks/:id/deliveries/:deliveryId/redeliver` — Redeliver

Re-queue a past delivery for another attempt.

_Scope:_ `webhooks:write`

## Webhooks

Each delivery is a POST with an HMAC-SHA256 signature header `X-Sunucu-Signature: t=<ts>,v1=<hex>`, computed over `"<ts>." + raw_body` with your subscription secret. Other headers: `X-Sunucu-Event`, `X-Sunucu-Delivery`. Failed deliveries retry with exponential backoff (1m, 5m, 15m, 1h, 6h).

| Event | Description |
|---|---|
| `server.created` | A server finished provisioning. Payload: serverId, status, label. |
| `server.power.changed` | A power action ran. Payload: serverId, action (start/stop/reboot). |
| `server.resized` | A server changed plan (vCPU/RAM resize). Payload: serverId, productId, vcpu, ramMb. |
| `server.reinstalled` | A reinstall ran. Payload: serverId, os, osTemplate. |
| `server.ptr.changed` | A reverse-DNS (PTR) record was set or cleared. Payload: serverId, ip, ptr (null when cleared). |
| `server.terminated` | A server was terminated. Payload: serverId. |
| `server.suspended` | A server was suspended (e.g. expiry). Payload: serverId, reason. |
| `hosting.created` | A web-hosting account finished provisioning. Payload: hostingId, domain, status. |
| `invoice.created` | A new invoice was issued (any source — order, renewal, admin). Payload: invoiceId, invoiceNumber, status, totalUsdCents, currency. |
| `invoice.paid` | An invoice transitioned to paid (card, PayPal, crypto, or wallet). Payload: invoiceId, invoiceNumber, totalUsdCents, currency. |
| `wallet.deposit.received` | A wallet top-up was credited. Payload: amountUsdCents, gateway, transactionId. |
| `domain.registered` | A domain registration completed (post-payment). Payload: domainId, domain, periodYears, expiresAt. |
| `ticket.created` | A support ticket was opened. Payload: ticketId, ticketNumber, subject, status, priority. |
| `ticket.replied` | Support staff replied to your ticket. Payload: ticketId, ticketNumber, subject, status. |

## Errors

| Code | Meaning |
|---|---|
| 400 Bad Request | Missing or invalid request body parameters. |
| 401 Unauthorized | Missing, invalid, or expired API key. |
| 403 Forbidden | API key lacks the required scope for this action. |
| 404 Not Found | The resource does not exist or belongs to another account. |
| 429 Too Many Requests | Per-key rate limit exceeded (120 req/min). See the X-RateLimit-Limit / -Remaining / -Reset and Retry-After response headers. |
| 500 Internal Server Error | Unexpected server error. If persistent, contact support. |

## Changelog

### v1.15 — 2026-08-16 (latest)

- **new:** Server add-ons on the API — `GET /v1/servers/:id/addons` lists what this server's plan offers (extra IPs, /24 class blocks, the **SEO IP Pack**, backups) with the prorated cost of buying today, `POST /v1/servers/:id/addons` attaches one (debits your balance immediately, then renews with the server), and `DELETE /v1/servers/:id/addons/:addonId` cancels one (no refund; the price drops from the next renewal). Only one add-on per type may be active. Reads carry servers:read, the writes carry servers:write. Also in the dashboard and as MCP tools.

### v1.14 — 2026-08-11

- **new:** `GET /v1/mail/setup` now returns a `client` block — the host, ports and security to enter in Outlook, Thunderbird or a phone. ⚑ Use `client.host`, NOT `mail.<your domain>`: both reach the same server, but only `client.host` is on its TLS certificate, so the other one makes mail programs show a security warning.
- **improved:** `GET /v1/mail/setup` now takes an optional `?domain=` and returns the records composed for that zone (`records[]`, plus `mx_host`), built from the same definition the provisioner writes — so what you are told to add is what we create. It also returns `webmail_url`, where a mailbox is read in a browser.
- **removed:** `GET /v1/mail/setup` no longer returns a fixed `mx_host` when no domain is given. The MX for your domain is `mail.<your domain>`, not a shared host: pass `?domain=` to get it, or build it yourself and point `mail.<your domain>` at `mail_ip`.

### v1.13 — 2026-07-08

- **new:** New webhook event `server.resized` — fires when a server changes plan (vCPU/RAM resize). Payload: serverId, productId, vcpu, ramMb.

### v1.12 — 2026-07-08

- **new:** Dashboard SSO for servers — `POST /v1/servers/:id/sso` returns a short-lived URL that logs into the dashboard for that server (scope servers:read). Also an MCP tool.

### v1.11 — 2026-07-08

- **new:** Wallet auto-recharge — `PATCH /v1/billing/wallet/auto-recharge` configures automatic top-up when your balance drops below a threshold. New opt-in scope `billing:write` (not in defaults).

### v1.10 — 2026-07-08

- **new:** Full hosting control panel on the API — file manager (list/read/write/delete/upload/download/mkdir/rename), MySQL databases, backups (create/restore/download), cron, PHP version, SSL re-issue, protected directories, WAF, browser-SSH terminal, and git deploy. All under one new opt-in scope `hosting:manage` — powerful (file + shell access), so it is NOT granted by default; add it explicitly when minting a key. Also available as MCP tools.

### v1.9 — 2026-07-08

- **new:** Email hosting on the API — the full mail panel is now scriptable: `GET/POST/DELETE /v1/mail/domains`, `GET/POST/DELETE /v1/mail/mailboxes` (+ `PATCH /v1/mail/mailboxes/:id/password`), `GET/POST/DELETE /v1/mail/aliases`, and `GET /v1/mail/setup` for the MX/SPF/DMARC records. New scopes: `mail:read` (in defaults) and `mail:write`. Also available as MCP tools.

### v1.8 — 2026-07-08

- **new:** Server resize — `GET /v1/servers/:id/plan-options` lists the plans a server can switch to (same family, same disk), and `POST /v1/servers/:id/change-plan` moves it to one, applying a new vCPU/RAM allocation. The server reboots (~1 min) and disk never changes. Only the recurring price changes — no proration on an up-switch, no credit on a down-switch. Reads carry servers:read, the switch carries servers:write. Powers the new Cloud Router line (move between Router S/M/L). Also in the dashboard and as MCP tools.

### v1.7 — 2026-06-11

- **new:** Reverse DNS (PTR) management — `GET /v1/servers/:id/ips` lists every IP on a server with its current PTR; `PUT`/`DELETE /v1/servers/:id/ips/:ip/ptr` set or clear the record. Reads carry servers:read, writes servers:write. Also available in the dashboard (Operations → Ters DNS) and as MCP tools.
- **new:** Webhook event `server.ptr.changed` — fires when a PTR record is set or cleared (from the dashboard, API, or MCP). Payload: serverId, ip, ptr (null when cleared).

### v1.6 — 2026-06-03

- **new:** Two more webhook events: `invoice.created` (fires for any new invoice — order, renewal, or admin) and `domain.registered` (a registration completed after payment). The catalogue is now 13 events.
- **improved:** Connect-AI (MCP) wizard on the API Keys page — pick your client (Claude Code / Desktop / Cursor / VS Code) and copy a ready-made config.

### v1.5 — 2026-06-03

- **new:** OAuth 2.0 device-code flow (RFC 8628). Connect AI tools by browser-approval instead of pasting a key: the client opens sunucu.com/oauth/device, you approve the requested scopes, and it receives a scoped `snc_at_` access token (+ single-use `snc_rt_` refresh, 90-day). Endpoints under `/oauth/*` with AS metadata at `/.well-known/oauth-authorization-server`. Revoke connected apps anytime from the API Keys page.

### v1.4 — 2026-06-03

- **new:** Model Context Protocol (MCP) server — connect Claude and other AI tools directly to your account at `https://api.sunucu.com/mcp` (Streamable HTTP) using your `snc_` API key as a Bearer token. 37 tools across servers, hosting, domains, billing, tickets and webhooks, scope-gated by the key.

### v1.3 — 2026-06-03

- **new:** Per-key rate limiting — 120 requests/minute per API key, with `X-RateLimit-Limit` / `X-RateLimit-Remaining` / `X-RateLimit-Reset` headers on every response and `Retry-After` on a 429.
- **new:** Four more webhook events: `server.suspended`, `hosting.created`, `invoice.paid` (fires for card / PayPal / crypto / wallet payments alike), and `wallet.deposit.received`.

### v1.2 — 2026-06-03

- **new:** Webhooks — subscribe a URL to account events and receive signed (HMAC-SHA256) POSTs. Eight endpoints under `/v1/webhooks` behind the new `webhooks:read` / `webhooks:write` scopes: list, create, get, update (incl. pause/resume), delete, rotate-secret, delivery log, and redeliver. Failed deliveries retry with exponential backoff (1m→6h).
- **new:** Webhook events: server.created, server.power.changed, server.reinstalled, server.terminated, ticket.created, ticket.replied.

### v1.1 — 2026-06-03

- **new:** Write endpoints. servers:write — power start/stop/reboot, password reset, create/delete snapshots. servers:destroy (opt-in, not in defaults) — reinstall, snapshot revert, terminate. hosting:write — set/verify/remove custom domain. domains:write — update auto-renew / lock / WHOIS / nameservers. tickets:write — open, reply, close.
- **improved:** Idempotency-Key header on snapshot-create, reinstall, and ticket-create dedups retried requests for 24h.

### v1.0 — 2026-06-03

- **new:** Public API launch — read-only endpoints for account, servers (incl. live stats & snapshots), hosting, domains, billing (invoices & wallet) and support tickets. Authenticate with an `snc_…` API key minted from the dashboard.
