Primeros pasos con la API
Convenciones de la API
Las reglas comunes de todos los endpoints de la API de Serverside.com: URL base, nombres, unidades monetarias, respuestas de éxito y error, paginación, códigos, reintentos e idempotencia.
URL base y versiones
https://api.serverside.com
Todas las rutas empiezan con un segmento de versión, /v1. Las peticiones y respuestas usan JSON sobre HTTPS; envía Content-Type: application/json con cualquier petición que tenga cuerpo. Todas las respuestas llevan una cabecera X-Request-Id.
Nombres y valores
| Dónde | Estilo | Ejemplo |
|---|---|---|
| Parámetros de consulta | camelCase | ?pageSize=50&sortColumn=name |
| Campos JSON de peticiones y respuestas | camelCase | "plan", "primaryIpv4" |
| Valores permitidos | Cadenas UPPER_SNAKE_CASE | "GRACEFUL_RESTART", "RAID10" |
Un campo con un conjunto fijo de valores los enumera en Allowed values en su página de endpoint. Todos los conjuntos están en mayúsculas salvo location de un detalle de error, que solo aparece en respuestas de error. La API los compara sin distinguir mayúsculas, por lo que semi_annually se lee como SEMI_ANNUALLY. Otra escritura (SemiAnnually), un número en lugar del nombre o una lista separada por comas se rechazan con 400 y el error indica los valores que acepta el campo. La única excepción es el type de un elemento de pedido, que debe escribirse exactamente: BAREMETAL o IP_BLOCK.
Los ID son UUID y un campo sin ID que proporcionar es null, nunca una cadena vacía. Algunos campos que aceptan un ID también aceptan un nombre inmutable: el slug de un plan bare metal (epyc-9354p) y el code de un centro de datos, tres letras para el área metropolitana y un número de instalación (ams1). Los campos verdadero o falso se nombran como preguntas que empiezan por is, como isLocked, y un campo con unidad la indica: speedMbps, memoryGb, sizeBytes. Una duración enviada se expresa en segundos.
Las direcciones y redes IP se transmiten como cadenas, como "192.0.2.10" y "192.0.2.0/28". Una IPv4 debe escribirse en su forma habitual con puntos, así que 10.1 y 010.0.0.1 se rechazan; una IPv6 puede escribirse en cualquier formato, sin corchetes ni zona. Las marcas de tiempo son cadenas ISO 8601. Las que envíes deben incluir su desfase: 2026-09-20T00:00:00Z y 2026-09-20T02:00:00+02:00 se leen como el mismo instante y 2026-09-20T00:00:00 se rechaza. Todas las marcas de tiempo que envía la API están en UTC y terminan en Z.
Cuerpos de petición
Una propiedad JSON no declarada por el endpoint se rechaza con 400 VALIDATION_ERROR y el detalle INVALID_BODY identifica la propiedad, de modo que un campo opcional mal escrito se detecta en vez de descartarse.
PATCH cambia solo lo indicado en el cuerpo: un campo omitido conserva su valor y la respuesta es 200 con el recurso tal como lo devuelve su GET. Las tres operaciones PATCH, sobre un servidor, una red virtual y una clave SSH, aceptan un campo, name, y un nombre null conserva el anterior. PUT sustituye un ajuste completo, como el modo de arranque de un servidor o su script iPXE; lock y unlock también forman un par PUT.
Dinero
Los importes son números enteros en la divisa de su registro, indicada en currency (pricing.currency en un plan). Los enteros mantienen exactos todos los importes. La mayoría de analizadores JSON leen un decimal como 0.10 como número binario de coma flotante, que no puede representarlo exactamente: en JavaScript, 0.1 + 0.2 es 0.30000000000000004. El nombre del campo indica la escala:
- Un campo cuyo nombre termina en
Millicentscuenta milésimas de céntimo:150000es 1,50. Los precios y tarifas de planes, pedidos y suscripciones se expresan así, para conservar la fracción de céntimo de una tarifa por hora. - Todos los demás campos monetarios cuentan céntimos:
12999es 129,99. Las facturas, los pagos, los cargos por uso y el crédito de cuenta se expresan así.
Un pedido solo contiene su precio. Los impuestos, descuentos e importe pendiente están en la factura (Facturación).
Respuestas de éxito y error
El estado HTTP distingue ambas estructuras: una respuesta 2xx es un éxito, cualquier otra es un error y success lo repite en el cuerpo.
Éxito
{
"success": true,
"data": { },
"pagination": {
"totalRecords": 42,
"page": 1,
"pageSize": 25,
"totalPages": 2
}
}
| Campo | Significado |
|---|---|
success | true. |
data | Los datos: un objeto o un array en endpoints de listas. |
pagination | En listas paginadas (Paginación). Las demás respuestas lo omiten. |
Una llamada que crea algo responde 201 con lo creado, con la estructura que devuelve su lectura. 202 Accepted significa que el cambio sigue aplicándose. Conectar un servidor a una red virtual, desconectarlo y cambiar su modo de arranque incluyen el progreso del cambio en data: un status de APPLYING y since, la hora en que se aceptó el cambio. Eliminar un servidor responde 202 sin cuerpo mientras se desmantela. Las respuestas 204 No Content no tienen cuerpo. Descargar PDF de factura es el único endpoint que devuelve un archivo en lugar de JSON.
Error
{
"success": false,
"data": null,
"code": "VALIDATION_ERROR",
"message": "pageSize: Must be between 1 and 1000.",
"traceId": "SRV-7F3A-0C21-9B4E-51D2",
"details": [
{
"code": "INVALID_VALUE",
"message": "Must be between 1 and 1000.",
"field": "pageSize",
"location": "query"
}
]
}
| Campo | Significado |
|---|---|
success | false. |
data | null, salvo si se rechaza un pago de factura: entonces contiene el resultado del pago (Facturación). |
code | Qué falló, como código estable UPPER_SNAKE_CASE. Decide el comportamiento con él y el estado. Un código que el cliente aún no conozca se gestiona por su estado. |
message | Una frase para personas. Su redacción puede cambiar, así que no la analices programáticamente. |
traceId | El ID de la petición, igual a la cabecera X-Request-Id. Cítalo al contactar con soporte. |
details | Una entrada por problema, en errores de validación y algunos otros. Cada una tiene su propio code y message, el field afectado (null si el problema afecta a toda la petición) y la location de ese campo: body, query, route o header. |
El cuerpo de error comparte success y data con uno de éxito, así que un cliente puede leer ambos con un único tipo.
Paginación
Ocho listas devuelven todas las filas a la vez y no llevan pagination: Listar regiones, Listar imágenes de SO, Listar aplicaciones, Obtener estado de PSU, Listar sesiones de consola, Listar medios virtuales, Obtener análisis de seguridad y Listar plugins de análisis. Todas las demás listas están paginadas y aceptan los mismos parámetros:
| Parámetro | Predeterminado | Notas |
|---|---|---|
page | 1 | Empieza en 1. Una página posterior a la última devuelve data vacío. |
pageSize | 25 | De 1 a 1000. Un valor fuera del intervalo produce 400. |
sortColumn | ninguno | El campo por el que ordenar. |
ascending | true | false invierte el orden. |
search | ninguno | Texto libre; se eliminan los espacios iniciales y finales. Los campos donde busca dependen del endpoint. |
filter[<field>] | ninguno | Un parámetro por campo filtrado. |
La pagination de la respuesta repite page y pageSize y añade totalRecords y totalPages. Para leer toda una lista, solicita páginas hasta que page alcance totalPages; una lista vacía devuelve totalPages 0, así que compruébalo primero. También funciona detenerse en la primera página vacía. Todas las listas paginadas terminan su orden por el ID de cada fila, para que las filas empatadas en sortColumn mantengan su orden de una página a otra.
curl --request GET \
--url 'https://api.serverside.com/v1/baremetal?page=2&pageSize=100&sortColumn=name' \
--header 'Authorization: Bearer <api-key>'Un filtro sobre un campo de texto coincide con cualquier valor que lo contenga, sin distinguir mayúsculas. Un filtro sobre un campo con valores permitidos usa el valor tal como lo escribe la API, filter[status]=CANCELLATION_REQUESTED, y uno sobre un campo verdadero o falso acepta true o false. Un valor que el campo no pueda contener, un nombre por el que la lista no pueda filtrar o cualquier filtro en una lista que no los admita se rechazan con 400 VALIDATION_ERROR, con un detalle INVALID_VALUE cuyo field es la clave enviada (filter[status]). Un valor vacío no aplica filtro.
sortColumn y los nombres dentro de filter[...] no forman parte del contrato estable. Un sortColumn que el endpoint no conoce se ignora y la lista vuelve en su orden predeterminado.
Errores
Estados
| Estado | Significado | Qué hacer |
|---|---|---|
400 | No se pudo leer la petición: JSON mal formado, tipo incorrecto, propiedad no declarada por el endpoint, valor fuera del intervalo declarado, valor permitido desconocido, marca de tiempo sin desfase. | Corrige la petición; la misma volverá a fallar. |
401 | Falta la clave, es incorrecta, está desactivada o caducada, o el endpoint requiere una sesión de consola (Autenticación). | Envía una clave válida. |
403 | La clave es válida, pero le falta el permiso que comprueba el endpoint. | Usa una clave que lo tenga. |
404 | No existe nada con ese ID en tu organización o ningún endpoint tiene esa ruta. Un recurso de otra organización obtiene la misma respuesta. | Comprueba el ID y la ruta. |
405, 406, 408, 413, 415 | El método (la cabecera Allow enumera los admitidos por la ruta), la cabecera Accept, el tiempo del cuerpo, su tamaño o el tipo de contenido son incorrectos. | Corrige la petición. |
409 | Hay un impedimento: un duplicado, un recurso en uso o una operación en curso. | Reintenta tras Retry-After si la respuesta lo incluye; de lo contrario, resuelve el conflicto. |
422 | La petición se leyó y una regla del recurso o su estado actual la rechazó. | Cambia lo solicitado. |
500 | Un fallo de nuestro lado. | Reintenta más tarde y envía el traceId a soporte si persiste. |
502 | Un sistema detrás de la API respondió con un error. | Reintenta más tarde. |
503 | No se puede acceder a un sistema detrás de la API o una función está pausada. Siempre lleva Retry-After. | Reintenta tras Retry-After. |
504 | Un sistema detrás de la API no respondió a tiempo. | Reintenta más tarde. |
Retry-After es un número de segundos. Todas las respuestas 503 lo incluyen, igual que cada 409 que se resuelve solo, como un controlador de gestión que se reinicia. Reintentar un 500, 502 o 504 es seguro para las lecturas. De las llamadas que cambian algo, solo las cinco enumeradas en Idempotencia aceptan una clave que hace seguro el reintento; antes de reintentar cualquier otra, lee lo que existe, ya que la primera petición puede haberse completado.
Validación
Dos códigos incluyen una lista de details:
VALIDATION_ERROR,400: no se pudo leer la petición. Elcodede un detalle esINVALID_BODYsi no se puede leer el propio cuerpo JSON: sintaxis incorrecta, tipo incorrecto, miembro obligatorio ausente, miembro no declarado por el endpoint o valor fuera de los permitidos por el campo. EsINVALID_VALUEpara un valor de consulta, ruta o cabecera y para un campo del cuerpo leído que incumple un límite declarado, como una longitud o intervalo.VALUE_OUT_OF_RANGEidentifica un número que la operación comprueba en su propio código.VALIDATION_FAILED,422: la petición se leyó y una o más reglas la rechazaron. Elcodede cada detalle indica la regla, comoBILLING_CYCLE_UNAVAILABLEen un pedido, y sulocationesnull.
Un campo del cuerpo se identifica por su ruta JSON, con índices para arrays (items[0].plan, billingAddress.countryCode). Un campo de consulta se identifica tal como lo enviaste, uno de ruta por el nombre de su parámetro y una cabecera por su nombre. Con un detalle, message muestra field: problem; con varios, The request has N problems: seguido de cada uno.
Un pedido con un ciclo de facturación en el que no se vende su plan:
{
"success": false,
"data": null,
"code": "VALIDATION_FAILED",
"message": "cycle: This billing cycle is not offered.",
"traceId": "SRV-1A2B-3C4D-5E6F-7A8B",
"details": [
{
"code": "BILLING_CYCLE_UNAVAILABLE",
"message": "This billing cycle is not offered.",
"field": "cycle",
"location": null
}
]
}
Un ID del cuerpo que no coincide con nada se trata según lo que identifica. Un plan, imagen, aplicación, segmento o interfaz es una entrada de catálogo y uno desconocido produce 422 con un detalle sobre ese campo, como OFFERING_NOT_FOUND en items[0].plan. Un ID de algo que posee tu organización (servidor, red o clave SSH) produce 404 ENTITY_NOT_FOUND sin campo, para que un ID de otra organización tenga el mismo aspecto que uno inexistente. Un centro de datos es la excepción: un code desconocido produce un detalle DATACENTER_NOT_FOUND y un UUID desconocido es 422 OFFERING_NOT_AVAILABLE.
Códigos
Códigos que puede devolver cualquier endpoint:
| Código | Estado | Significado |
|---|---|---|
VALIDATION_ERROR | 400 | No se pudo leer la petición; consulta details. |
BAD_REQUEST | 400 | No se pudo leer la propia petición HTTP. |
UNAUTHENTICATED | 401 | Consulta Errores de autenticación. |
NO_PERMISSION | 403 | A la clave le falta el permiso indicado por el endpoint. |
ENTITY_NOT_FOUND | 404 | No hay un recurso con ese ID en tu organización. |
ROUTE_NOT_FOUND | 404 | Ningún endpoint tiene esa ruta. |
METHOD_NOT_ALLOWED | 405 | La ruta existe, pero no el método; Allow enumera los métodos admitidos. |
ENTITY_ALREADY_EXISTS | 409 | Existe un recurso con la misma identidad. |
ENTITY_IN_USE | 409 | El recurso está en uso, por lo que no se puede eliminar ni mover. |
ENTITY_STATE_INVALID | 422 | El estado del recurso no permite la operación y no existe un código más específico. |
VALIDATION_FAILED | 422 | Una regla rechazó la petición; consulta details. |
INTERNAL_ERROR | 500 | Un fallo de nuestro lado. |
UPSTREAM_ERROR | 502 | Un sistema detrás de la API respondió con un error. |
UPSTREAM_UNAVAILABLE | 503 | No se puede acceder a un sistema detrás de la API. Retry-After: 30. |
UPSTREAM_TIMEOUT | 504 | Un sistema detrás de la API agotó el tiempo de espera. |
Códigos de servidores bare metal:
| Código | Estado | Significado |
|---|---|---|
SERVICE_SUSPENDED | 422 | El servicio está suspendido; nada puede cambiar hasta que se restablezca. |
SERVICE_LOCKED | 422 | El servicio está bloqueado. |
SERVICE_DELETING | 422 | Se está eliminando el servicio y rechaza lo mismo que uno suspendido. |
OPERATION_IN_PROGRESS | 409 | Hay otra operación en curso en el servidor. |
BMC_RESET_IN_PROGRESS | 409 | El controlador de gestión se está reiniciando. Retry-After: 30. |
BMC_UNREACHABLE | 503 | El controlador de gestión no responde. Retry-After: 30. |
BMC_REQUEST_FAILED | 502 | El controlador de gestión devolvió un error. |
KVM_SESSION_REQUEST_IN_PROGRESS | 409 | Ya hay una solicitud de sesión de consola en curso para el servidor. Retry-After: 10. |
OPERATION_NOT_SUPPORTED_PLATFORM | 422 | El hardware del servidor no admite la operación. |
PRIMARY_IPV4_REQUIRED | 422 | Un despliegue necesita una dirección IPv4 principal en el servidor. |
ISO_LIMIT_REACHED | 422 | La organización tiene tantas ISO como se le permiten. |
ISO_UPLOAD_INCOMPLETE | 422 | La subida de la ISO no ha terminado o no se ha podido verificar. |
VIRTUAL_MEDIA_EJECT_FAILED | 502 | El controlador de gestión no pudo expulsar el medio. |
VIRTUAL_MEDIA_ATTACH_TIMEOUT | 504 | Se agotó el tiempo de espera al conectar medios virtuales. |
NETWORK_METRICS_UNAVAILABLE | 503 | No se pueden leer las métricas de tráfico por ahora. Retry-After: 30. |
Códigos de pedidos y facturación:
| Código | Estado | Significado |
|---|---|---|
OFFERING_NOT_AVAILABLE | 422 | El plan no se puede contratar como se solicita: no hay existencias en ese centro de datos, no hay espacio de direcciones allí o el UUID del centro de datos es desconocido. |
USAGE_BILLING_DISABLED | 422 | La organización no tiene activada la facturación por hora (Guía rápida). |
BILLING_ADDRESS_REQUIRED | 422 | La organización no tiene dirección de facturación. |
PAYMENT_FAILED | 422 | No se pudo cobrar el pago: la tarjeta fue rechazada o la organización no tiene crédito; data contiene el resultado del pago. |
INVOICE_CANNOT_ACCEPT_PAYMENT | 422 | La factura ya está pagada, cancelada o reembolsada, no tiene importe pendiente o un pago está pendiente de confirmación. |
SUBSCRIPTION_NOT_ACTIVE | 422 | La suscripción ya se ha cancelado. |
SUBSCRIPTION_SERVER_TRANSFERRED | 422 | Un servidor facturado por la suscripción ahora pertenece a otra organización; no cambió nada. |
TERMINATION_BLOCKED | 422 | Un elemento de la suscripción no puede cancelarse ahora; no cambió nada. |
BUNDLED_ITEM_CANCELLATION_BLOCKED | 422 | El bloque de IP venía con un servidor; eliminar el servidor lo libera. |
SUBSCRIPTION_CANCELLATION_INCOMPLETE | 422 | Algunos elementos se cancelaron antes de que fallara uno. Es seguro volver a enviar la petición. |
IDEMPOTENCY_KEY_REUSED | 409 | La Idempotency-Key ya se usó para una petición diferente. |
ORDER_CREATION_IN_PROGRESS | 409 | Una petición con la misma Idempotency-Key sigue creando el pedido. Retry-After: 5. |
ORDER_PROVISIONING_IN_PROGRESS | 409 | Una creación con la misma Idempotency-Key sigue en curso. Retry-After: 5. |
PROVISIONING_FAILED | 409 | No pudo aprovisionarse nada de un pedido por hora o de una solicitud de servidor o bloque de IP por hora. |
VAT_SERVICE_UNAVAILABLE | 503 | No se pudo completar la comprobación del número de IVA de la UE. Retry-After: 30. |
STRIPE_PROVIDER_ERROR | 502 | Falló el proveedor de pagos. |
Los códigos de red se enumeran en Gestionar direcciones IP y Configurar redes virtuales, junto a las llamadas que los devuelven. Los códigos de detalle VALIDATION_FAILED se indican en la guía de la operación que los envía.
Idempotencia
Cinco operaciones aceptan una cabecera Idempotency-Key de hasta 200 caracteres: crear un pedido, crear un servicio bare metal, crear un bloque de IP y conectar o desconectar un servidor de una red virtual. Envía un valor nuevo para cada acción nueva y el mismo valor cuando reintentes esa acción.
Las tres llamadas de creación comparten un conjunto de claves por organización y una clave nunca se olvida. Un reintento con la misma clave y la misma compra (ciclo, código promocional y elementos) no crea nada nuevo y responde 200 en lugar de 201 con lo creado por la primera petición; Crear pedido también pone data.isReplayed en true. Identificar el plan por su slug en una petición y por su ID en la otra sigue contando como la misma compra, igual que el code de un centro de datos frente a su ID. La misma clave con una compra diferente se rechaza con 409 IDEMPOTENCY_KEY_REUSED. Mientras la primera petición sigue en curso, un reintento recibe 409 ORDER_CREATION_IN_PROGRESS u ORDER_PROVISIONING_IN_PROGRESS con Retry-After: 5; vuelve a enviarlo tras esos segundos.
En las llamadas de red virtual, una clave pertenece al servidor y se recuerda hasta 90 días después de aplicarse el cambio. Un reintento responde 202 de nuevo sin encolar un segundo cambio y la misma clave con otra red o segmento recibe 409 IDEMPOTENCY_KEY_REUSED. Un segundo cambio mientras el primero sigue aplicándose recibe 409 NETWORK_CHANGE_IN_PROGRESS con Retry-After: 10.
Límites de peticiones
Cada clave de API tiene sus propios límites:
| Peticiones | Límite |
|---|---|
Lecturas (GET) | 1.000 por minuto |
Escrituras (POST, PUT, PATCH, DELETE) | 100 por minuto |
Los límites se aplican delante de la API y la propia API no envía 429.
Consultar un despliegue cada 20 segundos, como hacen las guías, usa 3 lecturas por minuto.