Skip to content

API Authentication

The enconf REST API provides programmatic access to all hosting features. This page describes the available authentication methods, the token format and rate limiting.


Base URL

All API endpoints are available at the following base URL:

https://your-panel.com:3443/api/v1

Port 3443

The panel runs on port 3443 by default. The API is accessible on the same port.

Interactive API Documentation

A complete, interactive API reference with all endpoints, parameters and example responses is available directly in your panel:

https://your-panel.com:3443/api/docs

You can test all API calls directly in your browser (Swagger UI). Authenticate via the Authorize button using your API key or JWT token.

For WHMCS / HostBill developers

The OpenAPI specification (YAML) is available at https://your-panel.com:3443/api/docs/openapi.yaml and can be imported directly into your development environment.


Authentication Methods

The API supports two authentication methods:

Method Use Case Validity
JWT Token Interactive use, frontend Configurable (default: 24 hours)
API Key Automation, scripts, integrations Until expiration date or manual deletion

JWT Token (Login)

For interactive use, authenticate with email and password to receive a JWT token.

Login Request

POST /api/v1/auth/login
Content-Type: application/json

{
  "email": "customer@example.com",
  "password": "YourPassword"
}

Successful Response

{
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "user": {
      "id": 42,
      "email": "customer@example.com",
      "name": "John Doe",
      "role": "customer"
    }
  },
  "error": null,
  "message": "Login successful"
}

Login with 2FA

If two-factor authentication is enabled, the login additionally requires a TOTP code:

POST /api/v1/auth/login
Content-Type: application/json

{
  "email": "customer@example.com",
  "password": "YourPassword",
  "totp_code": "123456"
}

If the TOTP code is missing and 2FA is enabled, the API responds with:

{
  "data": null,
  "error": "2fa_required",
  "message": "Two-factor authentication code required"
}

Using the Token

Send the token in the Authorization header with all subsequent requests:

GET /api/v1/sites
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Token Validity

Setting Default Value
Validity Period 24 hours (configurable by admin)
Algorithm HS256 (HMAC-SHA256)

After the token expires, you must log in again.


API Keys

API keys are ideal for automation, deployment scripts and integrations with third-party systems.

Create API Key

POST /api/v1/auth/api-keys
Authorization: Bearer <jwt-token>
Content-Type: application/json

{
  "name": "Deployment Script",
  "expires_at": "2027-12-31T23:59:59Z"
}
Field Required Description
name Yes Label (1–100 characters)
expires_at No Expiration date in RFC 3339 format

Response

{
  "data": {
    "id": 1,
    "name": "Deployment Script",
    "key": "ncp_a1b2c3d4e5f6...",
    "key_prefix": "ncp_a1b2c3d4e5f6",
    "expires_at": "2027-12-31T23:59:59Z",
    "created_at": "2026-03-31T10:00:00Z"
  },
  "error": null,
  "message": "API key created"
}

Key Visible Only Once

The key field is returned only in this response. Store the key securely immediately. Only a SHA-256 hash of the key is stored in the database — the plaintext cannot be recovered.

Using an API Key

Send the key in the Authorization header:

GET /api/v1/sites
Authorization: Bearer ncp_a1b2c3d4e5f6...

List API Keys

GET /api/v1/auth/api-keys
Authorization: Bearer <jwt-token>

Response:

{
  "data": [
    {
      "id": 1,
      "name": "Deployment Script",
      "key_prefix": "ncp_a1b2c3d4e5f6",
      "last_used_at": "2026-03-30T14:22:00Z",
      "expires_at": "2027-12-31T23:59:59Z",
      "created_at": "2026-03-31T10:00:00Z"
    }
  ],
  "error": null,
  "message": ""
}

key_prefix

The key_prefix shows the first 20 characters of the key and serves for identification. The full key is never displayed again.

Delete API Key

DELETE /api/v1/auth/api-keys/:id
Authorization: Bearer <jwt-token>

Key Format

API keys use the following format:

ncp_<64 hex characters>
  • Prefix: ncp_ (NetCell Panel)
  • 32 bytes of random data, hex-encoded
  • Total length: 68 characters

Response Format

All API responses use a consistent JSON format:

{
  "data": { ... },
  "error": null,
  "message": "Description"
}
Field Type Description
data Object/Array/null The requested data
error String/null Error description (null on success)
message String Human-readable message

Error Responses

HTTP Status Meaning
400 Bad request (missing or invalid parameters)
401 Not authenticated (token missing or invalid)
403 Forbidden (insufficient role or resource belongs to another customer)
404 Resource not found
409 Conflict (e.g. duplicate)
422 Validation error
429 Too many requests (rate limit exceeded)
500 Internal server error

Example error response:

{
  "data": null,
  "error": "not authenticated",
  "message": "Authentication required"
}

Brute-Force Protection

The panel protects login and password reset against automated attacks using a cumulative failed-attempt counter per IP (not a per-minute sliding window).

Endpoint Behaviour
Login (/auth/login) 5 failed attempts within 15 minutes → IP is locked out for 15 minutes
Password Reset (/auth/forgot-password) Shares the same counter — a reset request counts as one failed attempt for the IP

Thresholds are configurable under Settings > Security > Login Protection (login_max_attempts, login_lockout_minutes).

On lockout the API responds with HTTP status 429:

{
  "data":    { "remaining_seconds": 812 },
  "error":   "too_many_attempts",
  "message": "Too many failed attempts. Please retry in 14 minutes."
}

No Global Rate Limit

For authenticated endpoints (Bearer token / X-API-Key) there is currently no additional request rate limit. Abuse is caught on the transport layer via fail2ban and on the login layer via the brute-force lockout above.


Subscription Context

Customer endpoints require the context of a subscription. Pass the subscription ID as a query parameter:

GET /api/v1/sites?subscription_id=5
Authorization: Bearer <token>

If the parameter is missing and the customer has multiple subscriptions, the default subscription is used.


Examples

cURL

# Login
TOKEN=$(curl -s -X POST https://panel.example.com:3443/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"customer@example.com","password":"secret"}' \
  | jq -r '.data.token')

# List websites
curl -s https://panel.example.com:3443/api/v1/sites?subscription_id=1 \
  -H "Authorization: Bearer $TOKEN" | jq

# With API key
curl -s https://panel.example.com:3443/api/v1/sites?subscription_id=1 \
  -H "Authorization: Bearer ncp_a1b2c3d4..." | jq

Python

import requests

BASE_URL = "https://panel.example.com:3443/api/v1"

# Login
resp = requests.post(f"{BASE_URL}/auth/login", json={
    "email": "customer@example.com",
    "password": "secret"
})
token = resp.json()["data"]["token"]

headers = {"Authorization": f"Bearer {token}"}

# List websites
sites = requests.get(f"{BASE_URL}/sites",
    headers=headers,
    params={"subscription_id": 1}
)
print(sites.json())

PHP

<?php
$baseUrl = 'https://panel.example.com:3443/api/v1';
$apiKey  = 'ncp_a1b2c3d4...';

$ch = curl_init("$baseUrl/sites?subscription_id=1");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer $apiKey",
        "Content-Type: application/json",
    ],
]);

$response = curl_exec($ch);
$data = json_decode($response, true);
print_r($data);