System documentation
Rule One
The IMEI unlocking and device-services platform by CodRule. What it is, how a request travels through it, every layer that protects it, how an order becomes a delivered result, and how another panel integrates over the API.
Written from the running system, not from a specification.
1 · What Rule One is#
Rule One is a complete storefront and back office for selling device services — IMEI unlocking, iCloud and FMI removal, carrier checks, server tools, file services and digital goods.
An operator runs a shop. Customers order services. Rule One prices the order, takes the money, sends the work to the right supplier, tracks it to completion and delivers the result — or refunds it. Other panels can buy from that same catalogue over a standard API, which makes every Rule One installation a supplier as well as a shop.
| Surface | What it does |
|---|---|
| Storefront | Public catalogue, ordering, wallet, tickets, order history |
| Admin console | Catalogue, customers, orders, pricing, providers, payments, security |
| Mobile client | The storefront as a native application |
| Reseller API | A standards-compatible endpoint other panels order through |
All four talk to one backend. There is no second source of truth: price, permission, balance and order state are decided in exactly one place.
2 · Architecture#
The four applications
┌──────────────────────────────┐
Customers ────────▶│ Storefront │──┐
└──────────────────────────────┘ │
┌──────────────────────────────┐ │
Operators ────────▶│ Admin console │──┤
└──────────────────────────────┘ │
┌──────────────────────────────┐ │ HTTPS / JSON
Mobile ────────▶│ Mobile application │──┤
└──────────────────────────────┘ │
┌──────────────────────────────┐ │
Other panels ──────▶│ Reseller API │──┘
└──────────────────────────────┘
│
┌──────────▼───────────┐
│ Core │
│ orders · pricing │
│ licensing · realtime│
└──────────┬───────────┘
│
┌──────────▼───────────┐
│ Suppliers │
│ and stock sources │
└──────────────────────┘The rule that holds it together
No client decides anything that matters.
The storefront never computes a price. The mobile app never decides whether a customer may order. The admin console never grants itself a permission. Every one of those answers comes from the core, on every request, and the client only renders what it is told.
This is why a tampered client cannot buy at the wrong price, spend past its limit, or reach an endpoint its account is not entitled to.
Real-time
Order status, ticket replies and live-chat messages are pushed to the browser as they happen, rather than polled for. Every broadcast is wrapped so a failure in the realtime layer can never roll back the write it was reporting — the order is saved whether or not anything is listening.
3 · Security#
Security in Rule One is not a feature; it is a sequence. A request meets the layers below in this exact order, and each one can end the request on its own.
- 1NetworkIP rules, country rules, automatic bans
- 2Rateper-route throttling
- 3Identitywho is calling
- 4Deviceis this device still allowed
- 5Sessionis this token still alive
- 6Authorisationmay this account do this
- 7Step-upprove it again for this action
- 8Licenceis this feature licensed
- 9Auditwhat happened, recorded
Layer 1 — Network
Two independent scopes are evaluated: site (the storefront) and admin2 (the console). A rule written for one does not affect the other.
| Rule type | Meaning |
|---|---|
safe_list | Never blocked, by anything. Evaluated first so no automated writer can lock the owner out. |
whitelist | Explicitly permitted |
blacklist | Permanently refused, set by an operator |
auto_ban | Temporary, written by the system |
country_block | Refused by country, resolved through IP ranges |
Automatic banning
A refused request answers 403 with a deliberately vague body — the reason is written to the audit log and visible to the operator, never to the caller.
Layer 2 — Rate limiting
Applied per route, tuned to the cost of the action rather than uniformly:
| Action | Limit |
|---|---|
| Sign-in | 5 attempts / 15 minutes |
| Password reset | 5 / hour |
| Order placement | 10 / minute |
| Read endpoints | 20–30 / minute |
Layer 3 — Identity
Three separate token audiences, each with its own middleware and its own failure mode. A customer token is not an admin token with fewer rights; they are different credentials on different guards.
| Audience | Credential | Lifetime |
|---|---|---|
| Customer (web / mobile) | Bearer token, device-bound | Until revoked or the device is unbound |
| Operator (console) | Bearer token | 12 hours absolute, enforced on every request |
| Reseller (API) | Account e-mail + API key | Until rotated |
The operator token carries an absolute expiry that is checked on each call, not only at issue. An expired token is deleted the moment it is presented.
Two-factor is enforced on the API path too
Layer 4 — Device binding
Every customer session is tied to a device record. The device carries an active flag, a revocation timestamp and an optional expiry, and all three are checked on every authenticated request — not just at login.
Unbinding a device kills its sessions immediately.
A stolen token stops working the moment the customer revokes the device it belongs to, and the block survives a reinstall. A login from an unrecognised device can be held for one-time-code verification before any session is issued.
Layer 5 — Session
- Idle timeout on tokens, independent of absolute expiry.
- Operators may pin their own account to an address list; a non-empty list means requests from anywhere else are refused with a distinct code, while the session itself stays valid. An empty list means no restriction, so the feature stays inert until it is deliberately configured.
- Safe-listed addresses override the list, so a mistaken entry cannot lock an operator out permanently.
Layer 6 — Authorisation
Role and permission based, enforced on the controller, not on the route. Route-level guards are easy to bypass by adding a new route; controller-level guards travel with the action.
The console exposes 362 endpoints. Every write among them is guarded.
Layer 7 — Step-up
Some actions are not covered by “you are signed in”. Rotating an API key, changing security settings, or acting on another account requires re-proving identity — password, or a second factor — within a short window that is then consumed.
Layer 8 — Licensing
Feature availability is signed by the licence server and verified on every read, not cached and trusted. An installation without a key runs its core functions and simply does not offer the add-on features. A tampered licence document fails signature verification and is discarded.
Layer 9 — Audit
Security decisions are recorded to an append-only event log with the actor, the address, the route, the outcome and the reason. The catalogue in use includes:
login.success login.failed session.revoked
device.trusted device.blocked_login ip.auto_banned
admin.ip_blocked stepup.required stepup.passed
apikey.generated password.reset_requested profile.ip_policy_changedThis log is what makes an incident answerable rather than debatable. It is also what the automatic banning reads from.
What is never logged
4 · Ordering and delivery#
The chain from a customer pressing Order to a result appearing in their account.
The pipeline
1 Normalise input strip decoration, split bulk, resolve the main field
2 Resolve quantity for a bulk order the count is the number of lines
3 Price, server-side the client's number is ignored entirely
4 Idempotency has this exact request already been accepted
5 Validate field rules, identifier format, duplicate window
6 Charge balance, gateway, or free
7 Persist one order per identifier, inside a transaction
8 Dispatch after commit, never inside it
9 Track poll or webhook until final
10 Settle deliver the result, or refundInput normalisation
Customers paste identifiers out of spreadsheets and chat messages. Values arrive decorated:
✅355796467388512
3527266… done ✅
3576 4412 8214 560Every value is cleaned before it is counted, validated, stored or forwarded. How aggressively depends on what the service actually asks for: a true IMEI is digits only, but a service whose field is a serial legitimately contains letters — stripping them there would destroy a valid value.
The two kinds of identifier field
This distinction runs through the whole platform, and getting it wrong is the difference between a service that works and a service nobody can order.
| IMEI | Serial / custom | |
|---|---|---|
| Content | 15 digits | Letters and digits |
| Length | Fixed | Whatever the supplier declares |
| Check digit | Luhn, computed from the first 14 | None |
| Customer enters | 14 digits; the 15th is calculated | The value as it is |
| Bulk | One per line | One per line |
| Sent to supplier as | The standard IMEI parameter | A custom field |
Names lie
Bulk
When a service accepts several identifiers, the customer pastes a list and Rule One creates one order per line — each with its own price, its own supplier reference and its own outcome. One bad line fails alone; the rest deliver.
Any additional text field the customer filled in as a matching list is paired line for line, so entry three keeps its own note or username. A field that is not a list of the same length is a single answer for the whole request.
Pricing
The price is decided by the server, in this order, and the first rule that applies wins:
- An explicit per-service price for the customer's group
- A historical tier the group is bridged to
- The group's markup rule applied to the service cost
- The service's own listed price
The result is converted to the customer’s currency at the configured rate, and the order stores the base amount, the base currency and the rate used — so an old order can always be read in the money it was actually placed in, whatever the rate does later. Zero-decimal currencies display as whole units.
Money
- The wallet is held in the customer's own currency.
- A charge is refused unless the account can afford it — including an operator-granted overdraft floor, when one exists. One method answers “may this account spend this” and every enforcement point calls it; there is no second opinion.
- Seventeen payment gateways are supported, plus manual transfer and direct-to-wallet cryptocurrency.
- Webhooks are verified by signature and protected against replay at the database level, not in application memory.
Idempotency
Every order request may carry an idempotency key. Rule One recognises three states:
| State | Answer |
|---|---|
| Never seen | Accept and process |
| In progress | 409 — this exact request is running |
| Completed | Return the original result; do not charge twice |
Keys are validated for format and length before use. A network retry, a double-tapped button and a reconnecting mobile client all resolve to one order.
Fulfilment
Two strategies, chosen per service:
- API fulfilment — the order is sent to the configured supplier and tracked. Rule One is a full client of the standard reseller protocol: catalogue synchronisation, order placement, bulk placement, status polling and account balance.
- Inventory fulfilment — the result is drawn from stock the operator loaded in advance and delivered instantly.
- Manual services are held for an operator, who delivers by hand.
Before an order leaves for a supplier, a dispatch guard confirms it is genuinely ready to send, and a supplier audit records exactly what was sent and what came back.
Delivery and settlement
An order reaches one of three ends:
| End | What happens |
|---|---|
| Completed | The result is written to the order, the customer is notified in the panel, by e-mail and by push, and the reply is formatted with the operator's own template for that service. |
| Failed | The amount is returned to the wallet and the order is marked refunded. Failure is never silent. |
| Rejected before dispatch | Nothing was sent and nothing was charged. |
Operators can define a success reply and a failure reply per service, so the customer reads the shop’s own wording while the supplier’s raw code is preserved for support.
5 · Supplier integration#
Rule One as a buyer: standards-compatible suppliers and custom HTTP APIs.
Catalogue synchronisationpulls the supplier’s full service list and mirrors it locally: name, cost, delivery time, group, service type, quantity range, which kind of identifier the service takes, whether it accepts several at once, and any additional fields it requires.
Placing an ordersends the service id and the parameters the supplier declared, with additional fields carried in the supplier’s custom-field envelope. Bulk orders use the protocol’s batch form.
Tracking polls order status on a schedule, and the scheduler stamps its own heartbeat so a stalled synchroniser is visible rather than silently frozen.
6 · Reseller API#
Every Rule One installation exposes a standards-compatible endpoint. Any panel that can already order from a supplier can buy from you without writing new code — and each reseller sees only the part of your catalogue you decided to sell them.
PHP example — downloadA client in one file with no dependencies, and a runnable script that checks your balance, imports the catalogue, places an order and reads it back. Ordering is commented out, so running it costs nothing.codrule-php-example.zip · CodRuleClient.php · example.php · config.php · READMEEndpoint and authentication
POST https://<your-domain>/api/index.php
Content-Type: multipart/form-data| Field | Value |
|---|---|
username | The reseller's account e-mail on your platform |
apiaccesskey | That account's API key |
action | The operation |
requestformat | JSON |
The account must be active. If the reseller has configured an address list, requests from other addresses are refused. Keys are compared in constant time.
API access is granted by you, not taken by the reseller.
Two things must both be true before a call is answered: the account carries an API key, and you have switched API access on for it in the customer drawer. A key alone is not enough, and a customer cannot generate one for themselves — the button in their own settings refuses until you enable the account.
One message for every authentication failure
Authentication failed: Invalid username or API key. That is deliberate: a distinct “no such user” would let anyone test which addresses bank with you. Repeated failures from one address are rate-limited, and the real reason is recorded on your side, not returned.Actions
| Action | Purpose |
|---|---|
accountinfo | Balance and account state |
| imeiservicelist | The IMEI services this reseller may buy |
| serverservicelist | The server services this reseller may buy — game top-ups, accounts, licences |
| placeimeiorder / placeserverorder | Place an order |
| getimeiorder / getserverorder | Order status |
Catalogue
The two list actions are not interchangeable. serverservicelist returns server services and imeiservicelist returns IMEI ones; ask for the section you sell. A reseller who only sells game top-ups calls serverservicelist and never sees a device service at all.
Scoped to that reseller
An empty LIST is not a fault. It means the account is restricted and nothing in the section you asked for has been granted to it yet.
{
"SUCCESS": [{
"MESSAGE": "SERVER Service List",
"LIST": {
"PUBG Mobile UC": {
"GROUPNAME": "PUBG Mobile UC",
"GROUPTYPE": "SERVER",
"SERVICES": {
"4412": {
"SERVICEID": 4412,
"SERVICETYPE": "SERVER",
"SERVICENAME": "PUBG Mobile — 660 UC",
"CREDIT": 8.75,
"INFO": "Player ID only, no login needed",
"TIME": "Instant",
"QNT": 1,
"QNTOPTIONS": "",
"MINQNT": "1",
"MAXQNT": "20",
"Requires.Custom": [
{
"type": "servicecustom",
"fieldname": "Player ID",
"fieldtype": "text",
"description": "The numeric ID shown in the game profile",
"fieldoptions": "",
"required": 1
}
]
}
}
}
},
"ACCOUNTINFO": {
"credit": "$22.408 ",
"creditraw": "22.408",
"mail": "[email protected]",
"currency": "USD"
}
}],
"apiversion": "6.1"
}The IMEI section has the same shape, with "MESSAGE": "IMEI Service List", GROUPTYPE and SERVICETYPE of IMEI, and a serviceimei field in Requires.Custom instead of a custom one:
{
"SUCCESS": [{
"MESSAGE": "IMEI Service List",
"LIST": {
"iPhone Carrier Unlock": {
"GROUPNAME": "iPhone Carrier Unlock",
"GROUPTYPE": "IMEI",
"SERVICES": {
"8970": {
"SERVICEID": 8970,
"SERVICETYPE": "IMEI",
"SERVICENAME": "AT&T USA iPhone Unlock",
"CREDIT": 12.50,
"INFO": "Clean and financed supported",
"TIME": "Instant",
"QNT": 1,
"MINQNT": "1",
"MAXQNT": "",
"Requires.Custom": [
{
"type": "serviceimei",
"fieldname": "IMEI",
"fieldtype": "text",
"description": "15 digit IMEI",
"fieldoptions": "",
"required": 1
}
]
}
}
}
}
}]
}CREDIT is that reseller's price
Requires.Custom — read that array, it is the contract.Placing an order
Use placeserverorder for a server service and placeimeiorder for a device one. Both are accepted for either kind, so an existing client that only knows the original verbs keeps working.
action = placeserverorder
ID = <service id>
parameters = <XML string — plain text, not encoded>
QNT = <only for services ordered by quantity><PARAMETERS>
<ID>8970</ID>
<IMEI>355796467388512</IMEI>
<CUSTOMFIELD>eyJFbWFpbCI6InVzZXJAZXhhbXBsZS5jb20ifQ==</CUSTOMFIELD>
</PARAMETERS>CUSTOMFIELD is base64 of a JSON object, keyed by the exact fieldname values from Requires.Custom:
{"Email": "[email protected]", "License": "CR-XXXX-XXXX-XXXX-XXXX"}Rule One accepts the parameters as XML, as JSON, or as plain form fields.
Integration notes
These are the mistakes integrators actually make:
| # | Note |
|---|---|
| 1 | parameters is plain XML. Only the content of CUSTOMFIELD is base64. Encoding the whole document is rejected. |
| 2 | CUSTOMFIELD is a JSON object, not an array and not a string. {"Email":"…"} — not [{"Email":"…"}]. |
| 3 | Field names must match exactly. Use the fieldname from Requires.Custom, not your own label. Matching is not fuzzy and not case-insensitive. |
| 4 | ID appears twice — as a form field and inside the parameters document. |
| 5 | Empty values are dropped. A parameter with an empty value is not sent at all. |
| 6 | Escape your values. An e-mail containing & breaks an unescaped XML document. |
| 7 | Use multipart/form-data. Not JSON, not URL-encoded. |
| 8 | Errors can be nested. A failure may arrive at the root as {"ERROR":[…]} or inside a success envelope as {"SUCCESS":[{"ERROR":[…]}]}. Check both, or you will treat a failure as a success. |
| 9 | Store REFERENCEID. Without it you cannot track the order. |
Response
{"SUCCESS": [{
"MESSAGE": "Order placed",
"REFERENCEID": "58905",
"STATUS": "processing"
}]}Tracking
action = getimeiorder
ID = <REFERENCEID>
parameters = <PARAMETERS><ID>REFERENCEID</ID></PARAMETERS>7 · Languages#
Nine languages ship with the platform, including four written right to left: Arabic, Persian, Urdu and Hebrew-script content where applicable.
This is more than a translation file. Right-to-left support includes correct fonts per script — Urdu is rendered in Nastaliq with its own line metrics — bidirectional isolation so a Latin service name inside Arabic text does not scramble the sentence, correct plural rules per language, and a search normaliser that treats the Arabic letter forms a customer actually types as equivalent.
Support conversations are translated in both directions: the customer writes in their language, the operator reads in theirs, and both are stored.
8 · White-label#
One installation is one shop, and every visible identity comes from configuration rather than from code: name, domain, logo, colours, e-mail identity and the licensed feature set.
Multiple independent shops run on one server without sharing customers, catalogues, prices, orders or credentials.
9 · Operations#
- Zero-downtime deployment. The storefront builds into a parallel directory and swaps, so visitors are served the previous build until the new one is ready.
- Scheduled work runs under a supervised daemon with its own heartbeat: order status polling, catalogue synchronisation, automatic banning, expired-token pruning.
- Every order carries an audit trail: what the customer submitted, what was sent to the supplier, what came back, and every state change with its timestamp.
- Maintenance mode closes the shop at the edge with a correct
503, while payment webhooks and the reseller API stay reachable so in-flight money is never lost.
10 · Summary#
| Principle | What it means |
|---|---|
| Server decides everything | Price, permission, balance and order state have exactly one source |
| Layered security | Nine independent gates, each able to end a request alone |
| No silent failure | An order completes, refunds, or is refused before it costs anything |
| Auditable | Security decisions and order transitions are recorded, not inferred |
| Standards-based API | Compatible in both directions — you can buy and be bought from |
| Built for scale | Bulk ordering, idempotent requests, zero-downtime releases |
Rule One — CodRule
Questions about integrating? Open a conversation from any page, or write to [email protected].