Overview #

All endpoints are REST calls with JSON responses. A successful response always has "success": true and the payload in the "data" object; an error has "success": false and an "error" message.

Base URL All requests are sent over HTTPS.
https://api.resellerunion.com/v1/
Use the exact address above Send every request directly to the address shown — over HTTPS, without a www. prefix and without any other host variant. Under the HTTP standard (RFC 7231) most HTTP clients turn a POST into a GET when they follow a 301 redirect, so a request that reaches the API through a redirect arrives as GET and the API answers Method not allowed. Use POST.

The same applies to the sandbox. If your client follows redirects, disable that option and use the exact address from the start.
Where do the parameter values come from? Everything you send in orders comes from the catalog endpoints: extensions, domain prices and the additional fields an extension requires from price_list.php, hosting packages (their uuid and available cycles) from hosting_offer.php. Existing services and their uuid identifiers come from my_domains.php and my_hosting.php.
Identification by UUID only All services (domains, hosting) are identified in API calls by the public uuid identifier you receive in the responses. Internal numeric identifiers do not exist at the API boundary.

Authentication #

Every request is authenticated with two headers that always go together as a pair:

HeaderDescription
X-API-UUID The UUID of your reseller account. Visible in the control panel.
X-API-KEY Your personal reseller API key; it can be regenerated at any time.
GET https://api.resellerunion.com/v1/price_list.php
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key
Exception: domain check Credentials are optional only for whois.php. If you do send them, they still go as a pair — sending only one of the two headers returns 401.
Security notes All API calls must be made from server-side code. Never expose X-API-KEY in frontend/JavaScript code. The system logs every access attempt with an invalid key.

Errors and limits #

HTTP codeMeaning
400Invalid input (missing field, wrong format) or a business error (e.g. domain taken, cycle unavailable, extension not in the offer)
401Missing or invalid credentials (X-API-UUID / X-API-KEY)
405Wrong HTTP method for the endpoint
429Rate limit exceeded
500Internal server error
502Backend system temporarily unavailable — try again
Rate limits (per IP address) Domain check (whois.php): 60 requests per minute. All action POST endpoints (orders, transfers, renewals, package changes, service management, EPP, nameservers, contacts, registrant change): 30 requests per minute per IP address. Exceeding the limit returns 429.
// Error example
{
  "success": false,
  "error":   "Field \"package_uuid\" is required."
}

Sandbox #

A test environment for developing your integration. Same paths and same response format as production, but without any real data and without consequences.

BASE https://sandbox.resellerunion.com/v1

Same paths as production — just replace the base address. The list of available endpoints is further down on this page.

Credentials

They are public and the same for everyone — you do not need an account:

X-API-UUID: 00000000-0000-4000-8000-000000000001
X-API-KEY:  sandbox_kljuc_za_testiranje_1234567

How it behaves

BehaviourDescription
StatelessThe sandbox remembers nothing between requests.
Ordersorder_* return success, but the order is not executed. No proforma invoice is created and nothing is charged.
Renewals and managementrenew_*, manage_*, upgrade_hosting, transfer_domain, contacts and change_registrant validate input and status like production and return a response of the same shape, but change nothing. Proforma invoices in the response are simulated.
Listsmy_* always return the same fixed list. An ordered item will not appear in it.
ValidationIdentical to production — you can also test failure paths (invalid uuid, private IP address, unsupported cycle, non-existent package).
Price levelThe sandbox account is on level 2 (Advanced).
The sandbox cannot be mistaken for production Every response carries "sandbox": true and a sandbox_napomena field, and order responses additionally carry sandbox_upozorenje. The HTTP headers include X-Sandbox: true.

Example

POST https://sandbox.resellerunion.com/v1/order_license.php
Content-Type: application/json; charset=utf-8
X-API-UUID:   00000000-0000-4000-8000-000000000001
X-API-KEY:    sandbox_kljuc_za_testiranje_1234567

{
  "package_uuid": "aaaaaaaa-0000-4000-8000-000000000001",
  "cycle": "monthly",
  "ip": "203.0.113.50"
}
// Response
{
  "success": true,
  "sandbox": true,
  "sandbox_napomena": "Test environment (sandbox). The data is fictitious…",
  "data": {
    "sandbox_upozorenje": "SANDBOX: the order was simulated and NOT executed…",
    "proforma_invoice": { "number": "SB-2026-04128", "total": "61.51" },
    "order":  { "order_number": "RSL-4820193756", "status": 1 },
    "license":   { "name": "cPanel Admin Cloud", "ip": "203.0.113.50", "status": 1 }
  }
}

Available endpoints

MethodPath
GET/v1/price_list.php
GET/v1/whois.php
POST/v1/order_domain.php
POST/v1/transfer_domain.php
POST/v1/renew_domain.php
POST/v1/epp_code.php
GET POST/v1/nameservers.php
GET POST/v1/contacts.php
GET POST/v1/change_registrant.php
GET/v1/my_domains.php
GET/v1/hosting_offer.php
POST/v1/order_hosting.php
GET/v1/my_hosting.php
POST/v1/renew_hosting.php
POST/v1/upgrade_hosting.php
POST/v1/manage_hosting.php
GET/v1/license_offer.php
POST/v1/order_license.php
GET/v1/my_licenses.php
POST/v1/renew_license.php
POST/v1/manage_license.php
GET/v1/dedicated_offer.php
POST/v1/order_dedicated.php
GET/v1/my_dedicated.php
POST/v1/renew_dedicated.php
POST/v1/manage_dedicated.php
GET/v1/my_profile.php
GET/v1/credit.php
GET/v1/my_documents.php
GET POST/v1/settings.php
Testing the WHMCS modules against the sandbox The API base is fixed inside the modules. For testing, temporarily change the resellerba_*_apiBase() function so that it returns https://sandbox.resellerunion.com/v1 — and change it back before going to production.

