If you already have code that talks to Xtream Codes, XUI.one, OTT Panel, or OneStream, that code keeps working against an Xtream AI panel. The wire contract is preserved on purpose. You do not throw away your scripts. You do not rewrite your billing system. You do not re-teach your team a new set of calls.

The intent of this page is to lay out exactly what that guarantee means, what does change, and where to go next depending on which classic panel you are coming from. If you read only one page before migrating your first environment, this is the one.

Only two things change. The first is the base URL, because your requests now hit an Xtream AI domain instead of the old panel. The second is the API key, because keys are issued by the new panel and the old secret does not carry over.

Every other detail stays the same: the action names, the parameter names, the response shape, the header names, and the field values inside the JSON your code parses today. If your billing bot posts create_line today and reads data.username back from the response, it will keep posting create_line and reading data.username back tomorrow.

What compatibility means here

Compatibility here is not an emulation layer that translates between two products. It is not a rewrite of your integration that lives inside our panel. What we did is much simpler and much more reliable.

The Xtream AI panel speaks the same wire contract natively. When your code sends action=create_line with the classic parameters, our backend accepts that request, runs the actual creation against the native model, and answers with the exact response shape your code was already parsing. There is no proxy in the middle, no queue, no separate compatibility service that could fall behind the real thing.

This is possible because the request layer of the panel is designed to accept three flavors of input against the same underlying operations: the native Xtream AI JSON style, the Xtream Codes query style, and the OneStream REST style.

All three share one authentication system, one set of API keys, and one line of business logic.

The compatibility flavors are first-class inside the panel, not a translation shim bolted on top. That distinction matters because a translation shim tends to drift from the real behavior over time. A native reimplementation has no separate code path to drift from. Fixes to the underlying line model, package model, or reseller model apply to every flavor at once.

The practical consequence for you is that you do not need to change anything conceptual about how your integration works. The same POST hits the same kind of URL, with the same fields and the same headers. Only the hostname before the path and the value of the key are new. If your team currently maintains a WHMCS module, a Blesta plugin, a custom PHP script, a Python worker, or any other client that speaks the classic protocols, that code drops in against Xtream AI after the two-value swap and keeps behaving exactly the way it does against your current panel.

If you use Xtream Codes, XUI.one, or OTT Panel

Change the base URL. Swap the key. Your calls run.

# Before
https://old-panel.example.com/panel_api/admin/index.php

# After
https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php

If your integration uses the reseller side of the panel, keep your existing /reseller/index.php path. Only the hostname and the /panel-api/xc/ prefix before it are new. The action string, the query parameters, the POST body, and the response your parser reads back all keep their exact classic shape.

Both /admin/index.php and /reseller/index.php accept the same API key type. The panel infers admin-versus-reseller from the key itself, so point your integration at whichever path your existing code already uses. There is no need to consolidate paths as part of the migration.

What stays the same

  • The query style you already use. Requests are still ?api_key=<your-api-key>&action=<name> with the parameters your code already sends.
  • The action names your code calls. create_line, edit_line, extend_line, enable_line, disable_line, delete_line, create_user, edit_user, and adjust_credits all work with the same request shapes, alongside the read actions like user_info, get_lines, get_line, get_bouquets, and packages.
  • The response shape. Every response is HTTP 200 with a JSON body of {"status": "STATUS_SUCCESS", "data": {...}} on success, or {"status": "STATUS_FAILURE", "data": {"error": "...", "message": "..."}} on failure. Your existing code that branches on the status field keeps behaving the way it did.
  • The field names inside those payloads. Where the underlying native call uses a slightly different name, our compatibility layer translates transparently in both directions. You keep sending package and bouquets_selected[]. You keep reading exp_date and max_connections. Nothing in your existing parser has to move.
  • The HTTP status. The classic contract is HTTP 200 for every response, with the real outcome carried by the status field. We keep that contract, so integrations that do not check the HTTP code (almost all of them) keep working, and integrations that do check it never see anything other than 200 for a well-formed call.

What is not supported

