Skip to content
Core Cloud cloud.core.gen.tr
0 Your cart

For developers

C2 Cloud API

Everything your machines, volumes, networks, DNS and subscriptions can be asked or told over HTTP. This page is generated from the same description a client generator reads, so it cannot say something the API does not do.

Base URL
https://cloud.core.gen.tr/api/v1
Version
1.0.0
Operations
100

01 Overview

What this API is

The customer API for the cloud at https://cloud.core.gen.tr.

Authenticate with a personal access token, created under Settings → API Tokens in the panel, sent as Authorization: Bearer <token>.

Every token carries a set of abilities. A request whose token lacks the ability an endpoint requires is rejected with 403, regardless of what the token's owner is otherwise allowed to do.

Errors are RFC 9457 problem details with the media type application/problem+json.

The description this page is generated from is published as well, so you can generate a client rather than write one: OpenAPI, as YAML · OpenAPI, as JSON

Use it from an assistant

Everything below is HTTP, for a program you write. If what you want instead is to ask an assistant in your own words — Claude Code, Claude Desktop, or the assistant already in your panel — the same cloud is reachable over the Model Context Protocol, with the same tokens and the same checks.

Use it from Claude

02 Authentication

A token, and what it may reach

Create a personal access token in the panel under Settings → API Tokens, and send it on every request:

curl 'https://cloud.core.gen.tr/api/v1/me' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

A token reaches the smaller of two things

An ability says what the token was created to do. Your account capability says what you are still allowed to do today. Every request is checked against both, so a token can never grant its holder something their account does not already permit — and a member whose access was narrowed after they created a token cannot keep working at the old level through it.

Either refusal answers 403, with the reason in the problem document's detail. Ask GET /me for the abilities the presented token actually carries rather than probing endpoints and collecting refusals.

The abilities a token may carry

Ability What it permits Account capability
cloud:read Read your cloud — instances, volumes and their snapshots, ISOs, templates, firewall rules, public IP addresses, VPN and affinity groups, the offerings behind them, and your usage records. Also reveals an instance's saved password. cloud: view
cloud:write Start, stop, restart and rename your machines, reset a password, open a console, attach and detach ISOs and volumes, take disk snapshots, and manage firewall rules, VPN users and affinity groups. cloud: manage
dns:read Read your DNS zones and every record in them. dns: view
dns:write Create and delete DNS zones, add, change and remove records, and set the reverse DNS record of a public IP address. dns: manage
billing:read Read your subscriptions, orders, payments, refunds, saved cards, account balance and the product catalogue. Reading only — a token can never write a billing record. billing: view
order:write Places orders and cancels subscriptions. Ordering spends money — it charges your saved card or your account balance with no further confirmation. Grant it only to a client you trust with your money. shop: manage
account:read Read your own profile, contact details and the abilities of the token being used. account: view
account:write Change your own profile and contact details. No endpoint serves it yet. account: manage
tickets:read Read your support tickets and the replies on them. tickets: view
tickets:write Open support tickets, reply to them and close them — each is sent to our support staff in your name. tickets: manage
ai:read Read your AI gateway keys, their limits and what they have spent. No endpoint serves it yet. ai: view
ai:write Change the limits on an AI gateway key and revoke one that leaked. Creating a key stays in the panel. No endpoint serves it yet. ai: manage
admin:read admin Read any customer's account, their machines, DNS zones, subscriptions and the audit records. Also requires the admin role — a token never grants authority its owner lacks. —
admin:write admin Start, stop and restart any customer's machine and attach or detach an ISO on it, write news, FAQ and legal drafts, answer and assign tickets, and manage invitations, support assignments and retention holds. Publishing, credit grants, lockouts and every other outward act it asks for are only put into the approval queue, where an administrator decides them in the panel. Also requires the admin role — a token never grants authority its owner lacks. —
support:read support Read the accounts, resources and audit records of the customers assigned to you. Also requires the support role, and passes the same per-assignment checks as the panel. —
support:write support Act on the customers assigned to you. Also requires the support role, and the same per-assignment checks as the panel. No endpoint serves it yet. —

03 Conventions

The things every endpoint does the same way

Requests and responses

Send JSON and ask for JSON. A single resource comes back under a data key; a collection comes back under data with meta and links beside it. Every write requires the email address on the account to be verified, exactly as the panel does.

Pagination

Collections take page and per_page. per_page defaults to 25 and anything above 100 is reduced to 100. meta carries the totals and links carries the neighbouring pages.

Rate limits

Budgets are counted per token, not per account, so one scripted integration cannot starve another. Reads are 120 a minute, writes 60, staff reads of another customer 30, ordering 5, and a reconciling read (refresh=true) 10 — that last one reaches the cloud itself, so it must not be used for polling.

Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset, the last of these in seconds. A refusal is 429 with Retry-After.

Retrying safely

Ordering requires an Idempotency-Key header you choose. The key is claimed before the order runs, so a retry that arrives while the first attempt is still going gets 409 rather than a second charge, and a repeat of a finished request replays the first response instead of ordering again.

Errors

One error shape for the whole API — RFC 9457 problem details, served as application/problem+json — so nothing has to branch on which of two formats came back. Branch on type, which is one stable URI per status code. Server-side failures never carry internal detail in production.

Field Type Description
type string A stable URI identifying the error class. One per status code.
title string
status integer
detail string A human-readable explanation for this specific occurrence. For 5xx responses this is a fixed, non-specific string in production — internal detail is logged, never served.
instance string The path of the request that failed.
errors Optional object Present only on 422. Field name to list of messages.
{
    "type": "https://cloud.core.gen.tr/api/errors/validation-failed",
    "title": "Validation failed",
    "status": 422,
    "detail": "The name field is required.",
    "instance": "/api/v1/me"
}

Operations

Identity

Who the presented token belongs to.

GET /me #

The identity behind the presented token

account:read api.read

Returns the authenticated user together with the abilities carried by the token used for this request. Call this to discover what a token may do instead of probing endpoints and collecting 403s.

Responses

  • 200 The authenticated user.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/me' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Compute

Virtual machines.

GET /instances #

List virtual machines

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile against the provider first — that variant is rate-limited far more tightly and must not be used for polling.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of virtual machines.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/instances' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /instances/{instance} #

Read one virtual machine

cloud:read api.read

Parameters

Name In Type Description
instance Required path integer
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 The virtual machine.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/instances/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
PATCH /instances/{instance} #

Rename a virtual machine

cloud:write api.read api.write

The only mutable attribute. Resizing is a billing event (POST /orders), and lifecycle changes are actions.

Parameters

Name In Type Description
instance Required path integer

Request body Required

Field Type Description
name Required string

Responses

  • 200 The updated virtual machine.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X PATCH 'https://cloud.core.gen.tr/api/v1/instances/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "string"
}'
POST /instances/{instance}/actions/start #

Start a virtual machine

cloud:write api.read api.write

Idempotent: starting an already-running machine returns 200 immediately without contacting the cloud. Terraform and similar tools reconcile desired state rather than issue commands, so asking for a state the machine is already in must never error.

Parameters

Name In Type Description
instance Required path integer

Responses

  • 200 The virtual machine, started (or already running).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/instances/1/actions/start' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /instances/{instance}/actions/stop #

Stop a virtual machine

cloud:write api.read api.write

Idempotent: stopping an already-stopped machine returns 200 immediately without contacting the cloud, for the same reason as start.

Parameters

Name In Type Description
instance Required path integer

Responses

  • 200 The virtual machine, stopped (or already stopped).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/instances/1/actions/stop' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /instances/{instance}/actions/restart #

Restart a virtual machine

cloud:write api.read api.write

Not idempotent — unlike start/stop there is no target state to compare against, so this always reaches the cloud regardless of the machine's current state.

Parameters

Name In Type Description
instance Required path integer

Responses

  • 200 The virtual machine, restarted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/instances/1/actions/restart' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /instances/{instance}/actions/reset-password #

Reset a virtual machine's password

cloud:write api.read api.write

NOT idempotent: every call generates and stores a brand new password, replacing whatever was there before. Fetch the result from GET /instances/{instance}/password afterwards, or from this response's data — the password itself is never included here (see Instance).

Parameters

Name In Type Description
instance Required path integer

Responses

  • 200 The virtual machine, after the password reset.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/instances/1/actions/reset-password' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /instances/{instance}/password #

Read a virtual machine's password

cloud:read api.read

Database-backed; never contacts the cloud. Returns null rather than 403 when the owning subscription is locked and the caller is not staff — the machine is visible, its password just is not.

Parameters

Name In Type Description
instance Required path integer

Responses

  • 200 The virtual machine's password.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/instances/1/password' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /instances/{instance}/console #

Open a virtual machine console session

cloud:write api.read api.write

