Billing
Premium is paid from prepaid credit. You add credit with a crypto deposit, and spend it on premium time. Billing belongs to accounts: anonymous sessions have no balance, and every endpoint here except the public lists needs a logged-in session. API keys cannot call billing endpoints.
Amounts
- Every amount is USD as a decimal string with exactly 18 fractional digits:
"4.990000000000000000"is $4.99. Parse it as a decimal or as an integer number of 10^-18 USD units. Never parse it as a floating-point number. - Crypto amounts (
amount,min_deposit) are integer strings in the asset's smallest unit, withdecimalsplaces. For examplemin_deposit"1000000"withdecimals6is 1 USDC. - Credit enters by deposit or referral reward and leaves only by being spent. There is no withdrawal or refund endpoint.
Get plans
The plans you can buy. No authentication.
Response
An array of plans.
- Name
plan- Type
- string
- Description
premium.
- Name
price_per_month- Type
- string
- Description
Price of one 30-day period, USD.
- Name
max_months- Type
- integer
- Description
Most months one purchase can cover.
Request
curl https://mail.nullnet.sh/v1/billing/plans
Response
[
{
"plan": "premium",
"price_per_month": "4.990000000000000000",
"max_months": 12
}
]
Get the balance
The account's credit and subscription.
Response
- Name
balance- Type
- string
- Description
Credit balance, USD.
- Name
currency- Type
- string
- Description
USD.
- Name
decimals- Type
- integer
- Description
18.
- Name
subscription- Type
- object | null
- Description
plan,period_end(timestamp) andactive(whetherperiod_endis in the future), ornullif the account never subscribed.
Request
curl https://mail.nullnet.sh/v1/billing/balance \
-H "Authorization: Bearer {token}"
Response
{
"balance": "12.500000000000000000",
"currency": "USD",
"decimals": 18,
"subscription": {
"plan": "premium",
"period_end": "2026-11-25T08:00:00Z",
"active": true
}
}
List ledger entries
Every change to the balance, newest first, as a page. The balance is the sum of all delta values.
Optional query parameters
- Name
limit- Type
- integer
- Description
Page size, 1–100. Default 25.
- Name
cursor- Type
- string
- Description
next_cursorfrom the previous page.
Entry fields
- Name
id- Type
- string
- Description
Entry id.
- Name
delta- Type
- string
- Description
Signed change, USD. Negative for spending.
- Name
kind- Type
- string
- Description
What caused it (see below).
- Name
ref_id- Type
- string | null
- Description
Related object, for example the deposit id for
deposit.
- Name
memo- Type
- string | null
- Description
Description.
- Name
created_at- Type
- timestamp
- Description
When it was posted.
Kinds
- Name
deposit- Description
A confirmed crypto deposit.
ref_idis the deposit id.
- Name
premium_charge- Description
Premium time bought.
- Name
referral_reward- Description
Your share of a referred account's deposit. See referrals.
- Name
referral_bonus- Description
A one-off referral bonus.
- Name
gift_code- Description
Credit from a gift code.
- Name
gift_code_purchase- Description
Credit spent on a gift code.
- Name
manual_payout, admin_adjust- Description
Entries made by support, with a memo.
- Name
reversal- Description
Reverses an earlier entry.
Request
curl -G https://mail.nullnet.sh/v1/billing/ledger \
-H "Authorization: Bearer {token}" \
-d limit=25
Response
{
"items": [
{
"id": "019a2fa0-1b2c-7d3e-8f40-5a6b7c8d9e0f",
"delta": "-4.990000000000000000",
"kind": "premium_charge",
"ref_id": null,
"memo": null,
"created_at": "2026-10-26T08:10:00Z"
},
{
"id": "019a2f9a-7c8d-7e9f-a0b1-c2d3e4f5a6b7",
"delta": "17.490000000000000000",
"kind": "deposit",
"ref_id": "019a2f95-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
"memo": null,
"created_at": "2026-10-26T08:02:00Z"
}
],
"next_cursor": null
}
Buy premium
Spends credit on premium time: price_per_month × months is charged at once. The subscription is extended by 30 days per month, from its current end if it is still active, otherwise from now. The account becomes premium immediately; fetch GET /v1/account again for the new limits.
If the balance is short, the request returns 402 payment_required with the balance and the price in the message, and nothing changes.
When the paid period ends, the account returns to the free tier automatically. Inboxes above the free limit are kept until they expire; new inboxes follow the free limits.
Required attributes
- Name
months- Type
- integer
- Description
1 to
max_monthsfrom the plan.
Response
- Name
charged- Type
- string
- Description
Amount charged, USD.
- Name
period_end- Type
- timestamp
- Description
New end of the paid period.
- Name
balance- Type
- string
- Description
Balance after the charge, USD.
Request
curl https://mail.nullnet.sh/v1/billing/subscribe \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"months": 1}'
Response
{
"charged": "4.990000000000000000",
"period_end": "2026-11-25T08:10:00Z",
"balance": "12.500000000000000000"
}
Deposits
Credit is bought with crypto only. The flow:
- List the assets you can deposit with
GET /v1/billing/assets. - Ask for your address for one asset with
POST /v1/billing/deposit. - Send at least
min_depositto that address from any wallet. - Poll
GET /v1/billing/deposits(every 15 seconds or so) while the deposit confirms. When its status becomescredited, the USD value has been added to your balance as adepositledger entry, exactly once.
Each account has one address per asset family, for life. EVM networks share one address, so the address for USDC on Base is the same as for ETH on Ethereum. A deposit below the asset's minimum is never credited.
The deposit endpoints return 503 unavailable if payments are temporarily not available.
List deposit assets
What can be deposited. No authentication. Build your asset picker from this list rather than hard-coding it.
Response
An array of assets.
- Name
key- Type
- string
- Description
Asset key used in
POST /v1/billing/deposit,<SYMBOL>@<network>.
- Name
symbol- Type
- string
- Description
Ticker.
- Name
network- Type
- string
- Description
Network id.
- Name
network_display- Type
- string
- Description
Network name for display.
- Name
decimals- Type
- integer
- Description
Decimal places of the smallest unit.
- Name
min_deposit- Type
- string
- Description
Smallest creditable deposit, in smallest units.
- Name
confirmations- Type
- integer
- Description
Confirmations before a deposit is credited.
- Name
est_confirmation_secs- Type
- integer
- Description
Rough time to reach those confirmations.
Request
curl https://mail.nullnet.sh/v1/billing/assets
Response
[
{
"key": "BTC@bitcoin",
"symbol": "BTC",
"network": "bitcoin",
"network_display": "Bitcoin",
"decimals": 8,
"min_deposit": "10000",
"confirmations": 2,
"est_confirmation_secs": 1200
},
{
"key": "USDC@base",
"symbol": "USDC",
"network": "base",
"network_display": "Base",
"decimals": 6,
"min_deposit": "1000000",
"confirmations": 20,
"est_confirmation_secs": 40
}
// ... ETH@base, ETH@ethereum, USDC@ethereum
]
Get a deposit address
Returns your deposit address for an asset. The same address comes back every time. Returns 400 bad_request for an unknown asset.
Required attributes
- Name
asset- Type
- string
- Description
An asset
keyfromGET /v1/billing/assets, case-insensitive.
Response
- Name
asset- Type
- string
- Description
Asset key.
- Name
network- Type
- string
- Description
Network id.
- Name
address- Type
- string
- Description
Your deposit address.
- Name
uri- Type
- string
- Description
Payment URI for wallets and QR codes: BIP-21 for Bitcoin, EIP-681 for EVM assets.
- Name
min_deposit- Type
- string
- Description
Smallest creditable deposit, in smallest units.
- Name
decimals- Type
- integer
- Description
Decimal places of the smallest unit.
- Name
confirmations- Type
- integer
- Description
Confirmations before crediting.
Request
curl https://mail.nullnet.sh/v1/billing/deposit \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"asset": "USDC@base"}'
List deposits
The account's deposits, newest first (up to 100), as an array.
Deposit fields
- Name
id- Type
- string
- Description
Deposit id. Matches
ref_idof the ledger entry once credited.
- Name
asset- Type
- string
- Description
Asset key.
- Name
network- Type
- string
- Description
Network id.
- Name
amount- Type
- string
- Description
Amount received, in smallest units.
- Name
decimals- Type
- integer
- Description
Decimal places of
amount.
- Name
status- Type
- string
- Description
See below.
- Name
confirmations- Type
- integer
- Description
Confirmations so far.
- Name
tx_hash- Type
- string
- Description
Transaction hash.
- Name
credited_usd- Type
- string | null
- Description
USD credited, once credited.
- Name
seen_at- Type
- timestamp
- Description
When the deposit was first seen.
- Name
credited_at- Type
- timestamp | null
- Description
When it was credited.
Statuses
- Name
seen- Description
Detected on chain.
- Name
confirming- Description
Waiting for confirmations.
- Name
credited- Description
Final. The USD value is in your balance.
- Name
reversed- Description
The transaction disappeared from the chain after being credited.
- Name
below_minimum- Description
Smaller than
min_deposit. Never credited.
- Name
pending_review- Description
Held for manual review.
Request
curl https://mail.nullnet.sh/v1/billing/deposits \
-H "Authorization: Bearer {token}"
Response
[
{
"id": "019a2f95-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
"asset": "USDC@base",
"network": "base",
"amount": "17490000",
"decimals": 6,
"status": "credited",
"confirmations": 20,
"tx_hash": "0x5e2b…",
"credited_usd": "17.490000000000000000",
"seen_at": "2026-10-26T08:01:20Z",
"credited_at": "2026-10-26T08:02:00Z"
}
]