Two areas of the classic API surface do not exist on this panel and never will. Both were common in the classic products, and both are absent from Xtream AI by design rather than by omission.

The first is action=mysql_query. The classic panels let clients run arbitrary SQL over HTTP against the panel database. This has caused most of the well-known incidents on those products, and we refuse to reproduce it.

Any call to mysql_query is rejected with STATUS_FAILURE and error: "forbidden_action". If your integration depends on mysql_query for a report or a bulk fix-up that has no first-class equivalent, contact us and we will look at exposing a real endpoint for that gap. That is how most of the reporting endpoints in the current native API got prioritized in the first place.

The second is device management for MAG and Enigma set-top boxes. Actions like create_mag, enable_mag, ban_enigma, convert_mag, and their siblings return STATUS_FAILURE with error: "not_implemented". The Xtream AI product concept for a subscriber is a Line. MAG or Enigma boxes are just clients that connect to a Line, so there is nothing to provision device-side from the API. If your existing integration keeps a MAG-per-user map on your side, keep it. The Line the user connects with is the resource we manage on our side.

The path segment right after /panel-api/xc/ (in the example above, panel_api) is decorative. In the classic panels that value was treated as a shared secret access code stapled onto the URL. Here, security is enforced only by the API key you send in the request. Whatever your existing code hardcodes as that segment keeps working without changes, including odd values that classic setups sometimes carry for historical reasons.

Full field-by-field reference, every action, every parameter, every response field, and the small list of known gotchas: Xtream Codes compatibility.

If you use OneStream

Change the base URL. Keep your header.

# Before
https://onestream.example.com/ext/*

# After
https://<your-panel-domain>/panel-api/onestream/ext/*

Your existing header (X-Api-Key: <your-api-key>) is accepted exactly the way OneStream accepts it. If your client has since standardized on Authorization: Bearer <your-api-key>, that form is accepted too. Older OneStream releases used X-Auth-User as the key carrier, and that legacy variant is still honored, so integrations that never migrated their header code keep authenticating without any client-side change.

The important corollary of that flexibility: you never have to update your header handling as part of the migration. Whichever variant your current code uses is the one that keeps working on the new panel.