Mints a fresh, one-time console session in the cloud on every call — an action against the provider, not a database read, which is why it requires cloud:write rather than cloud:read and is subject to the same rate limit as the lifecycle actions.

Parameters

Name In Type Description
instance Required path integer

Responses

  • 200 A console session URL.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/instances/1/console' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /instances/{instance}/actions/attach-iso #

Attach an ISO to a virtual machine

cloud:write api.read api.write

Idempotent: attaching an ISO already mounted on this instance returns 200 immediately without contacting the cloud.

Parameters

Name In Type Description
instance Required path integer

Request body Required

Field Type Description
iso_id Required integer Must name an ISO visible to the caller (public, or their own). A foreign private or missing id fails validation (422) rather than 404 — the addressed resource is the instance, not the ISO.

Responses

  • 200 The virtual machine, with the ISO attached (or already attached).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/instances/1/actions/attach-iso' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "iso_id": 5
}'
POST /instances/{instance}/actions/detach-iso #

Detach whatever ISO is mounted on a virtual machine

cloud:write api.read api.write

Idempotent: detaching an instance with no ISO attached returns 200 immediately without contacting the cloud.

Parameters

Name In Type Description
instance Required path integer

Responses

  • 200 The virtual machine, with its ISO detached (or already detached).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/instances/1/actions/detach-iso' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Storage

Volumes and ISOs.

GET /volumes #

List volumes

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile against the provider first — that variant is rate-limited far more tightly and must not be used for polling.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of volumes.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/volumes' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /volumes/{volume} #

Read one volume

cloud:read api.read

Parameters

Name In Type Description
volume Required path integer
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 The volume.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/volumes/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
PATCH /volumes/{volume} #

Rename a volume

cloud:write api.read api.write

The only mutable attribute. Attach/detach are actions, and resizing is a billing event (POST /orders).

Parameters

Name In Type Description
volume Required path integer

Request body Required

Field Type Description
name Required string

Responses

  • 200 The updated volume.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X PATCH 'https://cloud.core.gen.tr/api/v1/volumes/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "string"
}'
POST /volumes/{volume}/actions/attach #

Attach a volume to one of the caller's instances

cloud:write api.read api.write

Idempotent: attaching a volume already attached to the named instance returns 200 immediately without contacting the cloud.

Parameters

Name In Type Description
volume Required path integer

Request body Required

Field Type Description
instance_id Required integer Must name an instance the caller owns. A foreign or missing id fails validation (422) rather than 404 — the addressed resource is the volume, not the instance.

Responses

  • 200 The volume, attached (or already attached to the named instance).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/volumes/1/actions/attach' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "instance_id": 17
}'
POST /volumes/{volume}/actions/detach #

Detach a volume from whatever instance it is attached to

cloud:write api.read api.write

Idempotent: detaching an already-detached volume returns 200 immediately without contacting the cloud.

Parameters

Name In Type Description
volume Required path integer

Responses

  • 200 The volume, detached (or already detached).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/volumes/1/actions/detach' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /volumes/{volume}/snapshots #

List a volume's snapshots

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile the volume's snapshots against the cloud first — that variant is rate-limited far more tightly, must not be used for polling, and deletes local snapshot records the cloud no longer lists. A snapshot moved to the retention queue (after snapshots were dropped from the disk's plan) is not listed.

Parameters

Name In Type Description
volume Required path integer
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of the volume's snapshots, newest first.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/volumes/1/snapshots' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /volumes/{volume}/snapshots #

Take a manual snapshot of a volume

cloud:write api.read api.write

The snapshot is taken in the background: the response carries it in state Creating. A manual snapshot counts against the snapshot limit. 409 when the limit is reached (only manual snapshots count), when the disk's plan includes no snapshots, or while the disk or its machine is being resized; the body's detail says which. Deleting or restoring a snapshot, and retention schedules, are done in the panel.

Parameters

Name In Type Description
volume Required path integer

Request body Optional

Field Type Description
name Optional string An optional label for the snapshot.

Responses

  • 201 The snapshot, requested and being taken.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/volumes/1/snapshots' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "before-upgrade"
}'
GET /isos #

List ISOs

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile against the provider first — that variant is rate-limited far more tightly and must not be used for polling.

Includes every ISO visible to the caller: their own, plus every ISO the provider marks public.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of ISOs.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/isos' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /isos/{iso} #

Read one ISO

cloud:read api.read

Visible when public, or when it belongs to the caller. A private ISO belonging to another customer 404s, indistinguishable from one that does not exist.

Parameters

Name In Type Description
iso Required path integer
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 The ISO.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/isos/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Catalogue

Templates and offerings — the global, sellable product catalogue every instance and volume is built from. Read-only: see each endpoint's description for why reconciliation is never exposed here.

GET /templates #

List templates

cloud:read api.read

Reconciling the catalogue against the provider is a global administrative operation that can remove sellable products, so it is deliberately not available here. This endpoint always serves what the panel already knows.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of templates.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/templates' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /templates/{template} #

Read one template

cloud:read api.read

Reconciling the catalogue against the provider is a global administrative operation that can remove sellable products, so it is deliberately not available here. This endpoint always serves what the panel already knows.

Parameters

Name In Type Description
template Required path integer

Responses

  • 200 The template.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/templates/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /compute-offerings #

List compute offerings

cloud:read api.read

Reconciling the catalogue against the provider is a global administrative operation that can remove sellable products, so it is deliberately not available here. This endpoint always serves what the panel already knows.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of compute offerings.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/compute-offerings' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /disk-offerings #

List disk offerings

cloud:read api.read

Reconciling the catalogue against the provider is a global administrative operation that can remove sellable products, so it is deliberately not available here. This endpoint always serves what the panel already knows.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of disk offerings.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/disk-offerings' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Network

Firewall rules, public IP addresses, VPN and affinity groups. See each collection endpoint's description for the reconciling sibling it exists to keep off the request path — network resources are where that reconciliation compounds hardest, since reading firewall rules can also reconcile instances.

GET /ingress-rules #

List ingress firewall rules

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile against the provider first — that variant is rate-limited far more tightly and must not be used for polling. It is also the single most destructive read in this API: the reconciling method it calls deletes local firewall rules the provider listing omits, and its create-branch reconciles the caller's instances too, deleting any of those the listing omits as well.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of ingress rules.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/ingress-rules' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /ingress-rules #

Create an ingress firewall rule

cloud:write api.read api.write

Forwards a public IP/port combination to a private port on one of the caller's own instances. public_ip_address must name one of the caller's own stored public IP addresses, and instance_id one of the caller's own instances; either failing to resolve is 422, not 404 — the addressed resource is this collection endpoint.

Request body Required

Field Type Description
public_ip_address Required string
protocol Required string
public_port_start Required integer
public_port_end Required integer Must be greater than or equal to `public_port_start`.
private_port_start Required integer
private_port_end Required integer Must be greater than or equal to `private_port_start`.
instance_id Required integer

Responses

  • 201 The new ingress rule.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/ingress-rules' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "public_ip_address": "203.0.113.10",
    "protocol": "tcp",
    "public_port_start": 1,
    "public_port_end": 1,
    "private_port_start": 1,
    "private_port_end": 1,
    "instance_id": 17
}'
PATCH /ingress-rules/{ingressRule} #

Retarget an ingress firewall rule

cloud:write api.read api.write

The only mutable attributes: which private ports the rule forwards to, and which of the caller's own instances it forwards to. instance_id must name an instance the caller owns; a foreign or missing id fails validation (422), not 404 — the addressed resource is the rule, already resolved and owned before this request runs.

Parameters

Name In Type Description
ingressRule Required path integer

Request body Required

Field Type Description
private_port_start Required integer
private_port_end Required integer Must be greater than or equal to `private_port_start`.
instance_id Required integer

Responses

  • 200 The updated ingress rule.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X PATCH 'https://cloud.core.gen.tr/api/v1/ingress-rules/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "private_port_start": 1,
    "private_port_end": 1,
    "instance_id": 17
}'
DELETE /ingress-rules/{ingressRule} #

Delete an ingress firewall rule

cloud:write api.read api.write

The one documented exception to "every mutation returns the current representation": there is nothing left to return after a delete, so this responds 204 with an empty body rather than 200 with the deleted resource.

Parameters

Name In Type Description
ingressRule Required path integer

Responses

  • 204 The rule was deleted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X DELETE 'https://cloud.core.gen.tr/api/v1/ingress-rules/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /egress-rules #

List egress firewall rules

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile against the provider first — that variant is rate-limited far more tightly and must not be used for polling.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of egress rules.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/egress-rules' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /egress-rules #

Create an egress firewall rule

cloud:write api.read api.write

