Skip to content

API Reference

FOSSBilling provides a REST API for integrating external systems and building custom functionality on top of the platform.

Three main entrypoints:

EndpointAccess LevelPurpose
/api/admin/*Admin onlySystem management
/api/client/*Authenticated clientsClient services
/api/guest/*PublicNo authentication needed
  • Method: Core API routes generally accept GET and POST. Guest client login/signup and staff login require POST. Use POST for mutations and requests with a JSON body or form data.
  • Format: JSON responses. POST requests may send JSON or form data.
  • Naming: Lowercase with underscores (change_password)
  • Nulls: Blank fields are included as null, not omitted
  • Dates: ISO 8601 format

Use HTTP Basic Auth with base64 encoding:

  • Username: admin or client (depending on endpoint)
  • Password: Your API key (found in client profile or admin dashboard)
Authorization: Basic base64_encode('admin:YOUR_API_KEY')

Most HTTP clients (curl, Postman) handle the encoding automatically.

Browser requests from an active client or admin session use the session cookie instead. Those requests must include a valid CSRF token.

CSRF protection applies to session-authenticated client and admin browser API calls. It also applies to guest client login/signup, staff login, and cart mutations. External client and admin calls authenticated with API keys do not require CSRF tokens.

For browser calls, FOSSBilling accepts the token in any of these places:

  • CSRFToken in the JSON body
  • CSRFToken in form data (query parameters are also accepted except for guest authentication)
  • X-CSRF-Token request header

The token must match the server-side session token. For session-authenticated client and admin calls, a nonempty CSRF cookie must match it too. The bundled JavaScript API wrapper reads the fossbilling_csrf cookie and adds the token automatically to same-origin requests. Sending a cookie without a token in the request is insufficient.

Load a FOSSBilling page first to establish the session, then retain the session cookie and submit its token. These guest endpoints require a session-bound CSRF token:

  • client/login, client/create, and staff/login: POST only, with the token in the JSON/form body or X-CSRF-Token header.
  • cart/add_item, cart/remove_item, cart/apply_promo, cart/remove_promo, cart/reset, and cart/set_currency: GET or POST, with the token in the request. Prefer POST for mutations.

These checks apply even when api.CSRFPrevention is disabled. A supplied Origin must match the configured FOSSBilling origin, and Sec-Fetch-Site: cross-site is rejected. Serve custom browser forms from the same origin. Server-side guest integrations must retain the session and submit its token too.

Other guest calls are not subject to this authentication/cart CSRF check. See the migration guide for migration details.

Use Twig helpers for theme and module templates. This way, you don't need to manually attach CSRF tokens to the requests:

<form action="{{ 'profile/update'|api_url }}" {{ fb_api_form({ message: 'Saved'|trans }) }}>
<input type="text" name="first_name">
<button type="submit">{{ 'Save'|trans }}</button>
</form>

For raw fetch() requests, send the token yourself:

const token = document.cookie.match(/fossbilling_csrf=([^;]*)/)?.[1] || '';
fetch('/api/client/profile/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': decodeURIComponent(token),
},
body: JSON.stringify({ first_name: 'Jane' }),
});
Terminal window
curl -X POST "https://example.com/api/admin/staff/create" \
-H "Authorization: Basic $(echo -n 'admin:YOUR_API_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{
"email": "hello@fossbilling.org",
"password": "Testing123+",
"name": "John Doe",
"admin_group_id": 1,
"status": "active"
}'

Success:

{
"result": { ... },
"error": null
}

Error:

{
"result": null,
"error": {
"message": "Error description",
"code": 123
}
}

Error codes in the HTTP range 400–599 use that HTTP status, except application codes 413, 436, 437, and 498, which use HTTP 400. The original code stays in error.code. Application codes 201–206, 1002, and 1004 use HTTP 401; 701 and 879 use 400; and 740 uses 404. Other application errors can still return HTTP 200.

Read the JSON body on non-200 responses and check both the HTTP status and the error field. For example:

const response = await fetch('/api/guest/currency/get_pairs', {
headers: { Accept: 'application/json' },
});
const data = await response.json();
if (data.error) {
throw new Error(`${data.error.message} (code ${data.error.code})`);
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
console.log(data.result);

For HTTP libraries that throw on non-2xx responses, read the JSON body from the exception's response. Handle non-JSON proxy or web-server failures separately.

/api/{role}/{module}/{action}

Examples:

  • /api/admin/client/get_list
  • /api/client/profile/get
  • /api/guest/system/periods

List endpoints typically accept:

  • page — Page number (starting at 1)
  • per_page — Items per page

Paginated results use the FOSSBilling\Paginator class.