Developer API
Manage your servers, hosting, domains, billing and support tickets programmatically. Every endpoint is protected by a scope-gated API key.
https://api.sunucu.com/v1Authorization: Bearer snc_…AI connection (MCP)
Connect Claude and other MCP-capable tools straight to your account. Uses your API key as a Bearer token — every tool is limited to the key’s scopes.
https://api.sunucu.com/mcpclaude mcp add --transport http sunucu https://api.sunucu.com/mcp \ --header "Authorization: Bearer snc_…"
85 tools across servers (incl. reverse DNS), capacity pools, hosting, domains, billing, tickets and webhooks. Create an API key →
OAuth-capable clients can connect without pasting a key — you approve in the browser (RFC 8628 device-code flow).
Local/stdio: SUNUCU_API_KEY=snc_… npx -y @otwa/sunucu-mcp
Endpoints
Account
/v1/accountaccount:readReturns the authenticated account profile.
Servers
/v1/serversservers:readList every server on the account.
/v1/servers/:idservers:readServer detail (backbone-scrubbed — no upstream provider, no provisioning logs).
/v1/servers/:id/statsservers:readLive CPU / memory / network / disk usage.
/v1/servers/:id/snapshotsservers:readDisk snapshots (restore points) for the server.
/v1/servers/:id/ipsservers:readEvery 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.
/v1/servers/:id/plan-optionsservers:readPlans 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.
/v1/servers/:id/power/:actionservers:writePower the server start, stop, or reboot. `:action` ∈ {start,stop,reboot}.
/v1/servers/:id/ssoservers:readIssue a short-lived URL that logs into the dashboard for this server.
{ "next": "/optional/path" }/v1/servers/:id/change-planservers:writeSwitch 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.
{ "productId": "..." }/v1/servers/:id/addonsservers:readAdd-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.
/v1/servers/:id/addonsservers:writeAttach 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.
{ "addonId": "seoip7pk" }/v1/servers/:id/addons/:addonIdservers:writeCancel 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.
/v1/servers/:id/snapshotsservers:writeTake a disk snapshot. Honours an optional Idempotency-Key header.
{ "name": "pre-upgrade", "description": "before kernel bump" }/v1/servers/:id/snapshots/:snapshotIdservers:writeRemove a snapshot (non-destructive to the live disk).
/v1/servers/:id/ips/:ip/ptrservers:writePoint the IP's PTR record at a hostname (e.g. `mail.example.com`). Idempotent upsert.
{ "hostname": "mail.example.com" }/v1/servers/:id/ips/:ip/ptrservers:writeRemove the PTR record for the IP.
/v1/servers/:id/reinstallservers:destroyDESTRUCTIVE — wipe the disk and rebuild from an OS template. Honours Idempotency-Key.
{ "osTemplate": "ubuntu-22.04", "os": "ubuntu" }/v1/servers/:id/snapshots/:snapshotId/revertservers:destroyDESTRUCTIVE — roll the live disk back to a snapshot.
/v1/servers/:idservers:destroyDESTRUCTIVE — permanently terminate the server.
Capacity pools
/v1/pools/catalogueservers:readCapacity-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.
/v1/pools/quoteservers:readMonthly 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.
{ "productId": "...", "vcpu": 16, "ram2gb": 16, "disk100": 10, "ip16": 1 }/v1/poolsservers:readEvery capacity pool on the account, with its quotas, status, monthly price and renewal date.
/v1/pools/:idservers:readOne 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.
/v1/poolsservers:writeBuys 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.
{ "productId": "...", "label": "prod-cluster", "vcpu": 16, "ram2gb": 16, "disk100": 10, "ip16": 1 }/v1/pools/:id/resize-quoteservers:readPrices 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.
{ "vcpu": 32, "ram2gb": 32, "disk100": 20, "ip16": 2 }/v1/pools/:idservers:writeChanges 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.
{ "vcpu": 32, "ram2gb": 32, "disk100": 20, "ip16": 2 }/v1/pools/:id/serversservers:writeCreates 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.
{ "productId": "...", "label": "web-1", "os": "ubuntu", "osTemplate": "ubuntu-24.04", "ipCount": 1 }/v1/pools/:id/ipsservers:readEvery 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`.
/v1/pools/:id/ips/applyservers:writeAssign, 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.
{ "changes": [ { "ip": "203.0.113.10", "serverId": "uuid" }, { "ip": "203.0.113.11", "serverId": null } ] }/v1/pools/:idservers:destroyDESTRUCTIVE — 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.
Hosting
/v1/hostinghosting:readList web-hosting accounts.
/v1/hosting/:idhosting:readHosting account detail (connection info, backbone-scrubbed).
/v1/hosting/:id/custom-domainhosting:writeAttach a custom domain to a hosting account.
{ "domain": "example.com" }/v1/hosting/:id/custom-domain/verifyhosting:writeRe-check DNS and attach the custom domain once it points to us.
/v1/hosting/:id/custom-domainhosting:writeDetach the custom domain from the hosting account.
Hosting control panel
/v1/hosting/:id/statshosting:manageDisk usage, inode count, bandwidth, and mailbox count for the account.
/v1/hosting/:id/logshosting:manageTail the access or error log. Query: `kind` ∈ {access,error}, `lines`.
/v1/hosting/:id/cert/retryhosting:manageRetry the Let's Encrypt certificate issue now.
/v1/hosting/:id/php-versionhosting:manageSwitch the account's PHP-FPM version.
{ "php_version": "8.3" }/v1/hosting/:id/cronhosting:manageRead the crontab (header + jobs).
/v1/hosting/:id/cronhosting:manageReplace the crontab.
{ "jobs": [ { "schedule": "0 3 * * *", "command": "php cron.php" } ] }/v1/hosting/:id/protected-dirshosting:managePassword-protected directories (htpasswd).
/v1/hosting/:id/protected-dirshosting:manageAdd or update a password-protected directory.
{ "path": "/admin", "basic_user": "u", "password": "…" }/v1/hosting/:id/protected-dirshosting:manageRemove protection. Query: `path`.
/v1/hosting/:id/wafhosting:manageModSecurity WAF status for the account.
/v1/hosting/:id/waf/accesshosting:manageWhether temporary WAF-log access is active.
/v1/hosting/:id/waf/accesshosting:manageRequest temporary access to WAF logs.
/v1/hosting/:id/ssh-terminal/accesshosting:manageWhether browser-SSH terminal access is enabled.
/v1/hosting/:id/ssh-terminal/accesshosting:manageEnable browser-SSH terminal access.
/v1/hosting/:id/ssh-terminal/launchhosting:manageStart a browser-SSH session; returns a session URL/token.
/v1/hosting/:id/ssh-terminal/stophosting:manageStop the browser-SSH session.
/v1/hosting/:id/githosting:manageGit-deploy status for the account.
/v1/hosting/:id/git/deploy-keyhosting:manageThe SSH deploy key to add to your repo.
/v1/hosting/:id/git/webhookhosting:manageThe push-to-deploy webhook URL/secret.
/v1/hosting/:id/git/webhookhosting:manageEnable push-to-deploy.
/v1/hosting/:id/git/webhookhosting:manageDisable push-to-deploy.
/v1/hosting/:id/git/deployhosting:manageClone/deploy a repo into the site.
{ "repo_url": "git@…", "branch": "main", "subdir": "" }/v1/hosting/:id/git/pullhosting:managePull the latest commit for the deployed repo.
/v1/hosting/:id/githosting:manageDisconnect git deploy from the site.
/v1/hosting/:id/fileshosting:manageList a directory. Query: `path` (default /public_html).
/v1/hosting/:id/files/readhosting:manageRead a text file's contents. Query: `path`.
/v1/hosting/:id/fileshosting:manageCreate or overwrite a text file.
{ "path": "/public_html/x.txt", "content": "…" }/v1/hosting/:id/fileshosting:manageDelete a file or directory. Query: `path`, `recursive`.
/v1/hosting/:id/files/downloadhosting:manageStream a file as an attachment. Query: `path`.
/v1/hosting/:id/files/uploadhosting:manageUpload a file (multipart form field `file`). Query: `path`.
/v1/hosting/:id/files/mkdirhosting:manageCreate a directory.
{ "path": "/public_html/new" }/v1/hosting/:id/files/renamehosting:manageRename or move a file/directory.
{ "from": "/a", "to": "/b" }/v1/hosting/:id/backupshosting:manageSite backups (restore points).
/v1/hosting/:id/backupshosting:manageCreate a new site backup.
/v1/hosting/:id/backups/:bidhosting:manageDelete a backup.
/v1/hosting/:id/backups/:bid/restorehosting:manageRestore the site from a backup.
/v1/hosting/:id/backups/:bid/downloadhosting:manageStream a backup archive (gzip).
/v1/hosting/:id/visitor-statshosting:manageVisitor statistics. Query: `period` ∈ {24h,7d,30d}.
/v1/hosting/:id/databaseshosting:manageExtra MySQL databases on the account.
/v1/hosting/:id/databaseshosting:manageCreate an extra MySQL database.
{ "suffix": "wp2" }/v1/hosting/:id/databases/:namehosting:manageDelete an extra MySQL database.
/v1/mail/setupmail:readThe 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.
/v1/mail/domainsmail:readEvery mail domain on the account.
/v1/mail/domainsmail:writeEnable email hosting for a domain.
{ "domain": "example.com" }/v1/mail/domains/:idmail:writeDisable email hosting for a domain (removes its mailboxes and aliases).
/v1/mail/domains/:id/mailboxesmail:readMailboxes under one mail domain.
/v1/mail/domains/:id/aliasesmail:readForwarding aliases under one mail domain.
/v1/mail/mailboxesmail:readEvery mailbox across all your mail domains.
/v1/mail/mailboxesmail:writeCreate a mailbox on a mail domain.
{ "domain_id": 12, "local_part": "info", "password": "…", "quota_mb": 2048 }/v1/mail/mailboxes/:id/passwordmail:writeSet a new password for a mailbox.
{ "password": "…" }/v1/mail/mailboxes/:idmail:writePermanently delete a mailbox and its mail.
/v1/mail/aliasesmail:writeCreate a forwarding alias (source → destination).
{ "domain_id": 12, "source_local": "sales", "destination": "info@example.com" }/v1/mail/aliases/:idmail:writeRemove a forwarding alias.
Domains
/v1/domainsdomains:readList registered domains.
/v1/domains/:iddomains:readDomain detail.
/v1/domains/:iddomains:writeUpdate auto-renew, transfer lock, WHOIS privacy, or nameservers.
{ "auto_renew": true, "transfer_lock": true, "nameservers": ["ns1.example.com","ns2.example.com"] }Billing
/v1/billing/invoicesbilling:readPaginated invoice list. Query: page, limit.
/v1/billing/invoices/:idbilling:readSingle invoice with line items.
/v1/billing/walletbilling:readPrepaid wallet balance and state.
/v1/billing/wallet/transactionsbilling:readRecent wallet transactions. Query: limit.
/v1/billing/wallet/auto-rechargebilling:writeConfigure automatic wallet top-up when the balance drops below a threshold. Returns the updated wallet state.
{ "enabled": true, "threshold_usd_cents": 500, "amount_usd_cents": 2000 }Support tickets
/v1/ticketstickets:readList support tickets.
/v1/tickets/:idtickets:readTicket detail with the message thread.
/v1/ticketstickets:writeOpen a support ticket. Honours Idempotency-Key.
{ "subject": "Need help", "message": "…", "department": "technical", "priority": "medium" }/v1/tickets/:id/replytickets:writePost a customer reply on a ticket.
{ "body": "Thanks, that worked." }/v1/tickets/:id/closetickets:writeClose the ticket.
Webhooks
/v1/webhookswebhooks:readList webhook subscriptions.
/v1/webhookswebhooks:writeSubscribe a URL to events. Secret returned ONCE.
{ "url": "https://example.com/hooks", "events": ["*"], "description": "prod" }/v1/webhooks/:idwebhooks:readWebhook subscription detail (secret masked).
/v1/webhooks/:idwebhooks:writeChange url, events, description, or pause/resume (isActive).
/v1/webhooks/:idwebhooks:writeDelete a subscription.
/v1/webhooks/:id/rotate-secretwebhooks:writeIssue a fresh signing secret (returned ONCE). Old secret stops immediately.
/v1/webhooks/:id/deliverieswebhooks:readRecent delivery attempts. Query: limit.
/v1/webhooks/:id/deliveries/:deliveryId/redeliverwebhooks:writeRe-queue a past delivery for another attempt.
Webhooks
When an event fires we POST a signed payload to your URL. The signature is HMAC-SHA256: X-Sunucu-Signature: t=<ts>,v1=HMAC(secret, "<ts>." + body). Failed deliveries retry with exponential backoff (1m → 6h).
server.createdA server finished provisioning. Payload: serverId, status, label.
server.power.changedA power action ran. Payload: serverId, action (start/stop/reboot).
server.resizedA server changed plan (vCPU/RAM resize). Payload: serverId, productId, vcpu, ramMb.
server.reinstalledA reinstall ran. Payload: serverId, os, osTemplate.
server.ptr.changedA reverse-DNS (PTR) record was set or cleared. Payload: serverId, ip, ptr (null when cleared).
server.terminatedA server was terminated. Payload: serverId.
server.suspendedA server was suspended (e.g. expiry). Payload: serverId, reason.
hosting.createdA web-hosting account finished provisioning. Payload: hostingId, domain, status.
invoice.createdA new invoice was issued (any source — order, renewal, admin). Payload: invoiceId, invoiceNumber, status, totalUsdCents, currency.
invoice.paidAn invoice transitioned to paid (card, PayPal, crypto, or wallet). Payload: invoiceId, invoiceNumber, totalUsdCents, currency.
wallet.deposit.receivedA wallet top-up was credited. Payload: amountUsdCents, gateway, transactionId.
domain.registeredA domain registration completed (post-payment). Payload: domainId, domain, periodYears, expiresAt.
ticket.createdA support ticket was opened. Payload: ticketId, ticketNumber, subject, status, priority.
ticket.repliedSupport staff replied to your ticket. Payload: ticketId, ticketNumber, subject, status.
Error codes
400401403404429500Changelog
- newServer add-ons on the API —
GET /v1/servers/:id/addonslists 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/addonsattaches one (debits your balance immediately, then renews with the server), andDELETE /v1/servers/:id/addons/:addonIdcancels 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.
- new
GET /v1/mail/setupnow returns aclientblock — the host, ports and security to enter in Outlook, Thunderbird or a phone. ⚑ Useclient.host, NOTmail.: both reach the same server, but onlyclient.hostis on its TLS certificate, so the other one makes mail programs show a security warning. - improved
GET /v1/mail/setupnow takes an optional?domain=and returns the records composed for that zone (records[], plusmx_host), built from the same definition the provisioner writes — so what you are told to add is what we create. It also returnswebmail_url, where a mailbox is read in a browser. - removed
GET /v1/mail/setupno longer returns a fixedmx_hostwhen no domain is given. The MX for your domain ismail., not a shared host: pass?domain=to get it, or build it yourself and pointmail.atmail_ip.
- newNew webhook event
server.resized— fires when a server changes plan (vCPU/RAM resize). Payload: serverId, productId, vcpu, ramMb.
- newDashboard SSO for servers —
POST /v1/servers/:id/ssoreturns a short-lived URL that logs into the dashboard for that server (scope servers:read). Also an MCP tool.
- newWallet auto-recharge —
PATCH /v1/billing/wallet/auto-rechargeconfigures automatic top-up when your balance drops below a threshold. New opt-in scopebilling:write(not in defaults).
- newFull 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.
- newEmail 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, andGET /v1/mail/setupfor the MX/SPF/DMARC records. New scopes:mail:read(in defaults) andmail:write. Also available as MCP tools.
- newServer resize —
GET /v1/servers/:id/plan-optionslists the plans a server can switch to (same family, same disk), andPOST /v1/servers/:id/change-planmoves 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.
- newReverse DNS (PTR) management —
GET /v1/servers/:id/ipslists every IP on a server with its current PTR;PUT/DELETE /v1/servers/:id/ips/:ip/ptrset or clear the record. Reads carry servers:read, writes servers:write. Also available in the dashboard (Operations → Ters DNS) and as MCP tools. - newWebhook 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).
- newTwo more webhook events:
invoice.created(fires for any new invoice — order, renewal, or admin) anddomain.registered(a registration completed after payment). The catalogue is now 13 events. - improvedConnect-AI (MCP) wizard on the API Keys page — pick your client (Claude Code / Desktop / Cursor / VS Code) and copy a ready-made config.
- newOAuth 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-usesnc_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.
- newModel Context Protocol (MCP) server — connect Claude and other AI tools directly to your account at
https://api.sunucu.com/mcp(Streamable HTTP) using yoursnc_API key as a Bearer token. 37 tools across servers, hosting, domains, billing, tickets and webhooks, scope-gated by the key.
- newPer-key rate limiting — 120 requests/minute per API key, with
X-RateLimit-Limit/X-RateLimit-Remaining/X-RateLimit-Resetheaders on every response andRetry-Afteron a 429. - newFour more webhook events:
server.suspended,hosting.created,invoice.paid(fires for card / PayPal / crypto / wallet payments alike), andwallet.deposit.received.
- newWebhooks — subscribe a URL to account events and receive signed (HMAC-SHA256) POSTs. Eight endpoints under
/v1/webhooksbehind the newwebhooks:read/webhooks:writescopes: list, create, get, update (incl. pause/resume), delete, rotate-secret, delivery log, and redeliver. Failed deliveries retry with exponential backoff (1m→6h). - newWebhook events: server.created, server.power.changed, server.reinstalled, server.terminated, ticket.created, ticket.replied.
- newWrite 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.
- improvedIdempotency-Key header on snapshot-create, reinstall, and ticket-create dedups retried requests for 24h.
- newPublic 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.