Permits traffic from source_cidr toward destination_cidr. Both must be well-formed CIDR blocks — a malformed CIDR reaching the cloud from a firewall endpoint is a security defect, not a validation nicety.

Request body Required

Field Type Description
source_cidr Required string
destination_cidr Required string
protocol Required string
port_start Required integer
port_end Required integer Must be greater than or equal to `port_start`.

Responses

  • 201 The new egress rule.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/egress-rules' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "source_cidr": "10.0.0.0/24",
    "destination_cidr": "0.0.0.0/0",
    "protocol": "tcp",
    "port_start": 1,
    "port_end": 1
}'
DELETE /egress-rules/{egressRule} #

Delete an egress firewall rule

cloud:write api.read api.write

The one documented exception to "every mutation returns the current representation": there is nothing left to return after a delete, so this responds 204 with an empty body rather than 200 with the deleted resource.

Parameters

Name In Type Description
egressRule Required path integer

Responses

  • 204 The rule was deleted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X DELETE 'https://cloud.core.gen.tr/api/v1/egress-rules/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /public-ip-addresses #

List public IP addresses

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile against the provider first — that variant is rate-limited far more tightly and must not be used for polling. It deletes local rows the provider listing does not contain.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of public IP addresses.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/public-ip-addresses' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /public-ip-addresses/{publicIPAddress} #

Read a public IP address

cloud:read api.read

Database-backed by default. Pass refresh=true to reconcile the caller's whole set against the provider first, then pick this address out of it — there is no single-address provider lookup — before responding. That variant is rate-limited far more tightly and must not be used for polling, and, like the collection endpoint, deletes local rows the provider listing does not contain.

Parameters

Name In Type Description
publicIPAddress Required path integer
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 The public IP address.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/public-ip-addresses/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
PATCH /public-ip-addresses/{publicIPAddress} #

Set the reverse DNS record for a public IP address

dns:write api.read api.write

Writes a PTR record on the DNS service and the local row; it never touches the cloud, which is why this requires dns:write rather than cloud:write. See DNSUserService::updatePublicIPAddress().

Parameters

Name In Type Description
publicIPAddress Required path integer

Request body Required

Field Type Description
reverse_record Required string A valid DNS hostname.

Responses

  • 200 The updated public IP address.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X PATCH 'https://cloud.core.gen.tr/api/v1/public-ip-addresses/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "reverse_record": "host.example.com"
}'
GET /vpn #

List the caller's VPNs

cloud:read api.read

A collection, not a single object: a customer account may have zero VPNs configured, or in principle more than one. Database-backed by default; pass refresh=true to reconcile against the provider first — that variant is rate-limited far more tightly and must not be used for polling, and deletes local rows the provider listing does not contain.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of VPNs.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/vpn' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /vpn/users #

List VPN users

cloud:read api.read

Database-backed; never contacts the cloud. No refresh parameter — unlike public IP addresses and VPNs, this endpoint has no reconciling sibling exposed over the API.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of VPN users.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/vpn/users' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /vpn/users #

Create a VPN user

cloud:write api.read api.write

Creates a VPN user in the cloud under the caller's account. username must be free of the caller's own VPN users; a name already used by a different customer is not a conflict.

Both fields are validated against the cloud provider's own rule rather than a looser one of ours: each must BEGIN with a letter or a digit, and may then use letters, digits and a small punctuation set — @ . - _ for the username, and @ + = . - _ for the password. A value outside that is 422 here. It used to be accepted and refused by the provider afterwards, which reached the caller as a 502 naming a system they have no access to.

Request body Required

Field Type Description
username Required string
password Required string

Responses

  • 201 The new VPN user.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/vpn/users' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "jdoe",
    "password": "string"
}'
DELETE /vpn/users/{vpnUser} #

Delete a VPN user

cloud:write api.read api.write

The one documented exception to "every mutation returns the current representation": there is nothing left to return after a delete, so this responds 204 with an empty body rather than 200 with the deleted resource.

Parameters

Name In Type Description
vpnUser Required path integer

Responses

  • 204 The VPN user was deleted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X DELETE 'https://cloud.core.gen.tr/api/v1/vpn/users/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /affinity-groups #

List affinity groups

cloud:read api.read

Database-backed; never contacts the cloud. No refresh parameter: this endpoint's reconciling sibling is destructive in a way none of the others in this API are — it deletes both local affinity groups the provider listing omits and instance membership rows alongside them — and is never exposed here.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of affinity groups.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/affinity-groups' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /affinity-groups #

Create an affinity group

cloud:write api.read api.write

name must be unique across every customer's affinity groups — the provider does not namespace affinity group names per account. Each instances.* must name one of the caller's own instances; a foreign or missing id is 422, not 404.

Request body Required

Field Type Description
name Required string
description Optional string
affinity_type Required string
instances Optional array of integer

Responses

  • 201 The new affinity group.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/affinity-groups' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "web-tier",
    "affinity_type": "Host Affinity"
}'
PATCH /affinity-groups/{affinityGroup} #

Retarget an affinity group's membership

cloud:write api.read api.write

The only mutable attribute: which of the caller's own instances belong to the group. The provider does not support renaming or retyping an affinity group after creation. Each instances.* must name one of the caller's own instances; a foreign or missing id is 422, not 404 — the addressed resource is the group, already resolved and owned before this request runs. An empty array clears the group's membership.

Parameters

Name In Type Description
affinityGroup Required path integer

Request body Required

Field Type Description
instances Required array of integer

Responses

  • 200 The updated affinity group.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X PATCH 'https://cloud.core.gen.tr/api/v1/affinity-groups/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "instances": [
        17
    ]
}'
DELETE /affinity-groups/{affinityGroup} #

Delete an affinity group

cloud:write api.read api.write

The one documented exception to "every mutation returns the current representation": there is nothing left to return after a delete, so this responds 204 with an empty body rather than 200 with the deleted resource.

Parameters

Name In Type Description
affinityGroup Required path integer

Responses

  • 204 The affinity group was deleted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X DELETE 'https://cloud.core.gen.tr/api/v1/affinity-groups/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

DNS

Zones and records on the panel's DNS integration. refresh=true on any read here is the widest-blast-radius reconciliation in the whole API — there is no single-zone reconcile primitive, so it always resyncs the caller's entire DNS account, not just the resource addressed by the request.

GET /dns-zones #

List DNS zones

dns:read api.read

Database-backed by default. Pass refresh=true to reconcile against the DNS service first — that variant is rate-limited far more tightly and must not be used for polling. Unlike the equivalent parameter on /instances or /volumes, a DNS refresh reconciles the caller's entire DNS account, not just this listing: there is no cheaper single-zone reconcile primitive in the underlying service. It also deletes local zones (and cascades to their records) that the DNS service's own listing no longer contains.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of DNS zones.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/dns-zones' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /dns-zones #

Create a DNS zone

dns:write api.read api.write

Requires at least one of the caller's own subscriptions to be in the deployed state, and refuses a 6th zone — both checked before the zone is created on the DNS service, so a rejected request never leaves an orphan zone upstream.

Request body Required

Field Type Description
name Required string The zone's domain name, without a trailing dot.

Responses

  • 201 The new DNS zone.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/dns-zones' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "example.com"
}'
GET /dns-zones/{zone} #

Read a DNS zone

dns:read api.read

Database-backed by default. Pass refresh=true to reconcile before responding — like the collection endpoint, this reconciles the caller's entire DNS account (there is no single-zone reconcile primitive), then picks this zone out of the result. That variant is rate-limited far more tightly and must not be used for polling.

Parameters

Name In Type Description
zone Required path integer
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 The DNS zone.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/dns-zones/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
DELETE /dns-zones/{zone} #

Delete a DNS zone

dns:write api.read api.write

Deletes the zone on the DNS service and its local row, and all of its records' local rows along with it. The one documented exception to "every mutation returns the current representation": there is nothing left to return, so this responds 204 with an empty body rather than 200 with the deleted resource.

Parameters

Name In Type Description
zone Required path integer

Responses

  • 204 The zone (and its records) were deleted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X DELETE 'https://cloud.core.gen.tr/api/v1/dns-zones/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /dns-zones/{zone}/records #

List a DNS zone's records

dns:read api.read

Database-backed by default: a plain read of the zone's own records, no provider call involved (the zone itself must already belong to the caller — resolved and 404'd before any record is ever looked up). Pass refresh=true to reconcile first — like the zone endpoints, this reconciles the caller's entire DNS account, not just this zone, and is rate-limited far more tightly.

Parameters

Name In Type Description
zone Required path integer
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of the zone's DNS records.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/dns-zones/1/records' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /dns-zones/{zone}/records #

Create a DNS record

dns:write api.read api.write

