---
title: Create SSL Certificate
description: "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…"
url: "https://betterdocs.shahrear.msf.bd/index.php/docs/hell0-boys-docs/hell0-boys/sites/create-ssl-certificate/"
updated: "2026-08-20"
category: hell0 boys / Sites
---

# Create SSL Certificate

POST`/sites/{uuid}/ssl-certificates`

## Code Samples

```curl

                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

```json

                {
    "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](https://betterdocs.shahrear.msf.bd/encyclopedia/server/), OR an active Cloudflare integration when migrating from Cloudflare back to xCloud.
- **custom** — user-supplied certificate body + private key.
- **cloudflare** — uses the [Team](https://betterdocs.shahrear.msf.bd/encyclopedia/team/)'s Cloudflare integration that owns the domain's zone. Mapped [Server](https://betterdocs.shahrear.msf.bd/encyclopedia/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](https://betterdocs.shahrear.msf.bd/encyclopedia/server/), no Cloudflare integration owns the zone, strict-[Switch](https://betterdocs.shahrear.msf.bd/encyclopedia/switch/) without force). Requires the `write:sites` scope.

## 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](https://betterdocs.shahrear.msf.bd/encyclopedia/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](https://betterdocs.shahrear.msf.bd/encyclopedia/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. |

```json

                {
    "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](https://betterdocs.shahrear.msf.bd/encyclopedia/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](https://betterdocs.shahrear.msf.bd/encyclopedia/api/) call returns; clients can fetch the [New](https://betterdocs.shahrear.msf.bd/encyclopedia/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](https://betterdocs.shahrear.msf.bd/encyclopedia/useful/) when switching providers with \`force: true\`. |
| `data.status` | string | Optional | Allowed: queued |

```json

                {
    "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 |  |

```json

                {
    "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 |  |

```json

                {
    "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](https://betterdocs.shahrear.msf.bd/encyclopedia/team/)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | Optional |  |
| `message` | string | Optional |  |
| `data` | object | Optional |  |

```json

                {
    "success": false,
    "message": "Not found.",
    "data": null
}
```

### 409 — SSL generation already in progress (an existing certificate is still in \`[New](https://betterdocs.shahrear.msf.bd/encyclopedia/new/)\` or \`obtained\` status).

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | boolean | Optional |  |
| `message` | string | Optional |  |
| `data` | object | Optional |  |

```json

                {
    "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](https://betterdocs.shahrear.msf.bd/encyclopedia/server/) (and no Cloudflare migration in progress). - cloudflare provider but no [Team](https://betterdocs.shahrear.msf.bd/encyclopedia/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 |  |

```json

                {
    "success": false,
    "message": "An error occurred.",
    "data": null
}
```
