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.

SurfaceWhat it does
StorefrontPublic catalogue, ordering, wallet, tickets, order history
Admin consoleCatalogue, customers, orders, pricing, providers, payments, security
Mobile clientThe storefront as a native application
Reseller APIA 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

request flow
                       ┌──────────────────────────────┐
   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.

  1. 1NetworkIP rules, country rules, automatic bans
  2. 2Rateper-route throttling
  3. 3Identitywho is calling
  4. 4Deviceis this device still allowed
  5. 5Sessionis this token still alive
  6. 6Authorisationmay this account do this
  7. 7Step-upprove it again for this action
  8. 8Licenceis this feature licensed
  9. 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 typeMeaning
safe_listNever blocked, by anything. Evaluated first so no automated writer can lock the owner out.
whitelistExplicitly permitted
blacklistPermanently refused, set by an operator
auto_banTemporary, written by the system
country_blockRefused by country, resolved through IP ranges

Automatic banning

A scheduled task runs every five minutes and bans any address that produced 10 failed or blocked events in the last 15 minutes, for 60 minutes. The ban is written to the same rule table, so an operator can see it and remove it. Safe-listed addresses are exempt.

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:

ActionLimit
Sign-in5 attempts / 15 minutes
Password reset5 / hour
Order placement10 / minute
Read endpoints20–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.

AudienceCredentialLifetime
Customer (web / mobile)Bearer token, device-boundUntil revoked or the device is unbound
Operator (console)Bearer token12 hours absolute, enforced on every request
Reseller (API)Account e-mail + API keyUntil 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

An API login that skipped 2FA would be a bypass for the very accounts that enabled it. Recovery codes are accepted once and consumed on use. Sign-in never returns a usable token before every factor is satisfied — a pending challenge returns a challenge, never a partial credential.

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:

event types
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_changed

This log is what makes an incident answerable rather than debatable. It is also what the automatic banning reads from.

What is never logged

Passwords, one-time codes, API keys, tokens and gateway secrets are never written to logs — not at debug level, not in error traces, not in request dumps. Supplier credentials are masked when displayed to an operator: enough characters to recognise the key, never enough to use it.

4 · Ordering and delivery#

The chain from a customer pressing Order to a result appearing in their account.

The pipeline

order 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 refund
Steps 1 to 7 are one database transaction. Step 8 runs only after that transaction commits — a supplier must never receive an order that a later rollback erases.

Input normalisation

Customers paste identifiers out of spreadsheets and chat messages. Values arrive decorated:

✅355796467388512
3527266… done ✅
3576 4412 8214 560

Every 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.

IMEISerial / custom
Content15 digitsLetters and digits
LengthFixedWhatever the supplier declares
Check digitLuhn, computed from the first 14None
Customer enters14 digits; the 15th is calculatedThe value as it is
BulkOne per lineOne per line
Sent to supplier asThe standard IMEI parameterA custom field

Names lie

The supplier declares which kind a service is, and Rule One reads that declaration rather than guessing from the service name. A service called “iPad FMI Off” may take a ten-character alphanumeric serial, and a service whose field is labelled “SN” may take a fifteen-digit IMEI.

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:

StateAnswer
Never seenAccept and process
In progress409 — this exact request is running
CompletedReturn 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:

EndWhat happens
CompletedThe 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.
FailedThe amount is returned to the wallet and the order is marked refunded. Failure is never silent.
Rejected before dispatchNothing 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.

What the supplier says about a service is authoritative. Cost, quantity range and field definition follow the supplier on every sync; the selling price, the display name and the description stay under the operator’s control.

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 · README

Endpoint and authentication

endpoint
POST  https://<your-domain>/api/index.php
Content-Type: multipart/form-data
FieldValue
usernameThe reseller's account e-mail on your platform
apiaccesskeyThat account's API key
actionThe operation
requestformatJSON

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

An unknown e-mail, a wrong key and an account without access all answer 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

ActionPurpose
accountinfoBalance and account state
imeiservicelistThe IMEI services this reseller may buy
serverservicelistThe server services this reseller may buy — game top-ups, accounts, licences
placeimeiorder / placeserverorderPlace an order
getimeiorder / getserverorderOrder 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

If you have assigned a catalogue to the account — any mix of individual services and whole groups — these lists contain that and nothing else, and an order for anything outside it is refused with the same answer as an unknown service id. An account you have not restricted sees the whole shop, which is how every account starts. Assigning a GROUP rather than picking services one by one means a service you add to that group next month reaches the reseller without you doing anything.

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.

serverservicelist — a games reseller's view
{
  "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:

imeiservicelist — the device section
{
  "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

Already resolved through their group and currency. Two resellers calling the same endpoint receive different numbers for the same service, and neither can see the other’s. Extra fields a service requires are declared in 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.

form fields
action     = placeserverorder
ID         = <service id>
parameters = <XML string — plain text, not encoded>
QNT        = <only for services ordered by quantity>
the parameters document
<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:

before base64
{"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
1parameters is plain XML. Only the content of CUSTOMFIELD is base64. Encoding the whole document is rejected.
2CUSTOMFIELD is a JSON object, not an array and not a string. {"Email":"…"} — not [{"Email":"…"}].
3Field names must match exactly. Use the fieldname from Requires.Custom, not your own label. Matching is not fuzzy and not case-insensitive.
4ID appears twice — as a form field and inside the parameters document.
5Empty values are dropped. A parameter with an empty value is not sent at all.
6Escape your values. An e-mail containing & breaks an unescaped XML document.
7Use multipart/form-data. Not JSON, not URL-encoded.
8Errors 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.
9Store REFERENCEID. Without it you cannot track the order.

Response

order accepted
{"SUCCESS": [{
  "MESSAGE": "Order placed",
  "REFERENCEID": "58905",
  "STATUS": "processing"
}]}

Tracking

status
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.

Content the operator writes — service names, descriptions, terms — stays in the language they wrote it in. The platform does not machine-translate the operator’s own words without being asked.

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#

PrincipleWhat it means
Server decides everythingPrice, permission, balance and order state have exactly one source
Layered securityNine independent gates, each able to end a request alone
No silent failureAn order completes, refunds, or is refused before it costs anything
AuditableSecurity decisions and order transitions are recorded, not inferred
Standards-based APICompatible in both directions — you can buy and be bought from
Built for scaleBulk ordering, idempotent requests, zero-downtime releases

Rule One — CodRule

Questions about integrating? Open a conversation from any page, or write to [email protected].