Code Samples #
Copy
curl --request POST \
--url 'https://app.xcloud.host/api/v1/sites/{uuid}/ssl-certificates' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"provider": "xcloud",
"certificate": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----",
"force": false,
"ssl_search_replace": false
}'
const response = await fetch('https://app.xcloud.host/api/v1/sites/{uuid}/ssl-certificates', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"provider": "xcloud",
"certificate": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----",
"force": false,
"ssl_search_replace": false
})
});
const data = await response.json();
console.log(data);
import requests
headers = {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
}
payload = {
"provider": "xcloud",
"certificate": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----",
"force": false,
"ssl_search_replace": false
}
response = requests.post("https://app.xcloud.host/api/v1/sites/{uuid}/ssl-certificates", headers=headers, json=payload)
print(response.json())
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://app.xcloud.host/api/v1/sites/{uuid}/ssl-certificates',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_TOKEN',
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => '{
"provider": "xcloud",
"certificate": "-----BEGIN CERTIFICATE-----\\nMIID...\\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIE...\\n-----END PRIVATE KEY-----",
"force": false,
"ssl_search_replace": false
}',
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
using System.Net.Http;
using System.Text;
var client = new HttpClient();
var request = new HttpRequestMessage(new HttpMethod("POST"), "https://app.xcloud.host/api/v1/sites/{uuid}/ssl-certificates");
request.Headers.Add("Authorization", "Bearer YOUR_TOKEN");
request.Content = new StringContent(@"{
""provider"": ""xcloud"",
""certificate"": ""-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----"",
""private_key"": ""-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----"",
""force"": false,
""ssl_search_replace"": false
}", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.xcloud.host/api/v1/sites/{uuid}/ssl-certificates"))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"provider": "xcloud",
"certificate": "-----BEGIN CERTIFICATE-----\\nMIID...\\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIE...\\n-----END PRIVATE KEY-----",
"force": false,
"ssl_search_replace": false
}
"""))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Response #
Copy
{
"success": true,
"message": "SSL certificate generation queued",
"data": {
"site": {
"uuid": "11aa22bb-33cc-44dd-55ee-66ff77aa88bb",
"name": "example.com"
},
"provider": "xcloud",
"previous_provider": "cloudflare",
"status": "queued"
}
}
{
"success": false,
"message": "Unauthenticated.",
"data": null
}
{
"success": false,
"message": "This action is unauthorized. Your token is missing the required scope.",
"data": null
}
{
"success": false,
"message": "Not found.",
"data": null
}
{
"success": false,
"message": "An error occurred.",
"data": null
}
{
"success": false,
"message": "An error occurred.",
"data": null
}
Provisions an SSL certificate for the site. Three providers:
- xcloud — Let’s Encrypt via xCloud. Requires DNS pointing at the Server, OR an active Cloudflare integration when migrating from Cloudflare back to xCloud.
- custom — user-supplied certificate body + private key.
- cloudflare — uses the Team’s Cloudflare integration that
owns the domain’s zone. Mapped Server-side to the
multi-domain CF SSL architecture.
Switching providers on an already-SSL’d site requires
force: true; the previous provider’s row is retained as audit history. Returns 202 when the job is dispatched, 409 when generation is already in flight, 422 for pre-flight failures (invalid provider, missing custom cert, DNS not pointing at Server, no Cloudflare integration owns the zone, strict-Switch without force). Requires thewrite:sitesscope.
Path Parameters #
| Name | Type | Required | Description |
|---|---|---|---|
uuid | string (uuid) | Required | UUID of the site |
Request Body #
Content type: application/json — required
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Required | SSL provider. `cloudflare` maps Server-side to the multi-domain CF architecture. Allowed: xcloud, custom, cloudflare |
certificate | string | Optional | PEM-encoded certificate body. Required when `provider=custom`. |
private_key | string | Optional | PEM-encoded private key. Required when `provider=custom`. |
force | boolean | Optional | When the site already has an SSL provider configured, `force: true` is required to Switch to a different provider. Ignored when no existing provider is set or the requested provider matches. |
ssl_search_replace | boolean | Optional | WordPress only — when true, the site's HTTPS rollout will include a DB search-replace from `http://` to `https://`. Silently ignored on non-WordPress sites. |
Example request
Copy
{
"provider": "xcloud",
"certificate": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----",
"force": false,
"ssl_search_replace": false
}
Responses #
202 — SSL certificate generation queued #
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Optional | |
message | string | Optional | |
data | object | Optional | |
data | object | Optional | |
data.site | object | Optional | |
data.site.uuid | string (uuid) | Optional | |
data.site.name | string | Optional | |
data.certificate_uuid | string (uuid) | Optional | UUID of the New certificate row. Populated for `xcloud` and `custom` providers (row created synchronously). Null for `cloudflare`, where the row is created by the background job after the Cloudflare API call returns; clients can fetch the New uuid via `GET /sites/{uuid}/ssl-certificates` after a short poll. |
data.provider | string | Optional | Echoes the provider requested. Allowed: xcloud, custom, cloudflare |
data.previous_provider | string | Optional | The site's previously configured SSL provider, or null if none. Useful when switching providers with `force: true`. |
data.status | string | Optional | Allowed: queued |
Example 202 response
Copy
{
"success": true,
"message": "SSL certificate generation queued",
"data": {
"site": {
"uuid": "11aa22bb-33cc-44dd-55ee-66ff77aa88bb",
"name": "example.com"
},
"provider": "xcloud",
"previous_provider": "cloudflare",
"status": "queued"
}
}
401 — Missing or invalid authentication token #
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Optional | |
message | string | Optional | |
data | object | Optional |
Example 401 response
Copy
{
"success": false,
"message": "Unauthenticated.",
"data": null
}
403 — Token lacks the required scope #
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Optional | |
message | string | Optional | |
data | object | Optional |
Example 403 response
Copy
{
"success": false,
"message": "This action is unauthorized. Your token is missing the required scope.",
"data": null
}
404 — Resource not found or not accessible to your Team #
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Optional | |
message | string | Optional | |
data | object | Optional |
Example 404 response
Copy
{
"success": false,
"message": "Not found.",
"data": null
}
409 — SSL generation already in progress (an existing certificate is still in `New` or `obtained` status). #
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Optional | |
message | string | Optional | |
data | object | Optional |
Example 409 response
Copy
{
"success": false,
"message": "An error occurred.",
"data": null
}
422 — Pre-flight failure. Possible reasons: – Invalid `provider` value. – Custom provider with missing `certificate` / `private_key`. – xcloud provider but DNS does not resolve to the Server (and no Cloudflare migration in progress). – cloudflare provider but no Team Cloudflare integration owns the domain’s zone. – Different provider already configured and `force: true` not passed. #
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Optional | |
message | string | Optional | |
data | object | Optional |
Example 422 response
Copy
{
"success": false,
"message": "An error occurred.",
"data": null
}