Domain price list #

GET /v1/price_list.php

Returns all domain extensions offered on your platform with registration and renewal prices for your price level, plus the currency. This is the source of the values for domain registration and transfer, as well as of the additional fields that some extensions require.

The optional query parameter ?lang=en|es|de|fr sets the language of the names and descriptions of the additional fields. Without it, the platform's default language is used.

Example request

GET https://api.resellerunion.com/v1/price_list.php
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

Response

{
  "success": true,
  "data": {
    "level": 2,
    "currency": "EUR",
    "decimal_separator": ".",
    "total_count": 42,
    "domains": [
      {
        "extension": ".com",
        "featured": true,
        "registration_price": "12.90",
        "renewal_price": "14.90",
        "registration_periods": {
          "1": "12.90",
          "2": "25.80",
          "3": "38.70",
          "4": "51.60",
          "5": "64.50"
        },
        "custom_fields": []
      },
      {
        "extension": ".us",
        "featured": false,
        "registration_price": "9.90",
        "renewal_price": "9.90",
        "registration_periods": {
          "1": "9.90",
          "2": "19.00",
          "5": "45.00"
        },
        "custom_fields": [
          {
            "slot": 1,
            "required": true,
            "type": "dropdown",
            "name": "Nexus category",
            "description": "The registrant's connection to the United States, as required by the .us registry.",
            "options": ["C11", "C12", "C21", "C31", "C32"],
            "validation": "^(C11|C12|C21|C31|C32)$"
          },
          {
            "slot": 2,
            "required": true,
            "type": "dropdown",
            "name": "Application purpose",
            "description": "The intended use of the domain, as required by the .us registry.",
            "options": ["P1", "P2", "P3", "P4", "P5"],
            "validation": "^(P1|P2|P3|P4|P5)$"
          }
        ]
      }
    ]
  }
}
Registration periods per extension The registration_periods object contains only the periods offered for that extension — the key is the number of years, the value is the total price for the whole period. A period missing from the object cannot be ordered (in the example above, .us offers 1, 2 and 5 years; 3 and 4 are not available). The period value sent at domain registration must be one of these keys.
Additional fields per extension The custom_fields array is filled only for extensions that require additional fields; for all others it is empty. Every listed field is required — without it domain registration returns an error.

slot is the ordinal number (1–6) and is sent back as the key in the custom_fields object when ordering. The name is display text and may change; the slot never changes — bind to the slot.

type can be check (checkbox; value "true"), input (free text) or dropdown. A dropdown also comes with an options array of allowed values.

validation is a regular expression without delimiters, the same one the server uses to check the value. It is sent so that you can validate the input before submitting and show the user an error immediately.

Hosting offer #

GET /v1/hosting_offer.php

Returns all hosting packages offered on your platform with prices for your price level across all available billing cycles. From this response you take the package uuid and the cycle name for the hosting order.

Example request

GET https://api.resellerunion.com/v1/hosting_offer.php
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

Response (abbreviated)

{
  "success": true,
  "data": {
    "level": 2,
    "currency": "EUR",
    "total_count": 6,
    "packages": [
      {
        "uuid": "3f2a1b6c-9d4e-4f70-8a21-5e6d7c8b9a01",
        "name": "Business",
        "disk_space": "10 GB",
        "bandwidth": "Unlimited",
        "requires_domain": true,
        "prices": {
          "monthly": "9.90",
          "annually": "99.00"
        }
      }
    ]
  }
}
A cycle that is not in the response is not offered The prices object of each package contains only the cycles available for that package and your level. Sending an order with a cycle that is not in the package's offer returns an error — a price is never made up.

Check domain availability #

GET /v1/whois.php

Checks whether the requested domain is available for registration. Only extensions that are in the reseller offer for your platform are supported (see the price list). Trying to check an extension outside the offer returns an error.

GET parameters

ParameterTypeRequiredDescription
domain string YES Full domain name including the extension (e.g. example.com, example.co.uk)
format string NO text = plain-text response for WHMCS (see below). Without the parameter: JSON.
Credentials are optional If you send credentials, X-API-UUID and X-API-KEY go together as a pair — sending only one returns 401.

Example request

GET https://api.resellerunion.com/v1/whois.php?domain=example.com

Response

{
  "success": true,
  "data": {
    "domain":    "example.com",
    "extension": ".com",
    "available": true
  }
}

Text format (WHMCS whois.json)

With the format=text parameter the endpoint returns plain text — intended for the WHMCS whois.json "https://" lookup. The response is always HTTP 200 (WHMCS compares the body, not the HTTP code):

STATUS: AVAILABLE
STATUS: REGISTERED
STATUS: ERROR: <message>

Example whois.json entry. The same entry works for any extension in the offer, including extensions that have no public port-43 whois server — list the extensions you need:

{
  "extensions": ".com,.net",
  "uri":        "https://api.resellerunion.com/v1/whois.php?format=text&domain=",
  "available":  "STATUS: AVAILABLE"
}

