Metadata-Version: 2.4
Name: mrxsim
Version: 1.0.3
Summary: Official Python client for MRXSIM.COM — secure SMS number purchasing & OTP retrieval (zero-knowledge API)
Author-email: MRXSIM <whomrxami@pm.me>
Maintainer-email: MRXSIM <whomrxami@pm.me>
License-Expression: MIT
Project-URL: Homepage, https://mrxsim.com
Project-URL: Documentation, https://mrxsim.com/docs
Project-URL: Repository, https://github.com/MRXSIM/MRXSIM-Universal-SMS-Automation
Project-URL: Bug Tracker, https://github.com/MRXSIM/MRXSIM-Universal-SMS-Automation/issues
Keywords: mrxsim,sms,otp,virtual-number,telegram,whatsapp,automation,api-client
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests<3,>=2.31.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: build>=1.2.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Provides-Extra: async
Requires-Dist: aiohttp<4,>=3.9.0; extra == "async"
Provides-Extra: cli
Requires-Dist: colorama<1,>=0.4.6; extra == "cli"
Dynamic: license-file

# mrxsim

Official Python client for **[MRXSIM.COM](https://mrxsim.com)** — purchase virtual numbers and retrieve SMS OTPs for every catalog service (Telegram, WhatsApp, Google, Instagram, PayPal, Snapchat, Other (SMS), and more).

> Brand: **MRXSIM** · Domain: **https://mrxsim.com** · Package: **`mrxsim`**

---

## Security first

- **No hardcoded API keys** in library source or examples.
- Prefer environment variable ``MRXSIM_API_KEY``.
- Or load a local ``config.json`` that is **gitignored**.
- Never commit live keys. Revoke immediately if exposed.

---

## Install

```bash
pip install mrxsim
```

From this repository (editable):

```bash
pip install -e .
```

---

## Quick start (environment variable)

```bash
export MRXSIM_API_KEY="mrxs_your_key_here"   # Linux / macOS
# setx MRXSIM_API_KEY "mrxs_your_key_here"  # Windows (new shell)
```

```python
from mrxsim import Client

with Client() as client:
    # Discover the catalog — no country/service needed to browse.
    countries = client.list_countries()
    services = client.list_services("england")
    options = client.list_options(country="england", service="telegram")

    order = client.get_number(
        country="england", service="telegram",
        operator=options[0]["operator"],  # a stable MRXSIM option code — never a provider ID
        idempotency_key="my-own-stable-id-for-this-purchase",  # optional, see "Retry safety" below
    )
    print(order["phone_number"], order["id"])

    sms = client.wait_for_sms(order["id"])
    print(sms["sms_code"])

    # client.cancel(order["id"])  # if you need to cancel before the OTP arrives
```

One-shot purchase + OTP:

```python
from mrxsim import Client

with Client(country="egypt", service="whatsapp") as client:
    result = client.buy_and_wait()
    print(result["phone_number"], result["sms_code"])
```

---

## Quick start (config file)

```bash
cp config.example.json config.json
# edit config.json → set api_key, country, service
```

```python
from mrxsim import Client

client = Client.from_config("config.json")
order = client.get_number()
sms = client.wait_for_sms(order["id"])
client.close()
```

``MRXSIM_API_KEY`` overrides ``api_key`` in the file when set.

---

## Get your API key

1. Open [https://mrxsim.com](https://mrxsim.com) and create an account.
2. Top up with **Crypto** (USDT / supported networks).
3. **Profile → Get API KEY** (shown once at create/regenerate).
4. Export ``MRXSIM_API_KEY`` or paste into gitignored ``config.json``.

---

## API surface

| Method | Endpoint | Client method |
|--------|----------|---------------|
| `GET` | `/api/v1/sms/catalog` | `Client.list_countries()` |
| `GET` | `/api/v1/sms/services?country=…` | `Client.list_services()` |
| `GET` | `/api/v1/sms/operators?country=…&service=…` | `Client.list_options()` |
| `POST` | `/api/v1/get_number` | `Client.get_number()` |
| `GET` | `/api/v1/get_sms?order_id=…` | `Client.get_sms()` / `wait_for_sms()` |
| `POST` | `/api/v1/cancel` | `Client.cancel()` |

Catalog discovery (`list_countries`/`list_services`/`list_options`) is public MRXSIM
data — no purchase, no debit — and does not consume your purchase-tier rate budget.
An `operator` value from `list_options()` is a stable, MRXSIM-owned option code
(e.g. `"opt1"`, `"opt2"` for a service with more than one genuinely distinct price
tier) — never an upstream provider identifier — pass it straight to `get_number()`.

Header on every call:

```http
X-API-Key: YOUR_KEY
```

### Public order fields (zero-knowledge)

Successful responses expose **retail** fields only — aligned with the MRXSIM
server `OrderPublicOut` contract:

| Field | Meaning |
|-------|---------|
| `id` | MRXSIM order UUID |
| `phone_number` | Assigned number |
| `service` / `country` | Catalog codes |
| `status` | Order status |
| `price` | Retail USDT price charged |
| `sms_code` | OTP when received |

Internal operational metrics and upstream routing identifiers are **not** part
of the public API. The client also sanitizes responses client-side if any such
fields ever appear (defense in depth).

Docs: [https://mrxsim.com/docs](https://mrxsim.com/docs)

## Retry safety

`Client` **never automatically retries `get_number()`** — not on a timeout, not
on a network error, not on a `503`. A hidden automatic retry on a purchase call
is exactly how a client library accidentally causes a real second charge for
one logical purchase, so this client simply doesn't do it. What it gives you
instead, so *you* can retry safely when you choose to:

- **`idempotency_key`** on `get_number()` — pass the same string across your
  own retry attempts (e.g. after catching `MrxsimTimeoutError`) and MRXSIM
  guarantees at most one real purchase for that key, returning the original
  order on a repeat instead of buying a second number. Omit it for a normal,
  independent purchase.
- **`MrxsimRateLimitError.retry_after`** (`429`) and
  **`MrxsimServiceUnavailableError.retry_after`** (`503`, MRXSIM's own
  capacity backpressure — distinct from a per-key rate limit) — both carry the
  server's real `Retry-After` value in seconds (`None` if the response didn't
  include one). Prefer it over a fixed client-side delay:

```python
import time
from mrxsim import Client, MrxsimRateLimitError, MrxsimServiceUnavailableError

client = Client()
try:
    order = client.get_number(idempotency_key="my-own-stable-id-for-this-purchase")
except (MrxsimRateLimitError, MrxsimServiceUnavailableError) as exc:
    if exc.retry_after:
        time.sleep(exc.retry_after)
        order = client.get_number(idempotency_key="my-own-stable-id-for-this-purchase")
    else:
        raise
```

Plain read calls (`get_sms()`, status polling inside `wait_for_sms()`) are
naturally safe to retry on your own — they never mutate anything — so this
client doesn't add speculative auto-retry logic there either; keep your own
retry loop as simple or as sophisticated as your application needs.

---

## Changelog

### 1.0.3

- **`get_number(idempotency_key=...)`** — optional, forwarded as an
  `Idempotency-Key` header; a retry with the same key (and the same
  country/service/operator) returns the original order instead of a second
  purchase. Omitted by default — this client never generates or reuses a key
  on your behalf.
- **`MrxsimRateLimitError`/new `MrxsimServiceUnavailableError`** now expose a
  real `retry_after` (seconds) parsed from the server's `Retry-After` header,
  `None` if absent. `MrxsimServiceUnavailableError` is new — raised on `503`
  (MRXSIM's own capacity backpressure, distinct from the per-key `429`).
- New "Retry safety" section above — documents that this client never
  automatically retries a purchase call, by design.
- **`list_countries()`/`list_services()`/`list_options()`** — real catalog
  discovery, added 2026-08-31 (this version was never published while this
  gap existed, so it's folded into 1.0.3 rather than bumping to 1.0.4). Calls
  MRXSIM's existing public catalog endpoints directly — same canonical data
  Website/Mini App/Bot render, zero provider identity ever included.
- **`cancel(order_id)`** — added 2026-08-31, alongside a real server-side
  developer-API cancel endpoint (there was none before). Reuses the same
  proven cancel/refund logic the web/bot surface already uses — idempotent,
  provider-neutral errors, refunds only on a confirmed provider outcome.
- User-Agent bumped to `mrxsim-python/1.0.3`.

### 1.0.2

- Sanitize client responses to strip internal operational metrics and upstream routing identifiers.
- Harden public documentation for white-label / zero-knowledge API alignment.
- User-Agent bumped to `mrxsim-python/1.0.2`.

### 1.0.1

- Document and enforce zero-knowledge public order fields.
- User-Agent bumped to `mrxsim-python/1.0.1`.

---

## Examples

```bash
export MRXSIM_API_KEY="…"
python examples/buy_number_example.py
python examples/get_otp_example.py <order_id>
```

---

## Development

```bash
python -m venv .venv
# Windows: .venv\Scripts\activate
source .venv/bin/activate
pip install -e ".[dev]"
pytest
python -m build
```

---

## Support

- Site: [https://mrxsim.com](https://mrxsim.com)
- Docs: [https://mrxsim.com/docs](https://mrxsim.com/docs)
- Issues: [GitHub](https://github.com/MRXSIM/MRXSIM-Universal-SMS-Automation/issues)

© MRXSIM · Secure SMS Infrastructure