What stays the same

  • The endpoint paths. /ext/profile, /ext/packages, /ext/bouquets, /ext/lines, /ext/line/find, /ext/line/create, /ext/line/create-advanced, /ext/line/{uuid}/renew, /ext/line/{uuid}/enable, /ext/line/{uuid}/disable, /ext/line/{uuid}/terminate, /ext/line/{uuid}/update-advanced, and the sub-reseller endpoints under /ext/user/* all respond exactly as OneStream does.
  • The JSON request bodies. Same field names, same value types. Booleans arrive as booleans and integers arrive as integers, matching the shapes your OneStream SDK already produces.
  • The JSON responses. Plain arrays where OneStream returns arrays, plain objects where OneStream returns objects, without a wrapper added by us.
  • The opaque line_id UUIDs. The identifier you got from /ext/line/create on the old panel keeps its role: it goes into the URL of every follow-up call for that line, and its value stays stable across the lifetime of the line.
  • The rid body field on writes. Passing it makes a retry safe against duplicate creates or double charges. The behavior your OneStream SDK already relies on is intact.
  • The GET /ext/transaction/{rid} lookup. If you ever need to reconcile a transaction after a network failure, the same call your OneStream code makes today keeps returning the original response.

What is different

Two things are worth calling out before you switch. Neither is a blocker. Both are known upfront.

MAG and Enigma actions are not implemented for the same reason described in the Xtream Codes section: this product does not manage those physical devices. The paths route successfully at the network layer, but every action returns error: "not_implemented". Point those integrations at the Line endpoints instead.

Some fields that OneStream accepts on POST /ext/line/{uuid}/update-advanced (namely username, bouquets, reseller_notes, and is_trial) are rejected explicitly rather than accepted and silently dropped. If your update-advanced calls carry those fields today, remove them before you switch. Your writes will then fail cleanly on the fields we cannot honor, instead of appearing to succeed while ignoring your intent. This is a deliberate honesty guarantee: we would rather reject an unknown field loudly than let your integration believe a change happened when it did not.

Full endpoint reference, request and response examples, and the complete list of known differences: OneStream compatibility.

Where the API key comes from

You do not reuse the API key from your old panel. The new panel issues its own keys, tied to your account, with their own scopes and their own rate limits. This is a hard boundary. Any attempt to use an old-panel secret against Xtream AI will fail authentication.

Create a key from Settings, Panel API Keys, Create key inside the Xtream AI panel. The secret is displayed once at creation time. Copy it into your integration's secret store before you close the dialog, because we do not store the plaintext and we cannot show it to you again.

The same key works across all three flavors of the API, so you do not need one key per compatibility path. A single Xtream Codes integration and a single OneStream integration can share the same secret if they belong to the same team. Scopes on the key control what each caller is allowed to do, so you can still issue narrower keys to sub-integrations that only need read access or only need reseller-side calls. Full details on scopes, IP allow-lists, and key rotation live in Authentication.

Common questions from migrators

Six questions come up in almost every migration call we sit in on. The answers below are the ones we give. If your question is not here, the two detailed compatibility references (linked at the bottom of this page) go into every field and every edge case, and our support team is happy to walk you through anything the docs do not cover.

Does my billing system need to change?

No. Only the base URL and the API key are new. If your billing code parses responses correctly (branching on the status field for Xtream Codes calls, or on HTTP status for OneStream calls), no other change is required. Teams that migrate a WHMCS module or a Blesta plugin usually finish the client-side edit in one commit.

Do my old scripts still authenticate the same way?

Yes. Xtream Codes clients keep sending ?api_key=<your-api-key> in the query string. They can also switch to Authorization: Bearer <your-api-key> if you want to keep secrets out of URLs and referrer logs. OneStream clients keep sending X-Api-Key, and can also use Authorization: Bearer or the legacy X-Auth-User header if that fits your existing code better.

Can I run the old and the new panel in parallel while I migrate?

Yes. Nothing about the two setups conflicts. The typical approach is to configure two base URLs in your integration (feature-flagged or per-tenant), point new traffic at the Xtream AI URL, and drain the old panel as you cut over. Once every write is going to the new panel, you can decommission the old one at your own pace. There is no forced deadline on our side.

Do I need to change how I retry after a network timeout?

Only if you want the safety net. Xtream Codes writes accept an optional rid=<unique-per-operation> value that guarantees a retry with the same rid never runs the operation twice. OneStream writes accept the same rid field inside the JSON body. If your current integration does not send it, retries still work the way they did on the old panel. Adding rid to create_line and adjust_credits is the change we recommend most often for migrating teams, because those are the two calls where a duplicate would cost real money.

What about IP allow-lists on the new key?

You can attach an IP allow-list to any Xtream AI API key at creation time or later, so only your billing hosts can use it. Requests from other addresses are refused at the authentication layer. This is a defense-in-depth control on top of the secret itself. If you already run your integration from a small pool of fixed hosts, we recommend switching this on before you flip production traffic. Details are in Authentication.

Do I have to change my TLS setup?

No. All Xtream AI panels serve the Panel API over HTTPS on the standard 443 port with a valid certificate. Your existing HTTP client library (curl, requests, Guzzle, HttpClient, and their equivalents) connects the same way it did to the old panel. There is no self-signed certificate to trust and no custom port to open in your outbound firewall.

Where to go next

Pick the reference that matches your setup and read it end to end before you flip your production traffic. Both pages document every field, every response, and every known difference.

If you run integrations in both flavors, both pages apply. Read the one your primary billing lives on first, then skim the other for the differences that touch your secondary integration.

Common migration recipes (create a line, renew a subscription, adjust reseller credits) written as end-to-end flows live in Common Tasks. Those recipes are useful whether you are cutting over a classic integration or writing a new one from scratch.

Starting a brand new integration instead of migrating one? The official SDKs get you calling the API in about five minutes and hide most of the wire-level details described on this page. See Quickstart.