Requires at least one of the caller's own subscriptions to be in the deployed state, and refuses a 256th record on this zone — both checked before the record is created on the DNS service. Creating the record also reconciles the caller's entire DNS account as a side effect of reading the new record back — there is no cheaper way to obtain its local row, since the underlying provider call does not return one. A value the record's name and type already hold is refused with 422 on data before anything is written: one value is one record.

Parameters

Name In Type Description
zone Required path integer

Request body Required

Field Type Description
name Required string A relative value (e.g. `www`) is auto-qualified against the zone's own name; an already fully-qualified value (trailing dot) is used as-is.
type Required string
data Required string

Responses

  • 201 The new DNS record.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/dns-zones/1/records' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "www",
    "type": "A",
    "data": "203.0.113.5"
}'
PATCH /dns-zones/{zone}/records/{record} #

Update a DNS record

dns:write api.read api.write

The only mutable attributes: type and data. Updates the record on the DNS service and the local row directly, preserving the record's id — the underlying service method does not persist the change locally on its own, and reconciling through the account-wide sync instead would delete this record and mint a new one under a different id. A new type and data that another record at this name already holds is refused with 422 on data before anything is written; sending the record's own current value is accepted and changes nothing.

Parameters

Name In Type Description
zone Required path integer
record Required path integer

Request body Required

Field Type Description
type Required string
data Required string

Responses

  • 200 The updated DNS record.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X PATCH 'https://cloud.core.gen.tr/api/v1/dns-zones/1/records/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "A",
    "data": "203.0.113.6"
}'
DELETE /dns-zones/{zone}/records/{record} #

Delete a DNS record

dns:write api.read api.write

Deletes the record on the DNS service and its local row. The one documented exception to "every mutation returns the current representation": there is nothing left to return, so this responds 204 with an empty body rather than 200 with the deleted resource. When the DNS service no longer holds this record's value, the call answers 409, keeps the local row, and refresh=true on the zone's record list reconciles it.

Parameters

Name In Type Description
zone Required path integer
record Required path integer

Responses

  • 204 The record was deleted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X DELETE 'https://cloud.core.gen.tr/api/v1/dns-zones/1/records/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Billing

The sellable catalogue, subscriptions and their cancellation, payments, stored credit cards, refunds, the account balance and ordering. POST /orders pays only from the account balance: every card charge in this system requires an interactive 3-D Secure challenge in a browser, which nothing here can complete headlessly, so the order path takes a payment method that has no card to reach for. See each endpoint's description for the reconciling sibling — if any — it deliberately keeps off the request path.

GET /virtual-machine-products #

List virtual machine products

billing:read api.read

The sellable VM catalogue. No refresh parameter: this is database-backed by construction — nothing here ever reconciles against the cloud, unlike the offerings it is built from. Only published products are returned, matching VirtualMachineProductPolicy::view().

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of virtual machine products.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/virtual-machine-products' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /virtual-machine-products/{virtualMachineProduct} #

Read one virtual machine product

billing:read api.read

404s for an unpublished product, matching VirtualMachineProductPolicy::view() — reproduced as a query constraint, the same way GET /isos/{iso} reproduces IsoPolicy::view's visibility rule, rather than a policy check that would 403 instead.

Parameters

Name In Type Description
virtualMachineProduct Required path integer

Responses

  • 200 The virtual machine product.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/virtual-machine-products/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /volume-products #

List volume products

billing:read api.read

The sellable volume catalogue. No refresh parameter, for the same reason as GET /virtual-machine-products. Only published products are returned.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of volume products.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/volume-products' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /volume-products/{volumeProduct} #

Read one volume product

billing:read api.read

404s for an unpublished product, matching VolumeProductPolicy::view() — reproduced as a query constraint rather than a policy check.

Parameters

Name In Type Description
volumeProduct Required path integer

Responses

  • 200 The volume product.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/volume-products/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /subscriptions #

List subscriptions

billing:read api.read

Database-backed only — no refresh parameter. Unlike volumes or instances, the reconciling sibling here (BillingUserService::listSubscriptions()) is not "ask the provider what exists": it is an administrative repair pass that promotes any subscription below deployed to deployed (so merely listing one would mark a Terraform provider's own deployment finished), terminates subscriptions whose instance moved, deletes ROOT-volume subscriptions along with their payments, and dials the cloud. It does not belong behind a customer's GET at any rate limit.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of subscriptions.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/subscriptions' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /subscriptions/{subscription} #

Read one subscription

billing:read api.read

Ownership is enforced as a query constraint, not a policy check: another customer's subscription 404s here, where the panel's own route (implicit binding plus SubscriptionPolicy) would 403 it. No refresh parameter, for the same reason as GET /subscriptions.

Parameters

Name In Type Description
subscription Required path integer

Responses

  • 200 The subscription.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/subscriptions/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /subscriptions/{subscription}/actions/cancel #

Cancel a subscription

order:write api.read api.write

Terminates the subscription. Requires order:write, not billing:read: cancelling ends a paid asset, so it sits behind the same deliberate commerce-write opt-in as an order would, even though nothing here charges a card — TokenAbility's docblock is explicit that the read/write grid is not meant to be "completed" with a dedicated billing:write.

Idempotent on an already-terminated subscription: repeating the call returns 200 with the current (already-terminated) representation rather than the 409 a second cancellation would otherwise produce, so a Terraform destroy that retries after a timeout does not fail.

Refuses to cancel anything not currently deployed — an instance still running, a volume still attached, or a missing instance/volume — with 409, since each of those is a conflicting state the caller must resolve first (stop the instance, detach the volume), not a malformed request.

Parameters

Name In Type Description
subscription Required path integer

Responses

  • 200 The subscription, terminated (or already terminated).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/subscriptions/1/actions/cancel' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /payments #

List payments

billing:read api.read

Database-backed by default. amount/subtotal/taxes/discount/ applied_balance/taxable_base/list_total/catalogue_discount are null on any payment that has never been recalculated — recalculating is a write, so a plain GET never triggers it. Pass refresh=true to recalculate every payment on the returned page; that variant is rate-limited far more tightly and must not be used for polling.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of payments.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/payments' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /payments/{payment} #

Read one payment

billing:read api.read

Ownership is enforced as a query constraint: another customer's payment 404s. Pass refresh=true to force a recalculation of amount and its siblings before responding — see GET /payments's description for why a plain read never does.

Parameters

Name In Type Description
payment Required path integer
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 The payment.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/payments/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /credit-cards #

List stored credit cards

billing:read api.read

Database-backed by default. Card enrolment stays in the panel, which is already behind a session and 2FA — this API never accepts a PAN, so there is no POST here.

refresh=true asks the payment gateway directly whether it still knows each card, one call per card, and deletes the local row for any card the gateway no longer has — this is not a free "check the status" call, it is a destructive reconciliation the caller is opting into. Rate-limited far more tightly than a plain read.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
refresh Optional query boolean default false Reconcile against the upstream provider before responding, instead of reading the local database. Subject to a much tighter rate limit; do not use it for polling.

Responses

  • 200 A page of stored credit cards.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/credit-cards' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /refunds #

List refunds

billing:read api.read

The caller's own refunds only. No refresh parameter: a refund is a record of something that already happened (or is pending), not a live provider resource to reconcile against.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of refunds.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/refunds' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /billing/account #

Read the caller's balance and outstanding total

billing:read api.read

No refresh parameter: both balance and due are derived straight from stored rows, so there is nothing to reconcile against a provider.

Responses

  • 200 The caller's account summary.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/billing/account' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /orders #

Place an order, discounted by the account balance

order:write api.read api.order

Buys virtual machines and volumes, applies whatever granted credit the account holds as a discount, and leaves the rest for a card. This is the only endpoint in the API that spends money.

There is no card path HERE, and this is structural rather than a setting: a stored card's first charge always requires an interactive 3-D Secure challenge in a browser (global_settings.shop_threeds_only defaults to true and credit_cards.threeds_authorized defaults to false), which nothing headless can complete. So the order is PLACED and the subscriptions are created, and the whole bill is left on the payment for a person to settle: needs_card says whether that is the case, credit_applied says what the account's credit will take off it, payable says what a card is then asked for, and payment_url is where a browser finishes it. A card is never charged silently.

Placing an order moves no money. Nothing is taken from the balance here — the credit is applied when the payment is settled, like any other bill, so an order nobody ever pays holds none of the customer's credit. credit_applied and payable are therefore projections of what will happen at payment, while the nested payment object carries the row as it stands: its amount is the whole figure and its applied_balance is 0.00 until it is paid.

Granted credit is a discount on the NET, capped at a share of it, so an order with a price on it normally leaves something payable however large the balance. An order is no longer refused for want of a balance.

Credit is granted by our staff, never bought; there is no way to add it from the API or the panel.

Asynchronous. Paying does not provision. A queued listener reacts to the order and dials the cloud, driving each subscription new → pending → deployed or failed. The response is 202 and carries a Location header pointing at the first subscription; poll GET /subscriptions/{id} from there. A subscription that never leaves pending is a failed deployment that has not yet been recorded — check failure_reason on the subscription.

Idempotent. Idempotency-Key is required. The key is claimed before the order runs, so a client that times out and retries while the first request is still in flight gets 409 rather than a second charge; once the first request has finished, the same key with the same body replays the original 202 and creates nothing.

Preconditions, each re-asserted here exactly as the panel's checkout enforces them, and each refused with 422 naming the one that is unmet: billing information on file, the end-user licence agreement accepted, an identity or passport number on file, the shop open, and the caller's max_vms / max_vols quotas not exceeded. This endpoint is not a way around any limit the panel applies.

Requires order:write, which is off by default when a token is minted and is never implied by another ability.

Parameters

Name In Type Description
Idempotency-Key Required header string A caller-chosen key that makes this request safe to retry. The key is claimed before the order runs: a retry that arrives while the first request is still in flight gets `409` rather than a second charge, and a repeat of a request that already finished replays the original response with an `Idempotent-Replay: true` header instead of ordering again. Keys are scoped to the caller and honoured for 24 hours. Reusing one with a different body is a `409`.

Request body Required

Field Type Description
items Required array of object One entry per unit ordered. Repeat an entry to buy two of the same thing.

Responses

  • 202 The order was paid and provisioning has been queued. `Location` points at the first subscription.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 409 The `Idempotency-Key` is in use by a request that is still running, or was already used with a different body.
  • 422 The order was refused and nothing was created or charged. `errors` names the reason: `items.*` for an unavailable product or a mismatched payment plan, and `billing_info`, `eula`, `identity_number`, `shop`, `max_vms` or `max_vols` for an unmet precondition. A `balance` shortfall is NOT among them any more — a balance too small no longer refuses an order, it simply discounts it by less and leaves more on `payable`.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/orders' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Idempotency-Key: a-key-you-choose' \
  -H 'Content-Type: application/json' \
  -d '{
    "items": [
        {
            "type": "virtual_machine",
            "product_id": 1,
            "payment_plan_id": 1
        }
    ]
}'