Register domain #

POST /v1/order_domain.php

Creates a domain registration order. The domain must be available (the system performs the check) and the extension must be in your platform's offer. The price is calculated according to your price level.

POST JSON fields

FieldTypeRequiredDescription
domainstringYESFull domain name (e.g. example.us)
periodintegerYESNumber of registration years: 1–5. Only a period that exists in registration_periods for that extension in the price list is allowed — every period has its own total price. An unavailable period returns an error.
registrantobjectYESRegistrant details — see Registrant details
nameserversarrayYESAt least 2, at most 5 hostnames. Each must be different. The registry rejects a domain with fewer than two nameservers, so an order without them is not accepted.
custom_fieldsobject*Required if the extension requires additional fields — see custom_fields in the price list. The key is the slot as a string, the value is text.

Example request

POST https://api.resellerunion.com/v1/order_domain.php
Content-Type: application/json; charset=utf-8
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

{
  "domain": "example.us",
  "period": 1,
  "registrant": {
    "is_company": 0,
    "first_name": "John",
    "last_name": "Smith",
    "address": "123 Main Street",
    "city": "Springfield",
    "postal_code": "62701",
    "country": "US",
    "email": "john@example.com",
    "phone": "+12025550142"
  },
  "nameservers": ["ns1.example.com", "ns2.example.com"],
  "custom_fields": {
    "1": "C11",
    "2": "P3"
  }
}
Nameservers are required At least two are needed and they must be different. The check is done before the order and the proforma invoice are created, so an order without them never comes into existence and nothing is charged. Default nameservers are not substituted — a nameserver you did not specify is never made up.
Additional fields Before ordering, read the custom_fields for that extension from price_list.php. Every active field is required; the value must satisfy the validation regex and, for a dropdown, be one of the values in the options array.

For a field of type check the text "true" is sent (or JSON true, which the server converts to the same thing).

A value sent for a slot that the extension does not require is rejected with an error — that is a sign you are working from an outdated field definition.

Response

The response is nested: data contains four objects — order, domain, proforma_invoice and currency. The order UUID is data.order.uuid and the domain UUID is data.domain.uuid — not data.uuid.

{
  "success": true,
  "data": {
    "order": {
      "uuid": "945bda1a-2a36-4f7e-acfd-4c3cfd158a99",
      "order_number": "RSL-3430439926",
      "status": 1
    },
    "domain": {
      "uuid": "4dd69549-68df-4cf7-9bd5-dc73b38acc8d",
      "domain": "example.us",
      "extension": ".us",
      "registration_period": 1,
      "level": 2,
      "price": "58.67",
      "status": 1,
      "nameservers": ["ns1.example.com", "ns2.example.com"],
      "custom_fields": {
        "1": "C11",
        "2": "P3"
      }
    },
    "proforma_invoice": {
      "proforma_number": "1564",
      "subtotal": "50.15",
      "vat_amount": "8.52",
      "total": "58.67",
      "currency": "€",
      "status": "unpaid"
    },
    "currency": {
      "code": "EUR",
      "prefix": "",
      "suffix": "€",
      "position": "after",
      "space": 1,
      "rate": "1.000000"
    },
    "decimal_separator": "."
  }
}
Common mistake data.uuid does not exist. There are data.order.uuid (the order) and data.domain.uuid (the domain) — two different objects and two different UUIDs. To track the domain through my_domains.php use data.domain.uuid.
Currency always comes from the response The currency code, symbol and position are returned in the currency object of every order response and in the catalog endpoints. Never assume them in your integration — read them from the response.
custom_fields Present only when the extension requires additional fields. The key is the slot as a string, the same one returned by price_list.php.

Transfer domain #

POST /v1/transfer_domain.php

Creates a transfer order for a domain to your account. The domain must be registered (for a free domain use registration). The transfer price is the registration price for your level and includes one year of renewal.

POST JSON fields

FieldTypeRequiredDescription
domainstringYESFull domain name
periodintegerYESOnly 1
eppcodestringYESEPP / authInfo code from the current registrar
registrantobjectYESSee Registrant details
nameserversarrayNOWithout them the domain keeps its current nameservers. If sent: at least 2, at most 5
custom_fieldsobjectdepends on extensionSame as for registration

Flow

After payment the transfer is started at the registry and the domain gets status 2 (transfer pending). When the current registrar confirms the transfer, the domain moves to status 3 (active).


Renew domain #

POST /v1/renew_domain.php

Creates a proforma invoice to renew the domain for the period it is registered for. The domain is identified by its uuid from my_domains.php. With automatic renewal enabled and enough credit, the proforma invoice is charged from credit and the domain is renewed at the registry (within a few minutes).

POST https://api.resellerunion.com/v1/renew_domain.php
Content-Type: application/json; charset=utf-8
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

{
  "uuid": "9c1f4a2e-7b3d-4e58-a690-1f2e3d4c5b6a"
}

Response

{
  "success": true,
  "data": {
    "proforma_invoice": { "proforma_number": "1043", "total": "23.00", "currency": "€", "status": "unpaid" },
    "domain": {
      "uuid": "9c1f4a2e-…", "domain": "example.com", "period_years": 1,
      "post_expiry_period": "regular", "renewal_price": "23.00",
      "grace_fee": "0.00", "redemption_fee": "0.00",
      "expires_at": "2026-10-02", "new_expires_at": "2027-10-02"
    },
    "auto_renewal": { "enabled": true, "message": "…" }
  }
}

