Browse the documentation

Managing services

Every route on this page takes the service code (SRV-TJUAQ1-1951), given by GET /services. A service outside the key's restriction answers 404 SERVICE_NOT_FOUND.

GET /services

Permissions: services:read

ParameterTypeRequiredValues
limitintegerno, default 201 to 100
cursorstringnopagination.nextCursor from the previous page
statusstringnoACTIVE, SUSPENDED, CANCELLED, DELETED
curl -H "Authorization: Bearer $FRESHPERF_KEY" \
     "https://api.freshperf.fr/v1/services?limit=2&status=ACTIVE"
{
  "data": [
    {
      "code": "SRV-TJUAQ1-1951",
      "name": "Minecraft 1",
      "customName": null,
      "productShortname": "minecraft-1",
      "productTitle": "Minecraft 1",
      "category": "minecraft",
      "status": "ACTIVE",
      "providerType": "pterodactyl",
      "autoRenew": true,
      "nextBillingAt": 1789437385056,
      "recurrence": "monthly",
      "createdAt": 1786845385066,
      "activatedAt": 1786845385056
    }
  ],
  "pagination": { "nextCursor": null, "limit": 2 }
}
FieldTypeNotes
codestringthe identifier every service route takes
namestringthe custom name when set, otherwise the product title
customNamestring or nullthe name you gave it
productShortnamestringpass it back as product in an order
productTitlestring or nullproduct label
categorystring or nullcategory shortname, e.g. vps, minecraft
statusstringACTIVE, SUSPENDED, CANCELLED, DELETED
providerTypestring or nullvps or pterodactyl
autoRenewboolean
nextBillingAtinteger or nullepoch milliseconds
recurrencestring or nullbilling cycle, e.g. monthly
createdAt, activatedAtinteger or nullepoch milliseconds

GET /services/{code}

Permissions: services:read

Carries the fields above and adds:

FieldTypeNotes
provisionedbooleanfalse while no infrastructure exists
priceCentsintegerrecurring price of one cycle, excluding tax
taxCentsintegertax on the same cycle
currencystring or nullISO 4217
dunningStatestringNONE, RETRY, SUSPENSION_TRIGGERED, DELETION_TRIGGERED
restartRequiredbooleana resource change is waiting for a restart
restartRequiredReasonstring or null
configurationobject string → stringthe configuration as ordered. Credentials and internal keys are stripped
cancelledAtinteger or nullepoch milliseconds
{
  "data": {
    "code": "SRV-TIYMZT-8349",
    "name": "VPS 1",
    "status": "ACTIVE",
    "providerType": "vps",
    "provisioned": true,
    "autoRenew": true,
    "nextBillingAt": 1787960297645,
    "recurrence": "monthly",
    "priceCents": 500,
    "taxCents": 100,
    "currency": "EUR",
    "dunningState": "NONE",
    "restartRequired": false,
    "restartRequiredReason": null,
    "configuration": {
      "os": "debian", "osVersion": "13", "location": "paris",
      "cpuCores": "2", "ramSize": "2048", "diskSize": "20"
    },
    "cancelledAt": null
  }
}

GET /services/{code}/status

Permissions: services.metrics:read

Asks the infrastructure live. Allow up to two seconds.

Every field can be null: each provider reports what it knows.

FieldTypeNotes
statusstringthe provider's own text: running, stopped, starting, stopping, restoring... Not a closed enum
uptimeSecondsinteger
cpunumbera fraction or a percentage depending on the provider
cpuCountnumber
memoryBytes, memoryMaxBytesintegerbytes
diskBytes, diskMaxBytesintegerbytes
networkInBytes, networkOutBytesintegerbytes
ipv4stringon a game server, address:port
ipv6string
extraIpv4array of stringadditional addresses
hostnamestring
extraobjectthe provider's own figures. Free-form, unversioned

INSTANCE_NOT_PROVISIONED (409) while no infrastructure exists.

GET /services/{code}/metrics/history