Operations

Tickets

Your account's own support tickets: read them, open one, reply and close. Every write reaches our support staff at once, in the token owner's name, and has no undo. Files are attached from the panel only.

GET /tickets #

List your support tickets

tickets:read api.read

Every support ticket on the caller's account, the ones a colleague opened included — the list the panel's Support page shows. The list carries each thread's facts; read one ticket for its messages.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of tickets.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/tickets' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /tickets #

Open a support ticket

tickets:write api.read api.write

Opens a ticket in the token owner's name and sends it to our support staff at once; they are notified and read it. There is no undo. Files cannot be attached here — add them from the ticket's page in the panel.

Request body Required

Field Type Description
title Required string A short subject line.
body Required string The message.
category Optional string What the ticket is about. `general` when left out.

Responses

  • 201 The new ticket.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/tickets' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Mail bounces since this morning",
    "body": "Every mail to our domain has bounced since 08:00."
}'
GET /tickets/{ticket} #

Read one of your support tickets

tickets:read api.read

The ticket with its opening message and every reply, oldest first. Another account's ticket answers 404, exactly like one that does not exist.

Parameters

Name In Type Description
ticket Required path integer

Responses

  • 200 The ticket.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/tickets/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /tickets/{ticket}/comments #

Reply to one of your support tickets

tickets:write api.read api.write

Adds a reply in the token owner's name; our support staff are notified and read it. There is no undo. A ticket that is solved or later takes no reply and answers 409 — open a new one instead. Files cannot be attached here.

Parameters

Name In Type Description
ticket Required path integer

Request body Required

Field Type Description
comment Required string The reply.

Responses

  • 201 The new reply.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The ticket is solved or closed and takes no more replies.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/tickets/1/comments' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "comment": "It works again, thank you."
}'
POST /tickets/{ticket}/actions/close #

Close one of your support tickets

tickets:write api.read api.write

Closes the ticket; our support staff are notified. Answers 409 for a ticket that is already closed, and for the work-order ticket of a purchased service that can still be refunded — closing that ticket ends the right to the refund, so it is closed from the ticket's page in the panel only.

Parameters

Name In Type Description
ticket Required path integer

Responses

  • 200 The closed ticket.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The ticket is already closed, or it is the work order of a service that can still be refunded.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/tickets/1/actions/close' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Usage

What your cloud consumed — machine hours, storage, IP address hours and network traffic. Quantities only; the bill is under Billing.

GET /usage #

Read what your cloud consumed

cloud:read api.read

What the panel's Usage page draws: machine hours, storage, IP address hours and network traffic over a window, with one row per machine and per disk and one per day. Quantities only — the bill is on /payments.

The window is days (7, 30 or 90; 30 when missing or anything else) or from and to together. It ends yesterday at the latest, because today is not counted yet, and spans at most 365 days. instance_id or volume_id narrows the figures to one of your machines or disks; one that is not yours answers 404. Only what the cloud meters per machine or per disk survives the narrowing — a machine keeps its hours and its disks' storage, a disk its storage. IP address hours, network traffic, snapshots and templates are metered per address, network or image, so they are not measured there: unmetered names each such key, and its figure is not a measurement, never zero traffic.

This reads the cloud's own usage records, so it is charged against the tighter reconciling-read budget. A window, once read, is kept for an hour. available: false means the records could not be read just now.

Parameters

Name In Type Description
days Optional query integer 7, 30 or 90. Ignored when `from` and `to` are both given.
from Optional query string The first day, YYYY-MM-DD (GMT).
to Optional query string The last day, YYYY-MM-DD (GMT); yesterday at the latest.
instance_id Optional query integer One of your machines, by id.
volume_id Optional query integer One of your disks, by id. Ignored when `instance_id` is given.

Responses

  • 200 The figures for the window.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/usage' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Admin

Staff reads of the whole install, plus a deliberately small set of instance-lifecycle writes, for a token carrying admin:read or admin:write whose owner also holds the admin or super-admin role. The ability alone is never enough: a token outlives the role its holder had when it was minted, so the role is checked on every request.

The read/write split rests on nothing but the route table. AdminPolicyTrait::before() returns true for anyone holding the admin role, and almost every policy in the application uses it — so no policy can distinguish an admin's read from an admin's write; abilities:admin:read versus abilities:admin:write plus the HTTP verb is the entire enforcement, and a test walks the route table to keep it that way.

Writes are confined to instance lifecycle — start, stop, restart, attach ISO, detach ISO — because an admin already has full write over every customer's cloud through the panel, so refusing it to an admin:write token bought no safety; it only meant the one channel that could be scripted was the one nobody could audit or rate-limit. Two things are deliberately absent: instance destroy, because subscriptions.instance_id must be released before an instance is deleted and a bare destroy would orphan a live billing row; and volume attach/detach, because it needs a second cross-ownership check with no precedent on this surface. Both are candidates for a later round, not oversights.

Every customer-scoped read on this surface writes an <domain>.pii_read row into the audit trail, exactly as the equivalent panel page does, and is charged against a tighter rate-limit budget than an ordinary read for that reason. Every write writes its own explicit cloud.instance_* row instead — the access-log middleware only records a successful GET — including when idempotency skipped the underlying CloudStack call, because the auditable act is the request an admin made, not whether CloudStack was actually dialled.

Installation content and the approval queue sit beside those customer routes, with no {user} in their paths. News drafts are created and edited directly; publishing one is only ever ASKED for — the request stages it and answers 202 — and GET /admin/staged-actions reports what became of it. Nothing on this API approves or rejects a staged request: that is a signed-in administrator's click on the panel's approvals page, so a token can ask and can never decide. GET /admin/work-queues and GET /admin/health read the operator board's counts and the installation's health; neither names a person.

GET /admin/customers #

List customers

admin:read api.read

Every account holding the user role, ordered by name.

Requires an admin:read token whose owner also holds the admin (or super-admin) role. The ability alone is not enough: a token outlives the role its holder had when it was minted, so the role is checked on every request.

The query selects the published columns explicitly rather than reading whole User models — the same deliberate projection the panel's customer table uses, after an unprojected version of it once shipped every customer's national identity number into a page payload.

Database-backed, with no refresh variant anywhere on this surface. The reconciling siblings of these reads (listSubscriptions(), listZones(), getInstances()) mutate; at admin scope they mutate the whole install. There is no rate limit at which that belongs behind a GET.

This listing writes no audit row: it publishes no more about any one customer than a name and an email, and a per-request row per page of the roster would swamp the trail without recording an access to anybody's data in particular. The per-customer reads below are the ones that log.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of customers.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/customers' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/customers/{user} #