post_expiry_period: regular, grace or redemption. In the grace and redemption periods the fee is a separate proforma item. A deleted domain (status 10), a suspended one and a pending one cannot be renewed (409). If an unpaid renewal proforma invoice already exists for the domain, the response is 409 with its number.


EPP code #

POST /v1/epp_code.php

Sends the domain's EPP (authInfo) code to the registrant's email. The domain is identified by its uuid. For security reasons the code is never returned in the API response.

{
  "uuid": "9c1f4a2e-7b3d-4e58-a690-1f2e3d4c5b6a"
}

Domain nameservers #

GET POST /v1/nameservers.php

GET ?uuid=<uuid> returns the domain's current nameservers. POST changes the nameservers at the registry.

POST JSON fields

FieldTypeRequiredDescription
uuidstringYESDomain UUID
nameserversarrayYESList of up to 5 hostnames
{
  "uuid": "9c1f4a2e-7b3d-4e58-a690-1f2e3d4c5b6a",
  "nameservers": ["ns1.example.com", "ns2.example.com"]
}

Domain contacts #

GET POST /v1/contacts.php

GET ?uuid=<uuid> returns the domain's contacts (Registrant, Admin, Tech). POST changes contacts at the registry — free of charge. You can send registrant, admin and tech blocks (at least one). For the registrant the address, city, postal code, state, country, email and phone are changed; the name and company are not changed this way — that is a change of domain owner and goes through change_registrant.php.

{
  "uuid": "9c1f4a2e-7b3d-4e58-a690-1f2e3d4c5b6a",
  "registrant": { ... contact fields, without name and company ... },
  "admin": { ... contact fields ... },
  "tech":  { ... contact fields ... }
}

Contact fields

name, email_address, address1, city, state_province, postal_code, country (ISO-2), phone (format +387.61123456). For admin and tech name and email_address are required; for the registrant name is ignored.


Change of domain owner (registrant) #

GET POST /v1/change_registrant.php

This is charged. A change of owner means a change of the company name (registrant is a company) or of the first and last name (registrant is an individual). The other details of the new owner are sent along with it. Changing only the address, email, phone and similar is free and goes through contacts.php — this endpoint rejects it.

Available only for extensions that support an owner change and have a change price for your level; for the others the response is 409.

GET ?uuid=<domain uuid>

Returns the current registrant (from the registry), the change price (change_price) and billable_change: company or full_name — the field that has to change. If a request is already waiting for payment, it returns pending_request: true and that request's data.

POST JSON fields

FieldRequiredDescription
uuidYESDomain UUID
companycompany: YESNew company name — must differ from the current one
first_name, last_nameindividual: YESNew first and last name — must differ from the current ones. For a company: contact person (optional)
address, city, postal_code, state, countryYES (except postal_code, state)New owner's address (country = ISO-2)
phone, emailYESNew owner's contact

POST creates the request and a proforma invoice. After payment the change is applied at the registry automatically. An unpaid request is cancelled with {"uuid": "…", "action": "cancel"}.


Order hosting #

POST /v1/order_hosting.php

Creates a hosting package order and the corresponding proforma invoice. You take the package and the cycle from hosting_offer.php — the order goes through only for a cycle that is in that package's offer.

POST JSON fields

FieldTypeRequiredDescription
package_uuidstringYESPackage uuid from the hosting offer
cyclestringYESCycle name — see Billing cycles
domainstringNO*The service's domain. Required if the package has requires_domain: true.

Example request

POST https://api.resellerunion.com/v1/order_hosting.php
Content-Type: application/json; charset=utf-8
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

{
  "package_uuid": "3f2a1b6c-9d4e-4f70-8a21-5e6d7c8b9a01",
  "cycle": "annually",
  "domain": "example.com"
}

Response

The response is nested: data contains order, service, proforma_invoice, auto_activation and currency. The service UUID is data.service.uuid.

{
  "success": true,
  "data": {
    "order": {
      "uuid": "e7a0565d-a746-456e-8938-68412977e573",
      "order_number": "RSL-3036365111",
      "status": 1
    },
    "service": {
      "uuid": "c3c3b3f0-db2f-42cc-a195-99e6a97aedb8",
      "package": "START HOSTING",
      "cycle": "annually",
      "cycle_months": 12,
      "domain": "example.com",
      "level": 1,
      "price": "54.40",
      "status": 1,
      "dedicated_ip": false,
      "package_price": "54.40",
      "dedicated_ip_price": null
    },
    "proforma_invoice": {
      "proforma_number": "1564",
      "subtotal": "46.50",
      "vat_amount": "7.90",
      "total": "54.40",
      "currency": "€",
      "status": "unpaid"
    },
    "auto_activation": {
      "enabled": true,
      "message": "Automatic activation: the available credit covers the proforma invoice amount."
    },
    "currency": {
      "prefix": "",
      "suffix": "€",
      "position": "after",
      "space": 1
    },
    "decimal_separator": "."
  }
}
Common mistake data.uuid does not exist. The service UUID is data.service.uuid and the order UUID is data.order.uuid.
Dedicated IP When ordered, price INCLUDES it — the document has one line item, not two. package_price and dedicated_ip_price are informative split amounts.

My hosting services #

GET /v1/my_hosting.php