Permissions: services.metrics:read

{ "data": { "samples": [
  { "ts": 1787903520000, "cpu": 0.1364, "mem": 1069400678, "maxmem": 2147483648, "netin": 4550, "netout": 69 }
] } }

samples is an array of free-form objects: the window, the step and the keys come from the provider. It is empty when no history is available, which is the case on game servers.

POST /services/{code}/power

Permissions: services.power:write Rate: 20 a minute, per key and per service.

FieldTypeRequiredValues
actionstringyesstart, stop, restart, kill

kill exists only on game servers; on a VPS it answers 400 ACTION_UNSUPPORTED.

curl -X POST -H "Authorization: Bearer $FRESHPERF_KEY" \
     -H "Content-Type: application/json" -d '{"action":"restart"}' \
     https://api.freshperf.fr/v1/services/SRV-TJUAQ1-1951/power
{ "data": { "status": "SUCCESS", "message": "Power signal accepted" } }
FieldValues
statusSUCCESS when done, PENDING when the infrastructure is still working on it
messagethe provider's sentence, or null

On PENDING, read /status again every 5 to 10 seconds.

ErrorStatusWhen
VALIDATION_ERROR:action400action absent or outside the list
ACTION_UNSUPPORTED400kill on a VPS
SERVICE_NOT_ACTIVE409service suspended or cancelled
INSTANCE_NOT_PROVISIONED409no infrastructure yet

POST /services/{code}/console/command

Permissions: services.console:write

Game servers only.

FieldTypeRequired
commandstringyes, non-blank
curl -X POST -H "Authorization: Bearer $FRESHPERF_KEY" \
     -H "Content-Type: application/json" -d '{"command":"say hello"}' \
     https://api.freshperf.fr/v1/services/SRV-TJUAQ1-1951/console/command
{ "data": { "status": "SUCCESS", "message": "Command sent" } }

On a VPS: 400 ACTION_UNSUPPORTED. On a stopped server the panel refuses the command and the answer is 502 ACTION_FAILED.

Backups

The four routes relay the provider. The response always has the same shape: {"data": {"status", "message", "result"}}, where result is the provider's payload.

GET /services/{code}/backups

Permissions: services.backups:read

Answers even on a suspended service.

{ "data": { "status": "SUCCESS", "message": "OK", "result": {
  "customerEnabled": true,
  "limits": { "max": 6, "used": 2 },
  "customer": [
    { "id": "9b5d3938-cbd9-4946-8357-05badcdf6c33",
      "note": null, "status": "COMPLETED",
      "createdAt": "2026-08-15T19:50:45.282411", "sizeBytes": 21474837581 }
  ],
  "internal": []
} } }

A backup id is a string, the provider's own. It is what delete and restore take.

POST /services/{code}/backups

Permissions: services.backups:write

FieldTypeRequiredValues
notestring or nullno200 characters at most
{ "data": { "status": "PENDING", "message": "VPS backup in progress",
  "result": { "taskId": "d3b780a2-308f-40bf-95a2-0316d8872721", "status": "PENDING" } } }
ErrorStatusWhen
NOTE_TOO_LONG400note beyond 200 characters
SERVICE_NOT_ACTIVE400service suspended or cancelled
SERVICE_IN_DUNNING400service in dunning
INSTANCE_NOT_PROVISIONED400no infrastructure yet
LIMIT_REACHED409backup quota reached
BACKUP_IN_PROGRESS400a backup or a restore is already running

DELETE /services/{code}/backups/{backupId}

Permissions: services.backups:write

backupId comes from result.customer[].id. An unknown one answers 400 BACKUP_NOT_FOUND.

POST /services/{code}/backups/restore

Permissions: services.backups:write

Overwrites the disk.

FieldTypeRequiredValuesWhere it comes from
sourcestringyesCUSTOMER or INTERNAL-
backupIdstringyes when source is CUSTOMER-result.customer[].id
volidstringyes when source is INTERNAL-result.internal[].volid