Get one customer

admin:read api.read api.privileged

One customer, with database-derived counts of their instances, volumes, DNS zones, subscriptions, invoices and tickets.

The panel's equivalent page returns twenty-four props in a single request and dials CloudStack, PowerDNS and the payment gateway to build them. This is the decomposition of that page: the counts here are plain select count(*), and the detail lives on the four per-domain collections beside this path.

Reading another person's record writes an account.pii_read row into the audit trail, exactly as the equivalent panel page does — the KVKK access-log obligation does not stop at the panel's edge. Reading your own record writes nothing: the row would be one per page load of your own dashboard, and your own actions are recorded anyway.

Because every call writes an audit row, this path is charged against a tighter rate-limit budget than an ordinary read.

Any account may be addressed here, not only one holding the user role — the equivalent panel page binds any user and an admin can legitimately need to look at a colleague's record. The listing beside this path is customers only. An id that does not exist is a 404.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.

Responses

  • 200 The customer.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/customers/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/customers/{user}/instances #

List one customer's virtual machines

admin:read api.read api.privileged

The customer's instances as currently stored, in the same Instance representation the customer's own /instances returns — so a field withheld from the owner stays withheld from staff.

Served by resolving the customer-scoped cloud service for the target customer and reading it. The admin-scoped variant of that service exists, and overriding only its data-source hooks turns every inherited reconcile-on-read method into a fleet-wide mutation — a read of one page can delete another customer's rows. Nothing on this surface resolves it, and a source-level test keeps it that way.

There is therefore no refresh parameter here, unlike the customer-facing /instances. Reconciliation is a mutation; a third party reading somebody else's machines is the last caller who should trigger one.

Writes a cloud.pii_read audit row and is charged against the tighter privileged read budget.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the customer's virtual machines.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/customers/1/instances' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/customers/{user}/dns-zones #

List one customer's DNS zones

admin:read api.read api.privileged

The customer's zones as currently stored, in the same DNSZone representation the customer's own /dns-zones returns.

Served by resolving the customer-scoped DNS service explicitly. No refresh parameter: the reconciling sibling deletes local zones — and cascades to their records — that PowerDNS's live listing no longer contains, before its own update flag is consulted, and at admin scope it does that to every zone in the install and reassigns unmatched ones to the acting staff member.

Writes a dns.pii_read audit row and is charged against the tighter privileged read budget.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the customer's DNS zones.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/customers/1/dns-zones' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/customers/{user}/subscriptions #

List one customer's subscriptions

admin:read api.read api.privileged

The customer's subscriptions as currently stored, in the same Subscription representation the customer's own /subscriptions returns. Money is always a minor-unit integer with its currency, never a float.

Served by resolving the customer-scoped billing service explicitly. No refresh parameter, and this is the sharpest case for it: the reconciling sibling terminates subscriptions whose linked resource has moved, promotes every pending subscription to deployed and erases its failure reason, deletes root-volume subscriptions together with their payments, and fires orphan events that dial the provider and create further subscriptions — all inside one transaction. At admin scope its input set is the whole table rather than one customer.

Writes a billing.pii_read audit row and is charged against the tighter privileged read budget.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the customer's subscriptions.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/customers/1/subscriptions' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /admin/customers/{user}/instances/{instance}/actions/start #

Start a customer's virtual machine

admin:write api.read api.privileged

Idempotent: starting an already-running machine returns 200 immediately without contacting CloudStack, exactly as the owner's own /instances/{instance}/actions/start does.

Served by resolving the customer-scoped cloud service for the target customer, never the admin-scoped variant — see the "customer-scoped service" note on GET /admin/customers/{user}/instances for why that distinction is load-bearing here too.

audit.access:cloud on this route is inert (it only records a successful GET); the admin-acting-on-a-customer's-machine row is written explicitly by the controller, whether or not CloudStack was actually dialled by the idempotency check above.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
instance Required path integer

Responses

  • 200 The customer's virtual machine, started (or already running).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/customers/1/instances/1/actions/start' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /admin/customers/{user}/instances/{instance}/actions/stop #

Stop a customer's virtual machine

admin:write api.read api.privileged

Idempotent: stopping an already-stopped machine returns 200 immediately without contacting CloudStack, for the same reason as start.

Served by resolving the customer-scoped cloud service for the target customer, never the admin-scoped variant — see the "customer-scoped service" note on GET /admin/customers/{user}/instances for why that distinction is load-bearing here too.

audit.access:cloud on this route is inert (it only records a successful GET); the admin-acting-on-a-customer's-machine row is written explicitly by the controller, whether or not CloudStack was actually dialled by the idempotency check above.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
instance Required path integer

Responses

  • 200 The customer's virtual machine, stopped (or already stopped).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/customers/1/instances/1/actions/stop' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /admin/customers/{user}/instances/{instance}/actions/restart #

Restart a customer's virtual machine

admin:write api.read api.privileged

Not idempotent — unlike start/stop there is no target state to compare against, so this always reaches CloudStack regardless of the machine's current state.

Served by resolving the customer-scoped cloud service for the target customer, never the admin-scoped variant — see the "customer-scoped service" note on GET /admin/customers/{user}/instances for why that distinction is load-bearing here too.

audit.access:cloud on this route is inert (it only records a successful GET); the admin-acting-on-a-customer's-machine row is written explicitly by the controller.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
instance Required path integer

Responses

  • 200 The customer's virtual machine, restarted.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 409 The addressed resource has drifted from the upstream provider in a way this request cannot resolve. Refresh and retry.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/customers/1/instances/1/actions/restart' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /admin/customers/{user}/instances/{instance}/actions/attach-iso #

Attach an ISO to a customer's virtual machine

admin:write api.read api.privileged

Idempotent: attaching an ISO already mounted on this instance returns 200 immediately without contacting CloudStack.

iso_id must name an ISO visible to the TARGET CUSTOMER — public, or owned by their account — never the acting admin's own account. Scoping on the admin's account instead would offer the admin's private images and reject the customer's own.

Served by resolving the customer-scoped cloud service for the target customer, never the admin-scoped variant — see the "customer-scoped service" note on GET /admin/customers/{user}/instances for why that distinction is load-bearing here too.

audit.access:cloud on this route is inert (it only records a successful GET); the admin-acting-on-a-customer's-machine row is written explicitly by the controller.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
instance Required path integer

Request body Required

Field Type Description
iso_id Required integer Must name an ISO visible to the CUSTOMER (public, or owned by their account). A foreign private or missing id fails validation (422) rather than 404 — the addressed resource is the instance, not the ISO.

Responses

  • 200 The customer's virtual machine, with the ISO attached (or already attached).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/customers/1/instances/1/actions/attach-iso' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "iso_id": 5
}'
POST /admin/customers/{user}/instances/{instance}/actions/detach-iso #

Detach whatever ISO is mounted on a customer's virtual machine

admin:write api.read api.privileged

Idempotent: detaching an instance with no ISO attached returns 200 immediately without contacting CloudStack.

Served by resolving the customer-scoped cloud service for the target customer, never the admin-scoped variant — see the "customer-scoped service" note on GET /admin/customers/{user}/instances for why that distinction is load-bearing here too.

audit.access:cloud on this route is inert (it only records a successful GET); the admin-acting-on-a-customer's-machine row is written explicitly by the controller.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
instance Required path integer

Responses

  • 200 The customer's virtual machine, with its ISO detached (or already detached).
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.
  • 502 The cloud's underlying IaaS control plane failed to carry out the request. The detail is a fixed, non-specific string in production — the provider's own error text routinely names internal hosts, pods and hypervisors. Treat this as retryable rather than as a client error.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/customers/1/instances/1/actions/detach-iso' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/ai/prompts #

Read both assistants' system prompts

admin:read api.read

The two assistants C2 runs — the panel assistant a signed-in customer talks to, and the chat bubble on the public marketing site — and, for each, the fixed built-in prompt plus the operator's own guidance appended to it.

Requires an admin:read token whose owner holds the admin or super-admin role.

core is read-only, on every surface. It lives in the application's source, not in the database, and there is no endpoint, form or tool that edits it. It carries the rules that make the assistants safe to run: read every fact from a tool, never guess an instance state, a price or a balance, pause for the customer's explicit approval before a machine is started or stopped, and never do arithmetic on money. The panel assistant can spend a customer's money, so those rules are the reason it can be allowed to.

guidance is the part an operator writes, and it is APPENDED below core, never substituted for it. It is framed in the prompt as operator policy that is additional to the rules above it and cannot relax, contradict or override them. null means nothing is set, and an installation with null on both surfaces sends exactly the prompt that shipped, byte for byte.

It is returned beside core deliberately: a caller iterating on the appended text is iterating against the contract above it, and should not have to fetch a second document — or guess — to see what it is appending to.