List of your hosting services. Parameters: ?limit=50&offset=0 (optional) or ?uuid=<uuid> for a single service. For each service it returns: uuid, package, domain, status, price, cycle, dates, disk/bandwidth usage and the order number.

Service statusMeaning
1Pending
2In progress
3Active

License offer #

GET /v1/license_offer.php

The complete license offer with prices according to your price level. Licenses are grouped into categories, and each carries a uuid that you use when ordering.

Example request

GET https://api.resellerunion.com/v1/license_offer.php
X-API-UUID: 550e8400-e29b-41d4-a716-446655440000
X-API-KEY:  your_api_key

Response (abbreviated)

{
  "success": true,
  "data": {
    "level": 2,
    "currency": { "code": "EUR", "suffix": "€", "position": "after", "space": 1 },
    "decimal_separator": ".",
    "categories": [ { "name": "cPanel/WHM" }, { "name": "CloudLinux" } ],
    "total_count": 24,
    "licenses": [
      {
        "uuid":         "3f2a1b6c-9d4e-4f70-8a21-5e6d7c8b9a01",
        "name":        "cPanel Admin Cloud",
        "category":   "cPanel/WHM",
        "host_type":    "virtual",
        "max_accounts": 5,
        "term_months": 1,
        "featured":    true,
        "prices":       { "monthly": "61.51" }
      }
    ]
  }
}
License fieldTypeDescription
uuidstringIdentifier used when ordering
namestringLicense name
categorystringGroup the license belongs to
host_typestringvirtual or dedicated — the server type the license is valid for
max_accountsint|nullMaximum number of accounts; null = unlimited
prices.monthlystringPrice for your level, per month
Licenses are monthly only A license is leased for one month and renewed every month. Longer cycles do not exist — the cycle field at ordering accepts only monthly.

Order license #

POST /v1/order_license.php

Creates a license order and the corresponding proforma invoice. The license is bound to the server IP address you send in the request — without it the license cannot be activated.

POST JSON fields

FieldTypeRequiredDescription
package_uuidstringYESLicense uuid from the license offer
cyclestringYESAlways monthly — licenses are leased monthly only
ipstringYESPublic IPv4 or IPv6 address of the server the license is bound to
IP address restrictions The address must be public — private and reserved ranges (10.x, 192.168.x, 172.16–31.x, 127.x) are rejected with 400. A second license cannot go to the same IP address; the attempt returns 409.

Example request

POST https://api.resellerunion.com/v1/order_license.php
Content-Type: application/json; charset=utf-8
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

{
  "package_uuid": "3f2a1b6c-9d4e-4f70-8a21-5e6d7c8b9a01",
  "cycle": "monthly",
  "ip": "203.0.113.50"
}

Response

{
  "success": true,
  "data": {
    "proforma_invoice": { "number": "P-2026-00412", "total": "61.51", "currency": "€", "status": "unpaid" },
    "order":  { "uuid": "…", "order_number": "RSL-0000100042", "status": 1 },
    "license":   { "uuid": "…", "name": "cPanel Admin Cloud", "ip": "203.0.113.50", "status": 1 }
  }
}

The license stays in the Pending status until the proforma invoice is paid. After payment it is activated and receives a licenseid — track its state through my_licenses.php.


My licenses #

GET /v1/my_licenses.php

List of your licenses. Parameters: ?limit=50&offset=0 (optional) or ?uuid=<uuid> for a single license.

FieldTypeDescription
uuidstringLicense identifier
namestringLicense name at the time of purchase
categorystringGroup the license belongs to
statusintSee the status table below
greskastring|nullFailure reason — filled only for status 4
ipstringIP address the license is bound to
licenseidstring|nullLicense number at the vendor; null until activated
hostnamestring|nullServer hostname, if known
pricestringMonthly price at which it was sold
activated_atstring|nullDate and time of activation
expires_atstring|nullExpiry date of the current month
order_numberstring|nullNumber of the order with which the license was purchased
License statusMeaning
1Pending — order received, awaiting payment
3Active
4Failed — reason in the greska field
5Expired
7Cancelled
9Suspended

Renew hosting service #

POST /v1/renew_hosting.php

Creates a proforma invoice for the service's next period. The service is renewed with the cycle it already has — the cycle does not change on renewal.

POST JSON fields

FieldTypeRequiredDescription
uuidstringYESService uuid from My hosting services

The price is not sent — the system determines it according to your price level and the cycle the service has.

Example request

POST https://api.resellerunion.com/v1/renew_hosting.php
Content-Type: application/json; charset=utf-8
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

{
  "uuid": "7c1e9a2b-4d38-4f61-9b02-1a5c8e7d3f40"
}

Response

{
  "success": true,
  "data": {
    "proforma_invoice": { "proforma_number": "P-2026-00518", "total": "19.56", "currency": "€", "status": "unpaid" },
    "service": {
      "uuid": "7c1e9a2b-…", "package": "BUSINESS HOSTING", "domain": "example.com",
      "cycle_months": 1, "expires_at": "2026-08-20", "new_period_until": "2026-09-19"
    },
    "auto_activation": { "enabled": true, "message": "Automatic renewal: the available credit…" }
  }
}

When renewal is possible

