Create a Site via API
Provision a disposable Joomla trial site programmatically and poll for its status using two simple REST endpoints.
Overview
Creating a site is asynchronous. The first endpoint (POST /api/v1/trial-sites) accepts your configuration and returns a siteId and pollToken immediately. Provisioning continues in the background. The second endpoint (GET /api/v1/trial-sites/{siteId}) lets you poll for status until the site is ready or failed.
Each trial site has a fixed 4-hour lifetime and is permanently deleted on expiry with no backup. The exact deletion time is in result.expiresAt.
Authentication
All requests require an API key sent as a Bearer token. Get your key at Settings → Application API Key (signed-in dashboard). One active key per account; the full key is shown once at creation.
Authorization: Bearer ij_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/jsonTreat the key like a password — it authorises site creation against your account quota. Rotate it from Settings if it is ever exposed.
- Missing, malformed, or revoked key →
401 Unauthorized. - One active key per account.
Base URL
All requests go to the production base URL https://jinstant.com. Every example in this guide uses it.
Endpoint 1 — Create a trial site
/api/v1/trial-sites202 AcceptedReserves a provisioning job and returns immediately. Every request body field is optional — send an empty JSON object ({}) or no body at all to use all defaults.
Request body
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
joomlaVersion | "5" | "6" | No | "6" | "5" provisions the latest Joomla 5 release (currently 5.4); "6" provisions the latest Joomla 6 release (currently 6.1). See the versions matrix below for allowed PHP combinations. |
phpVersion | "8.1" | "8.2" | "8.3" | "8.4" | No | "8.3" | Must be compatible with the selected Joomla version. Unsupported combinations return 400. |
Examples
curl -X POST "https://jinstant.com/api/v1/trial-sites" \
-H "Authorization: Bearer $JINSTANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"joomlaVersion": "6",
"phpVersion": "8.3"
}'Response — 202 Accepted
{
"siteId": "4db53b6f-b1a6-4e46-a793-9a15a9dbf9ef",
"pollToken": "uG0Q6Zq4xv9M3v3q8c2m4mS0nLQh4x2M",
"status": "queued",
"progressStage": "queued",
"progressMessage": "Your site is in line. We are setting up Joomla 6 / PHP 8.3."
}| Name | Type | Description |
|---|---|---|
siteId | string (UUID) | Identifies the provisioning job. Use in endpoint 2's path. |
pollToken | string | Secret required to poll status. Pair it with siteId — store both. |
status | string | "queued" on creation. |
progressStage | string | Machine-readable stage. See the status lifecycle below. |
progressMessage | string | Human-readable progress text, safe to display in a UI. |
Endpoint 2 — Check status / get result
/api/v1/trial-sites/{siteId}?token={pollToken}200 OKRequires the same Authorization: Bearer key and the token query parameter. The job must belong to the authenticated user. Responses are always Cache-Control: no-store.
Parameters
| Name | Type | In | Required | Description |
|---|---|---|---|---|
siteId | string | path | Yes | The siteId from endpoint 1. |
token | string | query | Yes | The pollToken from endpoint 1. Missing token → 400. |
Example request
curl "https://jinstant.com/api/v1/trial-sites/$SITE_ID?token=$POLL_TOKEN" \
-H "Authorization: Bearer $JINSTANT_API_KEY"Status lifecycle
The status field moves through these values while you poll:
| status | Terminal? | Meaning |
|---|---|---|
queued | No | Job accepted, waiting for a provisioning slot. |
provisioning | No | Actively building the Joomla environment. |
ready | Yes | Site is running. Credentials available on first read. |
failed | Yes | Provisioning failed. Check the "error" field. |
progressStage provides finer-grained machine-readable stages:queued → leasing_warm_instance → creating_files → starting_containers → waiting_for_joomla → configuring_routing → ready / failed.
Response examples
In progress
{
"status": "provisioning",
"progressStage": "waiting_for_joomla",
"progressMessage": "Almost there. Finishing setup for Joomla 6 / PHP 8.3.",
"error": null,
"result": null
}Ready
{
"status": "ready",
"progressStage": "ready",
"progressMessage": "Joomla 6 / PHP 8.3 is ready.",
"error": null,
"result": {
"slug": "ab3k9m2q8n",
"siteUrl": "https://ab3k9m2q8n.jinstant.com",
"expiresAt": "2026-06-20T21:05:00.000Z",
"credentials": {
"username": "admin",
"password": "s3cr3t-one-time-pw",
"administratorUrl": "https://ab3k9m2q8n.jinstant.com/administrator/",
"magicLoginUrl": "https://ab3k9m2q8n.jinstant.com/administrator/instant-login-xxxx.php"
}
}
}One-time credentials
The credentials block — password, administratorUrl, and magicLoginUrl — is returned only on the first poll that observes status: "ready". The server marks them consumed on that read. Subsequent polls still return result (slug, siteUrl, expiresAt) but with credentials: null.
Capture and store the credentials from the first ready response.
Failed
{
"status": "failed",
"progressStage": "failed",
"progressMessage": "Provisioning failed",
"error": "Provisioning failed",
"result": null
}Response fields
| Name | Type | Description |
|---|---|---|
status | string | queued | provisioning | ready | failed |
progressStage | string | null | Fine-grained stage name. |
progressMessage | string | null | Human-readable status text. |
error | string | null | Populated when status is "failed". |
result | object | null | null until ready; the site details once ready (see below). |
result.slug | string | The site's subdomain label. |
result.siteUrl | string | Public URL of the running Joomla site. |
result.expiresAt | string (ISO 8601) | When the site auto-deletes (created + 4 hours). |
result.credentials | object | null | Admin login details — returned once. null on subsequent polls. |
result.credentials.username | string | Admin username. |
result.credentials.password | string | Plaintext admin password. |
result.credentials.administratorUrl | string | Direct URL to the Joomla /administrator/ panel. |
result.credentials.magicLoginUrl | string | One-click auto-login URL — no password required. |
Polling strategy
- Poll endpoint 2 every ~2 seconds.
- Stop when
status === "ready"(capture credentials immediately) orstatus === "failed"(readerror). - Recommended timeout budget: 2–5 minutes. Most sites provision in under a minute when a warm-pool instance is available.
Complete example (Node.js)
This script creates a site, polls until it is ready, and logs the result. Credentials are captured on the first ready response.
const BASE = "https://jinstant.com";
const KEY = process.env.JINSTANT_API_KEY;
async function createTrialSite() {
// 1) Create the job
const create = await fetch(`${BASE}/api/v1/trial-sites`, {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ joomlaVersion: "6", phpVersion: "8.3" }),
});
if (create.status !== 202) throw new Error(`Create failed: ${create.status}`);
const { siteId, pollToken } = await create.json();
// 2) Poll until ready or failed (≈5 min budget)
const deadline = Date.now() + 5 * 60 * 1000;
while (Date.now() < deadline) {
const res = await fetch(
`${BASE}/api/v1/trial-sites/${siteId}?token=${encodeURIComponent(pollToken)}`,
{ headers: { Authorization: `Bearer ${KEY}` } }
);
const body = await res.json();
if (body.status === "ready") {
// 3) Capture credentials NOW — they are returned only once.
console.log("Site URL:", body.result.siteUrl);
console.log("Login:", body.result.credentials);
return body.result;
}
if (body.status === "failed") throw new Error(body.error ?? "Provisioning failed");
await new Promise((r) => setTimeout(r, 2000));
}
throw new Error("Timed out waiting for the site to become ready.");
}Site lifetime
Trial sites created via the API have a fixed 4-hour lifetime. They are automatically and permanently deleted on expiry, with no backups, consistent with the Terms of Use. The exact deletion time is in result.expiresAt.
Versions reference
Joomla / PHP matrix
| joomlaVersion (API) | Provisions | Allowed phpVersion |
|---|---|---|
"5" | Joomla 5.4 | "8.1", "8.2", "8.3" |
"6" (default) | Joomla 6.1 | "8.3" (default), "8.4" |
You choose the major line ("5" or "6") and always get the latest release we support on it. Unsupported combinations (e.g. joomlaVersion: "6" with phpVersion: "8.1") return 400 Bad Request.
Errors
All error responses use JSON: { "error": "message" }.
| HTTP | Meaning | Typical cause |
|---|---|---|
400 | Bad Request | Malformed JSON; unsupported joomlaVersion / phpVersion; unsupported combination; (endpoint 2) missing token. |
401 | Unauthorized | Missing, malformed, invalid, or revoked API key. |
404 | Not Found | No job matches that siteId + token for the authenticated user. |
409 | Conflict | Account already at its concurrent-site limit (default 3). Delete a site to free a slot. |
429 | Too Many Requests | More than 3 create attempts per 60-minute window from one IP. |
500 | Internal Server Error | Unexpected provisioning or server failure. |
Note
A malformed JSON body is rejected with 400 before authentication is checked. All other validation happens after the key is verified — so a bad key returns 401 even when the body is also invalid.
Rate limits & quotas
- Create rate limit: 3
POSTattempts per 60-minute window, per IP. Exceeding this returns429. - Concurrent-site quota:3 active sites per account (a site is "active" when its status is
queued,provisioning,ready,failed, ordeleting). Exceeding this returns409. Delete a site from your dashboard to free a slot.
Next steps
- Open your dashboard to manage sites and create an API key.
- Terms of Use — usage policy, site lifetime, and prohibited use.
- Privacy Policy.