max_guidance is the character limit each surface's guidance is held to, enforced identically by this API, the admin settings form and the MCP tool. The text is sent to the model on every turn of every conversation, so it is a bill as well as a policy.

Responses

  • 200 Both assistants' prompts.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/ai/prompts' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /admin/ai/prompts #

Set or clear one assistant's operator guidance

admin:write api.read api.privileged

Replaces the operator guidance appended to one assistant's system prompt, or clears it. Requires an admin:write token whose owner holds the admin or super-admin role.

surface names which assistant: assistant for the signed-in panel assistant, public for the anonymous marketing chat bubble. They are separate fields because they are separate audiences, and neither can read the other's text.

guidance must be present. null or an empty string CLEARS it and restores the built-in prompt exactly; anything longer than max_guidance characters is refused with 422 rather than truncated.

The built-in prompt itself cannot be written here or anywhere else — see the GET on this path.

Every change to the settings row is recorded in the audit trail, whether it was made here, in the admin settings form or through the MCP tool, with the acting token owner as the actor. Answers with the same document the GET returns, so a caller tuning the text sees the result of its own write without a second request.

Request body Required

Field Type Description
surface Required string Which assistant to update.
guidance Required string The operator guidance to store, or null/empty to clear it.

Responses

  • 200 Both assistants' prompts, after the write.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/ai/prompts' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "surface": "assistant",
    "guidance": "string"
}'
GET /admin/audit-logs #

List audit-trail rows

admin:read api.read

A page of the whole audit trail, newest first (occurred_at descending, id breaking ties so a client can page it without seeing a row twice).

Requires an admin:read token whose owner holds the admin (or super-admin) role and the audit.view permission. The ability alone is not enough: a token outlives the role its holder had when it was minted, so the role is checked on every request.

The trail is append-only and nothing reconciles it, so there is no refresh parameter and no polling semantics — a row never changes after it is written.

changes, context, hash and previous_hash are not published; see the AuditLog schema for why. The hash chain is sealed and verified out of band by the c2:verify-audit-chain command, not through this API.

Any query parameter not listed below is a 422, rather than being ignored: a client that mistypes a filter would otherwise receive the whole unfiltered trail and believe it had asked a narrower question.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.
actor_id Optional query integer min 1 Only rows written by this user.
subject_id Optional query integer min 1 Only rows whose data subject is this user.
event Optional query string max length 96 Substring match against the dotted event name.
domain Optional query string one of cloud, billing, dns, tickets, account, auth, shop, privacy, partner, system Kept in lock-step with `App\Enums\AuditDomain`, which is what `IndexAuditLogRequest` derives its own validation rule from — see the `AuditLog` schema's `domain` field.
from Optional query string Inclusive lower bound on `occurred_at`.
to Optional query string Inclusive upper bound on `occurred_at`.

Responses

  • 200 A page of audit rows.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/audit-logs' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/audit-logs/{auditLog} #

Get one audit-trail row

admin:read api.read

One row of the append-only trail.

This is the only endpoint on the staff surface that answers 403 rather than 404 for a row the caller may not read. Elsewhere a resource outside the caller's scope is indistinguishable from one that does not exist, because scoping there is per-customer; the trail is a single global collection, so "this row exists but is not yours to read" is the honest answer.

Unlike the collection, this path carries no audit.view requirement in its middleware — authorization is the AuditLogPolicy, which admits an admin holding audit.view, the row's own data subject reading their own trail, and a support agent holding at least view on the row's domain for that row's subject. Rows in the auth, shop, privacy and system domains have no support equivalent and are never visible to a support agent.

changes, context, hash and previous_hash are not published; see the AuditLog schema.

Parameters

Name In Type Description
auditLog Required path integer min 1 The audit row id.

Responses

  • 200 The audit row.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/audit-logs/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/support-assignments #

List the support-assignment matrix

admin:read api.read

Every row of the support-assignment table, most recently updated first: which agent may act on which customer, and at what level in each of the five domains.

Requires an admin:read token whose owner holds the admin (or super-admin) role and the support.manage permission. The panel's equivalent route is gated role_or_permission:super-admin|support.manage; a super-admin who does not literally hold the permission is admitted here too, through the application's god-mode gate, which makes the two equivalent. That equivalence is proven by test rather than assumed.

Read-only. This table is the control plane for every gate on the Support surface: a token that could write it could grant any agent manage over any customer, and no policy stands behind such a route. Exposing the write side needs its own threat model, not a verb.

Both sides are projected to {id, name, email} and are null when the account has been deleted. Publishing the matrix read-only lets an operator diff intended access against actual access without touching either.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of assignment rows.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/support-assignments' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/staged-actions #

List the approval queue

admin:read api.read

Every action a token has asked for and a person decides — a news item to publish, and later kinds — newest first, with what it will do (preview), who asked, and what became of it. Poll this, or the single entry, to learn whether a request was approved, rejected, lapsed or failed.

Requires an admin:read token whose owner holds the admin or super-admin role.

Read-only, and deliberately so. No endpoint on this API approves or rejects an entry: that is a click by a signed-in administrator on the panel's approvals page (approval_url). A token can only ask. The frozen payload is not published; preview is the sentence the approver reads.

Parameters

Name In Type Description
status Optional query string one of pending, approved, rejected, expired, failed Only entries in this state.
action Optional query string Only entries of this kind, for example `publish_news`. An unknown kind is refused with `422`.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of queue entries.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/staged-actions' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/staged-actions/{stagedAction} #

Get one approval-queue entry

admin:read api.read

One entry of the approval queue, by the staged_action_id the request that created it returned. status moves from pending to exactly one of approved, rejected, expired or failed, and never back.

Requires an admin:read token whose owner holds the admin or super-admin role. Read-only: see the listing for why.

Parameters

Name In Type Description
stagedAction Required path integer min 1 The queue entry id.

Responses

  • 200 The queue entry.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/staged-actions/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/news #

List news items

admin:read api.read

The panel's news items, newest first — drafts and published alike, filtered by published when it is given.

Requires an admin:read token whose owner holds the admin or super-admin role. Editorial content: no person's data is read, so no access-log row is written.

Parameters

Name In Type Description
published Optional query boolean `true` for published items only, `false` for drafts only.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of news items.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/news' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /admin/news #

Create a news draft

admin:write api.read api.privileged

Creates a DRAFT with the rules the draft tools apply: title up to 255 characters, body up to 2048, language one of tr-TR, en-US, ar-SA, and an optional audience. It is never published, scheduled or sent here: is_published, publish_date and scheduled_for in the body are refused with 422 (a schedule publishes on its own when it falls due), and publishing is a separate request that an administrator must approve (POST /admin/news/{news}/publish).

Requires an admin:write token whose owner holds the admin or super-admin role.

Request body Required

Field Type Description
title Required string
body Required string
language Required string
audience Optional string

Responses

  • 201 The draft.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/news' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "string",
    "body": "string",
    "language": "tr-TR"
}'
GET /admin/news/{news} #

Get one news item

admin:read api.read

One news item by id. Requires an admin:read token whose owner holds the admin or super-admin role.

Parameters

Name In Type Description
news Required path integer min 1 The news item id.

Responses

  • 200 The news item.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/news/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
POST /admin/news/{news} #

Edit a news draft

admin:write api.read api.privileged

Changes only the fields sent (title, body, language, audience), each held to the create rules; an empty body is a 422, and so is is_published, publish_date or scheduled_for. A published item, or a draft somebody scheduled in the panel, cannot be edited here and answers 422. POST rather than PATCH: every write on the staff API is a POST.

Requires an admin:write token whose owner holds the admin or super-admin role.

Parameters

Name In Type Description
news Required path integer min 1 The draft's id.

Request body Required

Field Type Description
title Optional string
body Optional string
language Optional string
audience Optional string

Responses

  • 200 The draft, after the edit.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/news/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "string",
    "body": "string",
    "language": "tr-TR",
    "audience": "everyone"
}'
POST /admin/news/{news}/publish #

Ask for a news item to be published

admin:write api.read api.privileged

Stages the publication of a draft in the approval queue and answers 202. NOTHING IS PUBLISHED OR SENT by this request: an administrator must approve the entry in the panel (approval_url), and it lapses after 24 hours if nobody does. The Location header and staged_action_id point at GET /admin/staged-actions/{stagedAction}, which reports the outcome. An item that is already published is refused with 422. Each request stages a new entry.

Requires an admin:write token whose owner holds the admin or super-admin role.

Parameters

Name In Type Description
news Required path integer min 1 The draft's id.

Responses

  • 202 Staged; nothing has happened yet.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 404 No such resource, or it belongs to another customer. The two cases are deliberately indistinguishable.
  • 422 The request body or query string failed validation.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X POST 'https://cloud.core.gen.tr/api/v1/admin/news/1/publish' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/work-queues #