Service stateRenewal
ActivePossible
Expired, within the renewal periodPossible
Expired, renewal period over409 — reactivation required
Suspended409 — reactivate the service first
Cancelled409
Pending (not yet activated)409
Existing unpaid proforma invoice If an unpaid renewal proforma invoice already exists for the service, a new one is not created. The response is 409 with the number of the existing proforma invoice — pay that one or wait for it to be processed.

Change hosting package #

POST /v1/upgrade_hosting.php

Moves the service to another package, keeping the same billing cycle. The unused part of the current period counts as credit, the new package is charged for the remaining days, and the difference is the amount due.

FieldTypeRequiredDescription
uuidstringYESService uuid
package_uuidstringYESNew package uuid from hosting_offer.php
CaseResult
Amount due above 0 (bigger package)A proforma invoice for the difference; the package changes after payment (with auto_activation and enough credit — automatically). changed: false, calculation holds the breakdown.
Amount due 0 (smaller or equal package)The package changes immediately, with no proforma invoice and no refund of the difference. changed: true.

A service with a dedicated IP keeps the IP; the new package must offer an IP for your level and cycle. If the server rejects the new package (e.g. more disk used than the new package allows), the service stays on the old package.


Manage hosting service #

POST /v1/manage_hosting.php

Suspends, unsuspends or terminates the hosting account on the server.

FieldTypeRequiredDescription
uuidstringYESService uuid
actionstringYESsuspend, unsuspend or terminate
confirmbooleanfor terminatetrue — termination removes the account and is irreversible

A suspended service is not renewed automatically — that is how a WHMCS suspension stops the renewal (see Renewals).


Renew license #

POST /v1/renew_license.php

Creates a proforma invoice for the license's next month. Licenses are leased and renewed monthly only.

POST JSON fields

FieldTypeRequiredDescription
uuidstringYESLicense uuid from My licenses

Example request

POST https://api.resellerunion.com/v1/renew_license.php
Content-Type: application/json; charset=utf-8
X-API-UUID:   550e8400-e29b-41d4-a716-446655440000
X-API-KEY:    your_api_key

{
  "uuid": "9a4f2c81-6b30-4e75-8d19-3f7b2e5a1c68"
}

The response has the same shape as for hosting, with a license block instead of service. The same rules apply to the states in which renewal is not possible, as well as to an existing unpaid proforma invoice.


Terminate license #

POST /v1/manage_license.php

Permanently cancels the license at cPanel. Licenses are not suspended — they are billed for as long as they exist, so a license your client no longer uses is terminated. An unpaid renewal proforma invoice for that license is cancelled.

FieldTypeRequiredDescription
uuidstringYESLicense uuid from my_licenses.php
actionstringYESterminate
confirmbooleanYEStrue

Renewals, deadlines and expiry #

Your account has two separate settings (reseller panel, Settings; API: settings.php):

SettingApplies toWhen enabled
auto_activationNew orders and package changesThe proforma invoice is charged from credit immediately and the service is activated
auto_renewalRenewal of existing servicesThe renewal proforma invoice is charged from credit and the service is renewed; only the invoice is emailed to you

If there is not enough credit, the proforma invoice stays unpaid and waits for a payment or a credit top-up — nothing is ever charged partially.

Automatic renewal OFF

For domains, hosting, licenses and dedicated servers the renewal proforma invoice is issued in advance, before expiry (the number of days depends on the billing cycle) and emailed to you. The service is renewed as soon as it is paid. You can also start a renewal yourself at any time with the renew endpoints.

Automatic renewal ON

ServiceWhen it is renewed
DomainOnly on your renew_domain.php call (WHMCS sends it on its own). The proforma invoice is charged from credit and the domain is renewed at the registry.
Hostinghosting_grace days after expiry, unless the service has been suspended or terminated
Dedicated serverhosting_grace days after expiry, unless the server has been suspended or terminated
Licenselicence_grace days after expiry, unless the license has been terminated
Why hosting, servers and licenses renew after expiry WHMCS provisioning modules do not send a renewal command for hosting and licenses, but they do send suspension and termination. The hosting_grace / licence_grace window (see my_profile.php) is your room: if your client does not pay and you suspend or terminate the service, no renewal happens and no credit is taken. If you do nothing, the service is renewed.

You can always renew manually with renew_hosting.php, renew_dedicated.php or renew_license.php, or from the WHMCS module.

New period after renewal

Domain: old expiry date + number of years. Hosting, licenses and servers: old expiry date + billing cycle, without a gap — paying a few days after expiry does not shift the date. If the service stayed expired for longer than a whole cycle, the new period starts on the payment date.

What happens to a service that is not renewed

ServiceAfter expiry
HostingMore than hosting_grace days: suspension. Day 60: termination (the account is removed from the server) and the unpaid proforma invoice is cancelled. Paying before termination lifts the suspension and renews the service.
Dedicated serverMore than hosting_grace days: suspension (network disabled). Day 60: termination.
LicenseDay 1: status expired. More than licence_grace days: termination at cPanel — licenses are not suspended, because they are billed for as long as they exist.
DomainGrace period, then redemption period (days per extension — see the price list); a renewal in that time also includes the grace or redemption fee as a separate proforma item. On day 60 the domain becomes deleted and can no longer be renewed.

My domains #

GET /v1/my_domains.php

List of your domains. Parameters: ?limit=50&offset=0 (optional). For each domain it returns: uuid, name, status, price, dates and the order number — the uuid from here is what you use for renewal, EPP, nameservers and contacts.

Domain statusMeaning
1Pending
3Active
4Failed
5Expired