Same refusals as creation, plus 400 MISSING_FIELDS when source is absent or its matching identifier is missing.

POST /services/{code}/reinstall

Permissions: services.reinstall:write Rate: 2 a minute, per key and per service. Refused calls count.

Destroys the disk. On a game server it resets the server and the body may be empty.

FieldTypeRequiredValuesWhere it comes from
osstringyes on a VPSthe composite <family>-<version> valueGET /catalog/products/{shortname} → the kind: "os-picker" characteristic, options field
authTypestringyes on a VPSPASSWORD or SSH_KEY-
authValuestringyes on a VPSthe password, or an OpenSSH public key line-

authValue is stored encrypted, never returned, and this call is never logged with its body.

curl -X POST -H "Authorization: Bearer $FRESHPERF_KEY" \
     -H "Content-Type: application/json" \
     -d '{"os":"debian-13","authType":"SSH_KEY","authValue":"ssh-ed25519 AAAAC3Nza... admin@laptop"}' \
     https://api.freshperf.fr/v1/services/SRV-TIYMZT-8349/reinstall
{ "data": { "status": "PENDING", "message": "reinstalling" } }
ErrorStatusWhen
MISSING_FIELDS400one of the three fields is missing on a VPS
INVALID_OS400os outside the catalogue values
OS_FAMILY_MISMATCH400family and version do not go together
INVALID_AUTH_TYPE400authType outside the list
SERVICE_NOT_ACTIVE, SERVICE_IN_DUNNING, INSTANCE_NOT_PROVISIONED400state of the service
API_RATE_LIMITED429more than 2 calls in the minute

GET /services/{code}/addons

Permissions: services.addons:read

{ "data": {
  "addons": [
    { "shortname": "extra-saves", "title": "Additional saves",
      "kind": "BACKUP_SLOTS", "status": "ACTIVE", "quantity": 1,
      "unitPriceCents": 399, "unitTaxCents": 80,
      "linePriceCents": 399, "lineTaxCents": 80,
      "nextCycleLinePriceCents": 399, "nextCycleLineTaxCents": 80,
      "pendingRemovalQuantity": 0 }
  ],
  "available": [
    { "shortname": "extra-ram-1gb", "title": { "fr-fr": "+1 Go RAM", "en-us": "+1 Gb RAM" },
      "kind": "RESOURCE_DELTA", "resourceKey": "ramSize", "unitDelta": 1024,
      "unitPriceCents": 200, "maxQuantity": 10 }
  ],
  "recurringTotalCents": 479
} }
FieldContents
addonsthe add-ons the service already carries
availablethose it may still take. maxQuantity of 0 means unlimited
recurringTotalCentsthe service's recurring total including add-ons, excluding tax

Adding or removing an add-on happens in the dashboard.

PATCH /services/{code}

Permissions: services:write

FieldTypeRequiredValues
customNamestring or nullno32 characters at most. An empty string clears the name
autoRenewbooleannotrue only
curl -X PATCH -H "Authorization: Bearer $FRESHPERF_KEY" \
     -H "Content-Type: application/json" -d '{"customName":"prod-eu-1"}' \
     https://api.freshperf.fr/v1/services/SRV-TJUAQ1-1951

Answers the whole service, like GET /services/{code}.

ErrorStatusWhen
CUSTOM_NAME_TOO_LONG400beyond 32 characters
RENEWAL_CANCELLATION_NOT_AVAILABLE_VIA_API400autoRenew: false. Stopping a renewal happens in the dashboard

POST /services/{code}/renew

Permissions: services:write and billing.invoices:pay, plus billing.saved_methods:charge as soon as the funding touches a card. Required header: Idempotency-Key.

Charges the next cycle now and moves the billing date forward.