List what is waiting on a person

admin:read api.read api.privileged

Every operator queue — the erasure queue, privacy requests, failed payments, dunning, referral rewards, partner applications and trainings, open tickets, join requests, held partner rebates, the invoice worklist and price notices — with how many items wait and since when. Zeroes are included, in a fixed order, so an absent queue never reads as an empty one. Counts only: nobody is named, so no access-log row is written. The same figures the admin board and the admin MCP server read. The one money figure, the referrals queue's amount, is Money in minor units like the rest of this API — the MCP twin prints the same figure as a plain decimal.

Requires an admin:read token whose owner holds the admin or super-admin role.

Responses

  • 200 Every queue, zeroes included.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/work-queues' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /admin/health #

Read the installation's health

admin:read api.read api.privileged

One read for the installation's health: the application version, failed queue jobs (count, and the most recent by job name and exception class only — never the payload or the message, which can quote a customer's record), queue depth and whether Horizon runs, every scheduled command with its cadence, next due time and last FAILURE in 30 days, pending database migrations, and which configuration keys changed recently (never their values). C2 records a scheduled command's failures, not its successes, so there is no last successful run. The same report the admin MCP server's get_system_health returns.

Requires an admin:read token whose owner holds the admin or super-admin role.

Responses

  • 200 The health report.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/admin/health' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Operations

Support

Assignment-scoped reads of one customer's data, for a token carrying support:read whose owner holds the support or super-admin role.

A support agent sees only the customers they hold a support_assignments row for, and within those only the domains their per-domain capability level covers. A super-admin short-circuits both checks, matching the panel. Reads are audited identically to the panel's.

GET maps to the view capability level and mutations to manage — with one deliberate exception on the panel that must never be relaxed if it is ever ported here: minting a VM console session is gated at manage, not view, because a console is effective full control of the machine.

GET /support/customers #

List the customers assigned to the calling agent

support:read api.read

Only the customers the calling agent holds a support_assignments row for, ordered by name, each with the capability map the agent holds over them. An agent with no assignments gets an empty page — never the roster.

A super-admin sees every customer instead, matching the panel: both User::supportCan() and User::isAssignedTo() short-circuit for that role, so the assignment matrix is not a constraint on it.

Requires a support:read token whose owner holds the support (or super-admin) role. The ability alone is not enough: a token outlives the role its holder had when it was minted, so the role is checked on every request.

The equivalent panel route carries no gate at all — its filter lives in the controller — so an API port that simply queried "every customer" would hand the whole install to any support:read token. The scoping here is the endpoint's single most important property and is asserted in both directions by test.

Writes no audit row: it publishes no more about any one customer than a name and an email, and the per-customer reads beside it are the ones that log.

Parameters

Name In Type Description
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the agent's assigned customers.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/support/customers' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /support/customers/{user} #

Get one assigned customer

support:read api.read api.privileged

The cross-domain dashboard for one assigned customer: the record, the capability map, and database-derived counts of their instances, volumes, DNS zones, subscriptions, invoices and tickets.

Gated on the assignment alone — not on any per-domain capability — which matches the panel deliberately. The point of this record is to tell an agent where a customer's problem might be before they have a domain to look in, so gating it at account,view would break the dashboard for a cloud-only agent. The per-domain collections beside this path each require their own capability.

Because the gate is that broad, the payload is narrower than the admin equivalent: phone is not published here. An agent whose assignment reads none on all five domains can reach this record, and the panel does hand them a phone number for it; the API being stricter than the panel is allowed, the reverse is not.

A customer the agent is not assigned to is a 403, not a 404 — the assignment gate runs before anything looks the record up, and that matches the panel's answer. An id that does not exist at all is a 403 for the same reason, and that is the intended answer: it makes "no such account" and "not yours to see" indistinguishable. Nothing on the support surface returns 404.

Writes an account.pii_read audit row, exactly as the equivalent panel page does, and is charged against a tighter rate-limit budget for that reason.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.

Responses

  • 200 The customer.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/support/customers/1' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /support/customers/{user}/instances #

List an assigned customer's virtual machines

support:read api.read api.privileged

Identical in payload to the admin equivalent — the same Instance representation the customer's own /instances returns — and identical in how it is served: the customer-scoped cloud service, its non-reconciling reader, no refresh variant. Only the gate stack differs.

Requires at least view on the cloud domain of an assignment covering this customer. An agent assigned to the customer but holding none on cloud is a 403, as is an agent with no assignment at all.

Writes a cloud.pii_read audit row and is charged against the tighter privileged read budget.

An unknown id, or one the agent is not assigned to, is a 403 — the gate runs before anything looks the record up, so "no such account" and "not yours to see" stay indistinguishable. Nothing on the support surface returns 404.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the customer's virtual machines.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/support/customers/1/instances' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /support/customers/{user}/dns-zones #

List an assigned customer's DNS zones

support:read api.read api.privileged

Identical in payload and in service resolution to the admin equivalent; only the gate stack differs. Requires at least view on the dns domain of an assignment covering this customer.

No refresh parameter: the reconciling sibling deletes local zones — and cascades to their records — that PowerDNS's live listing no longer contains, before its own update flag is consulted.

Writes a dns.pii_read audit row and is charged against the tighter privileged read budget.

An unknown id, or one the agent is not assigned to, is a 403 — the gate runs before anything looks the record up, so "no such account" and "not yours to see" stay indistinguishable. Nothing on the support surface returns 404.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the customer's DNS zones.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/support/customers/1/dns-zones' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /support/customers/{user}/subscriptions #

List an assigned customer's subscriptions

support:read api.read api.privileged

Identical in payload and in service resolution to the admin equivalent; only the gate stack differs. Requires at least view on the billing domain of an assignment covering this customer. Money is always a minor-unit integer with its currency, never a float.

No refresh parameter, and this is the sharpest case for it: the reconciling sibling terminates subscriptions whose linked resource has moved, promotes every pending subscription to deployed and erases its failure reason, deletes root-volume subscriptions together with their payments, and fires orphan events that dial the provider — all inside one transaction.

Writes a billing.pii_read audit row and is charged against the tighter privileged read budget.

An unknown id, or one the agent is not assigned to, is a 403 — the gate runs before anything looks the record up, so "no such account" and "not yours to see" stay indistinguishable. Nothing on the support surface returns 404.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the customer's subscriptions.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/support/customers/1/subscriptions' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'
GET /support/customers/{user}/audit-logs #

List an assigned customer's audit trail

support:read api.read api.privileged

The rows whose data subject is this customer, newest first, filtered to the domains the calling agent holds at least view on.

Two gates, both required: an assignment covering this customer, and account at view — the same pair the equivalent panel page carries. The per-domain filter inside is what stops a tickets-only agent from reading that customer's billing rows once they are in. An agent holding view on nothing sees zero rows, not every row: the empty domain list is an explicit "no domains", never a missing constraint.

The auth, shop, privacy, partner and system domains have no support-assignment equivalent and are therefore never visible here, whatever the agent holds. A data-subject request is between the customer and the controller, and a partner's commercial terms are between the partner and the business.

changes, context, hash and previous_hash are not published; see the AuditLog schema for why.

Unlike the panel's equivalent page, this does write an account.pii_read row of its own and is charged against the tighter privileged read budget. Every {user}-scoped staff read on this API leaves a trail, without exception — a rule with one exemption is a rule that rots, and reading somebody's whole audit history is not the access to leave unrecorded. It does mean a client paging this collection appends to it.

Parameters

Name In Type Description
user Required path integer min 1 The target customer's user id. The parameter is named `user` rather than `customer` on purpose: the capability gate, the assignment gate and the access-log middleware all read it by that literal name, and the last of those fails *open* — it would stop writing the access-log row — if it were renamed.
page Optional query integer min 1, default 1 1-based page number.
per_page Optional query integer min 1, max 100, default 25 Items per page. Values above 100 are clamped to 100.

Responses

  • 200 A page of the customer's audit rows, in the domains the agent may see.
  • 401 No token was presented, or it is invalid or expired.
  • 403 Authenticated, but not permitted — the token lacks the required ability, a policy denied the action, the email address is unverified, or a support capability is insufficient.
  • 429 Too many requests. Retry after the interval given in `Retry-After`.

Example request

curl -X GET 'https://cloud.core.gen.tr/api/v1/support/customers/1/audit-logs' \
  -H 'Authorization: Bearer $C2_TOKEN' \
  -H 'Accept: application/json'

Get Started Now

Create your account in minutes, set up your own cloud environment, and take control. With cloud.core.gen.tr, everything is faster, safer, and simpler.

Book a Meeting

Let us help you grow your business. Book a 15 minute meeting now.

Book Now