Dedicated server offer #

GET /v1/dedicated_offer.php

The complete dedicated server offer with prices for your price level, together with the available configurable options.

Servers are leased monthly only No longer cycle is offered. The prices block contains only monthly.

Response

The response has two parts: packages (servers) and options (additional options chosen when ordering).

{
  "success": true,
  "data": {
    "level": 2,
    "currency": { "code": "EUR", "suffix": "€", "position": "after" },
    "decimal_separator": ".",
    "total_count": 11,
    "packages": [
      {
        "uuid": "3f1c8a20-68df-4cf7-9bd5-dc73b38acc8d",
        "name": "2 x 18 Core Xeon Gold 6254",
        "subtitle": "DELL PowerEdge R640",
        "featured": false,
        "sold_out": false,
        "specification": {
          "model": "DELL PowerEdge R640",
          "cpu": "Xeon Gold 6254",
          "cpu_count": 2,
          "cores": 36,
          "cpu_speed": "32 x 3.10 GHz",
          "hyperthreading": true,
          "ram_included": "64 GB",
          "ram_type": "DDR 4",
          "disks_included": [
            { "name": "960 GB SSD Enterprise", "count": 2 }
          ],
          "drive_bays": 8,
          "included_ip_addresses": 1
        },
        "available_options": {
          "ram":  ["ram-1", "ram-2", "ram-3"],
          "raid": ["raid-1", "raid-2"],
          "disk_slots": [
            ["disk-6", "disk-7"],
            ["disk-6", "disk-7"]
          ]
        },
        "prices": { "monthly": "799.20" }
      }
    ],
    "options": {
      "ram": [
        {
          "code": "ram-2",
          "name": "Upgrade to 128 GB",
          "free": false,
          "prices": { "monthly": "96.00" }
        }
      ],
      "disks": [ ... ],
      "internet": [ ... ],
      "management": [ ... ],
      "cpanel": [ ... ],
      "raid": [ ... ],
      "ip": [ ... ],
      "operating_systems": [ ... ]
    }
  }
}
How to link a package and its options The options block lists all options on the platform. available_options inside a package says which of them that package offers — matching is done by the code field.

disk_slots is an array of arrays: one entry per physical slot, because the disk is chosen separately for each slot.
What is already included in the price ram_included and disks_included describe the configuration that comes with the server. The options from options are upgrades and are charged additionally.
FieldTypeDescription
uuidstringPackage identifier — used when ordering
namestringServer name
subtitlestringShort description, usually the chassis model
featuredboolHighlighted in the offer
sold_outboolCurrently unavailable
specificationobjectHardware description; see the example above
available_optionsobjectCodes of the options this package offers
prices.monthlystringYour monthly price for your level

Dedicated server order #

POST /v1/order_dedicated.php

Orders a dedicated server with the chosen configuration. Creates an order and a proforma invoice; the server stays in status 1 until delivery.

Delivery is manual A dedicated server is a physical machine and is not activated automatically. After payment the server waits for the technical team to put it into operation; the IP address and root access appear only then.
Auto-activation from credit When automatic activation is enabled on the account, the proforma invoice is charged from your credit immediately: an invoice is issued, the old advance invoice is reversed and a new one is issued for the remaining amount — all automatically, with the documents sent by e-mail. Even then the server waits for manual delivery (the status stays 1). Without enough credit the proforma invoice stays unpaid and waits for a payment.

Request

{
  "package_uuid": "dddddddd-0000-4000-8000-000000000002",
  "cycle": "monthly",
  "hostname": "srv1.example.com",
  "options": ["ram-2", "raid-2", "cp-1", "os-1"],
  "disks": ["disk-7", "disk-6"],
  "extra_ip": 4
}
FieldRequiredDescription
package_uuidyesuuid from dedicated_offer.php
cycleyesAlways monthly — servers are leased monthly
hostnamenoDesired hostname; can also be set later
optionsnoUpgrade codes: memory, RAID, link, management, control panel, OS
disksnoDisk codes per slot, in order
extra_ipnoNumber of additional IP addresses (0 if none are ordered)
An option the package does not offer is an error A code that is not listed in that package's available_options returns 400 — it is not skipped silently. The same applies to a disk in a slot that does not support it and to two options of the same kind.
Disks go per slot disks is an array where the first element belongs to the first slot, the second to the second and so on. An empty slot is sent as an empty string:

"disks": ["disk-7", "", "disk-6"]

The number of elements must not exceed the number of slots from specification.drive_bays.

Response

{
  "success": true,
  "data": {
    "order": {
      "uuid": "7c2f9a10-4e88-4a31-b0d2-1f5e77c3a904",
      "order_number": "RSL-4839947402",
      "status": 1
    },
    "server": {
      "uuid": "b41d7e60-9c2a-4f18-8ad5-3e90b21c7f56",
      "name": "2 x 18 Core Xeon Gold 6254",
      "model": "DELL PowerEdge R640",
      "hostname": "srv1.example.com",
      "cycle": "monthly",
      "cycle_months": 1,
      "level": 2,
      "price": "1044.06",
      "package_price": "849.15",
      "options_price": "194.91",
      "selected_options": ["Upgrade to 128 GB", "RAID 10"],
      "ordered_ip_addresses": 4,
      "status": 1
    },
    "proforma_invoice": {
      "number": "1587",
      "subtotal": "892.36",
      "vat_amount": "151.70",
      "total": "1044.06",
      "currency": "€",
      "status": "unpaid"
    },
    "currency": { "prefix": "", "suffix": "€", "position": "after" },
    "decimal_separator": "."
  }
}
Common mistake data.uuid does not exist. The order UUID is data.order.uuid and the server UUID is data.server.uuid — for tracking through my_dedicated.php the latter is used.
CodeError
400Invalid option code or an option the package does not offer
400Disk in a slot that does not support it, or more disks than slots
400Two options of the same kind (e.g. two memory upgrades)
400More IP addresses than allowed
404Server not in the offer