FieldTypeRequiredValuesWhere it comes from
methodstringno, default account_defaultaccount_default, balance, saved_method-
paymentMethodIdintegeryes when saved_method> 0GET /payment-methodsid
methodEffect
account_defaultapplies the account's rule: the balance when opted in and sufficient, otherwise the default payment method. Going through the card needs billing.saved_methods:charge
balancethe prepaid balance alone. No fallback to a card
saved_methodcharges the named method
curl -X POST -H "Authorization: Bearer $FRESHPERF_KEY" \
     -H "Content-Type: application/json" \
     -H "Idempotency-Key: renew-SRV-TJUAQ1-1951-2026-08" \
     -d '{"method":"balance"}' \
     https://api.freshperf.fr/v1/services/SRV-TJUAQ1-1951/renew
{ "data": { "status": "CHARGED", "serviceCode": "SRV-TJUAQ1-1951",
            "nextBillingAt": 1793091315189, "amountCents": 360 } }

status is only ever CHARGED: any other outcome is an error. amountCents is what was charged, tax included.

ErrorStatusWhen
VALIDATION_ERROR:method400method outside the list
PAYMENT_METHOD_ID_REQUIRED400saved_method without paymentMethodId
PAYMENT_METHOD_NOT_FOUND404that method is not on the account
INSUFFICIENT_BALANCE402balance too short
NO_PAYMENT_METHOD402account_default with no usable method
PAYMENT_METHOD_NOT_ACTIVE402method expired or blocked
RENEWAL_FAILED402the charge failed for another reason
API_KEY_SPENDING_CAP_EXCEEDED403the key's cap does not cover the cycle
SERVICE_NOT_ACTIVE409service neither active nor reactivatable
RENEWAL_IN_PROGRESS409a renewal of the same service is already running
RENEWAL_TOO_FREQUENT429less than a minute since the previous one

POST /services/{code}/actions/{action}

Permissions: they depend on the action sent.

The raw gateway to the provider. It is how the firewall and reverse DNS are reached, since neither has a dedicated route.

ActionPermission
power, start_vps, stop_vps, reboot_vpsservices.power:write
send_console_commandservices.console:write
backup_listservices.backups:read
backup_create, backup_delete, backup_restoreservices.backups:write
firewall_listservices.firewall:read
firewall_create, firewall_update, firewall_move, firewall_deleteservices.firewall:write
rdnsservices.rdns:write, including for op: "get"
featuresservices:read

No other action is reachable. There is no firewall_add, firewall_set or firewall_remove: a rule is created, edited and deleted with firewall_create, firewall_update and firewall_delete.

The game-panel actions (files, databases, allocations, schedules, startup, versions, content, subdomains, sftp, subusers) answer 403 API_ACTION_NOT_ALLOWED whatever the key holds.

FieldTypeRequired
argumentsobjectno. Contents specific to each action
curl -X POST -H "Authorization: Bearer $FRESHPERF_KEY" \
     -H "Content-Type: application/json" \
     -d '{"arguments":{"op":"set","address":"203.0.113.224","hostname":"vps.example.com"}}' \
     https://api.freshperf.fr/v1/services/SRV-TIYMZT-8349/actions/rdns
{ "data": { "status": "SUCCESS", "message": "Action completed", "result": {
  "configured": true,
  "entries": [
    { "family": "ipv4", "address": "203.0.113.224", "hostname": "vps.example.com", "zoneConfigured": true }
  ]
} } }

rdns takes op as get, set or delete, plus address (one of the addresses /status returns) and, for set, hostname. The arguments of the firewall_* actions depend on the hypervisor: read firewall_list to see the shape of a rule before writing one.

ErrorStatusWhen
INVALID_ACTION400action empty or starting with _
API_ACTION_NOT_ALLOWED:<action>403action the platform does not classify, or one with no public permission
SERVICE_NOT_ACTIVE409service suspended or cancelled
a provider marker, e.g. FIREWALL_INVALID_ARGUMENT409the provider refused
ACTION_FAILED502the provider failed or did not answer

Prefer the typed routes (/power, /backups, /reinstall, /console/command) wherever they exist: they are stable and provider-neutral.