My dedicated servers #

GET /v1/my_dedicated.php

List of your servers. Parameters: ?limit=50&offset=0 (optional) or ?uuid=<uuid> for a single server.

Delivery is manual A dedicated server is a physical machine and is not activated automatically. After payment the server stays in status 1 until the technical team puts it into operation. Root access and IP addresses appear only then.
FieldTypeDescription
uuidstringServer identifier
namestringPackage name at the time of purchase
modelstringMachine model (e.g. DELL PowerEdge R640)
hostnamestringHostname, if set
statusintSee the status table below
levelintYour price level at the time of purchase
cyclestringAlways monthly
pricestringTotal monthly price, with the selected options
package_pricestringServer only, without options
options_pricestringSum of the selected options
main_ipstringMain IP address; empty until the server is delivered
main_ipv6stringMain IPv6 address, if assigned
ordered_ip_addressesintNumber of additional IP addresses ordered
leased_ip_addressesintNumber of additional IP addresses actually assigned
root_usernamestringRoot username
specificationobjectHardware description
configurationobjectSelected options with the price at which they were charged
leased_atstring|nullLease date
expires_atstring|nullExpiry date of the current month
terminated_atstring|nullTermination date, if the service was terminated
Prices in configuration are frozen They show the amount that applied at the time of the order, not the current price list. The price list may change, but you are charged what was agreed.
Server statusMeaning
1Awaiting delivery — payment received, the server is being prepared
2Active
3Suspended
4Terminated
5Cancelled
6Fraud

Renew dedicated server #

POST /v1/renew_dedicated.php

Creates a proforma invoice for the next month of the server, at the server's contracted price (package + options chosen at order time).

FieldTypeRequiredDescription
uuidstringYESServer uuid from My servers

Renewal is possible for an active server and for a server expired within hosting_grace. A suspended, terminated or cancelled server returns 409, as does an existing unpaid renewal proforma invoice. The response has the same shape as renew_hosting.php (with hostname instead of package and domain).


Manage dedicated server #

POST /v1/manage_dedicated.php

Reboot, network, suspension and termination of the server. Executed through DCIM; the status changes only after DCIM confirms the action.

FieldTypeRequiredDescription
uuidstringYESServer uuid
actionstringYESreboot, network_on, network_off, suspend, unsuspend, terminate
confirmbooleanfor terminatetrue — termination is irreversible

On a suspended server only unsuspend and terminate are allowed. The response returns service.status and the network state (network: on / off).


My documents #

GET /v1/my_documents.php

The latest proforma invoices and invoices. Parameter: ?limit=10 (1–50, default 10). Each document contains uuid, number, dates, amount, currency and status. Proforma invoice status: 0 = unpaid, 1 = paid.


My profile #

GET /v1/my_profile.php

Returns your profile data in the registrant format — ready for the "register with my details" option when ordering a domain.


Credit #

GET /v1/credit.php

The current balance of your credit: { credit: { amount, currency, broj_avansnog_racuna, datum } }. Without an active advance payment the amount is 0.00.


Settings #

GET POST /v1/settings.php

GET returns { settings: { auto_activation: 0|1, auto_renewal: 0|1 } }. POST { "auto_activation": 0|1, "auto_renewal": 0|1 } (one or both fields) changes the settings and returns the new state. Auto-activation means that services are activated automatically after payment; auto-renewal is described under Automatic renewal and activation.


Registrant details #

The registrant object sent at domain registration and transfer:

FieldRequiredDescription
is_companyYES0 = individual, 1 = company (legal entity)
first_name, last_nameYESFirst and last name of the registrant / contact person
companyNO*Company name — for companies
company_idNO*Company registration number — for companies
vat_idNOVAT number — for VAT-registered companies
address, city, postal_codeYESRegistrant's address
countryYESISO-2 country code (e.g. US, GB, DE)
email, phoneYESRegistrant's contact details (phone in international format)
Fields for companies For is_company: 1 you must also send company and company_id. Incomplete data returns a business error describing the missing field.

Billing cycles #

The cycle field in a hosting order accepts one of the following values (string):

ValuePeriodNumber of months
monthlyMonthly1
quarterlyQuarterly3
semiannuallySemi-annually6
annuallyAnnually12
bienniallyEvery two years24
trienniallyEvery three years36
quadrenniallyEvery four years48
quinquenniallyEvery five years60
Availability per package Which cycles a specific package offers is shown in that package's prices object in the hosting offer. A cycle that is not in the package's offer cannot be ordered.
Domains Domains do not use cycles — the period is sent as a number of years in the period field: registration 1–5 years (availability per extension from registration_periods in the price list), transfer currently 1 year.
Licenses Licenses are leased and renewed monthly only. The cycle field in a license order accepts only the value monthly — longer cycles do not exist and return 400.