Partner earnings API
Private read-only mek_live_ key: balance, available for withdrawal, earnings for a period across all Millida services, and subscribers to your modpacks. The key works only from your server’s IP.
Updated September 28, 2026
If you want to see your earnings on your own website or in a panel, connect the earnings API. It returns the same figures as your wallet on Millida: balance, amount available for withdrawal, and earnings for the selected period broken down by service: modpack subscriptions, hosting, donations, market, and others.
The API is read-only. You cannot withdraw money, change payout details, or pay for anything through it. The key only sees your wallet; you cannot access other people's data with it.
Key
The key is issued in the partner dashboard: Profile → section named after your studio → Earnings API. When issuing it, specify the IP address of the server from which requests will be sent. The key does not work from any other address, even if it is stolen.
- You can specify up to ten addresses or subnets. The subnet must be no wider than
/24for IPv4 and/48for IPv6. - Home and local addresses (
127.0.0.1,10.x,192.168.x) are not accepted: you need the server's public address. - The key is shown once. Store it on the server, in environment variables, or in a secrets store, and never expose it to the browser.
- You can have up to five active keys. If you lose a key or change servers, revoke the old key and issue a new one. A revoked key stops working immediately.
All endpoints are relative to https://api.millida.net/v2. The key is passed in the header:
Authorization: Bearer mek_live_…
Summary
GET /earnings-api/v1/summary?from=2026-09-01T00:00:00.000Z&to=2026-09-30T23:59:59.999Z
from and to are the period boundaries in ISO 8601 format. Both parameters
are optional: without them, the period covers all time.
{
"currency": "RUB",
"balance": {
"balanceKopecks": 1254000,
"availableKopecks": 1204000,
"withdrawableKopecks": 980000,
"heldKopecks": 50000,
"pendingPayoutKopecks": 0,
"tradeHoldKopecks": 0,
"tradeHoldReadyAt": null,
"marketHoldKopecks": 0,
"marketWithdrawalReadyAt": null
},
"period": {
"from": "2026-09-01T00:00:00.000Z",
"to": "2026-09-30T23:59:59.999Z",
"earnedKopecks": 3108000,
"heldKopecks": 0,
"spentKopecks": 0,
"toppedUpKopecks": 0,
"paidOutKopecks": 2000000,
"refundKopecks": 0,
"netKopecks": 1108000,
"operations": 142,
"earnedBySource": [
{ "source": "catalog", "amountKopecks": 2950000, "operations": 131 },
{ "source": "hosting", "amountKopecks": 158000, "operations": 11 }
],
"truncated": false
},
"subscriptions": {
"subscribers": 14,
"bundleSubscribers": 2,
"packSubscribers": 12
}
}
All amounts are in kopecks: 1254000 means 12 540 ₽.
| Field | Meaning |
|---|---|
balance.balanceKopecks | everything in the wallet, including frozen funds |
balance.availableKopecks | can be spent within Millida |
balance.withdrawableKopecks | can be withdrawn right now — the same amount as on the “Withdraw” button |
balance.heldKopecks | frozen until the hold period ends |
period.earnedKopecks | earned during the period across all services |
period.earnedBySource | earnings during the period by service, from largest to smallest |
period.paidOutKopecks | withdrawn during the period |
period.truncated | true — there are too many transactions in the period and the amounts are incomplete: narrow the period |
subscriptions | subscribers to your modpacks right now, briefly; details in the “Subscribers” section |
The source values:
source | Service |
|---|---|
catalog | modpack catalog: subscriptions and purchases |
hosting | hosting |
trade | Trade donations |
market | market |
skins | Millida Skins |
rating | rating |
admin | Millida accruals |
New values may be added over time. If you don't recognize a value, display it as is and don't treat it as an error.
Subscribers
GET /earnings-api/v1/subscriptions?from=2026-09-01T00:00:00.000Z&to=2026-09-30T23:59:59.999Z
How many people are currently playing your modpacks under a Millida subscription and what happened to subscriptions during the period. Subscribers are counted by active access, not by payments: a person counts as long as they can launch the modpack, including the three days after the payment date given for the retry charge. Access via your website's keys, team access, and one-time purchases do not count as subscriptions.
The API returns only numbers. You cannot find out who exactly is subscribed through it.
from and to define the period in the same way as in the summary. They affect only the period block; the total, active, renewal, and packs blocks always show the state at the time of the request.
{
"from": "2026-09-01T00:00:00.000Z",
"to": "2026-09-30T23:59:59.999Z",
"generatedAt": "2026-09-28T16:30:00.000Z",
"total": {
"subscribers": 14,
"bundleSubscribers": 2,
"packSubscribers": 12
},
"partners": [
{
"partner": { "slug": "arcania-labs", "name": "Arcania Labs" },
"active": {
"subscribers": 14,
"bundleSubscribers": 2,
"packSubscribers": 12,
"packSubscriptions": 12
},
"renewal": {
"autoRenewing": { "bundle": 2, "packs": 12 },
"canceledStillActive": { "bundle": 0, "packs": 0 }
},
"packs": [
{ "slug": "arcania", "title": "Arcania 1.4.3", "published": true, "activeSubscribers": 14, "viaPack": 12, "viaBundle": 2 },
{ "slug": "dread", "title": "DREAD - A Horror Survival Pack", "published": true, "activeSubscribers": 2, "viaPack": 0, "viaBundle": 2 }
],
"period": {
"newSubscriptions": { "bundle": 2, "packs": 12 },
"canceled": { "bundle": 0, "packs": 0 },
"expired": { "bundle": 0, "packs": 0 },
"refunded": { "bundle": 0, "packs": 0 }
},
"truncated": false
}
]
}
packs lists all your modpacks, including those with no subscribers.
| Field | Meaning |
|---|---|
total.subscribers | how many distinct people are currently subscribed to at least one of your modpacks |
total.bundleSubscribers | of those, with an “All modpacks” subscription |
total.packSubscribers | of those, with a subscription to an individual modpack |
partners[] | one row per studio you have; if you are not a partner, the list is empty |
active.packSubscriptions | total subscriptions to individual modpacks: one person can have several |
renewal.autoRenewing | subscriptions that will renew automatically: auto-payment is enabled |
renewal.canceledStillActive | auto-payment is disabled, but the paid term is still active; access will end after it |
packs[].activeSubscribers | how many people can play this modpack by subscription |
packs[].viaPack / packs[].viaBundle | of those, by subscription to this modpack and by the “All modpacks” subscription |
period.newSubscriptions | subscriptions whose first charge occurred during the period |
period.canceled | subscriptions for which auto-payment was disabled during the period |
period.expired | access ended during the period and was not renewed |
period.refunded | access was closed during the period due to a refund |
truncated | true — there is too much data and the figures are incomplete: narrow the period |
bundle counts people, while packs counts subscriptions to individual modpacks.
If a subscription is canceled, it appears in canceled on the day of cancellation, and in
expired when the paid term ends.
Errors
| Code | code | What to do |
|---|---|---|
| 401 | INVALID_KEY | the key is missing, has a typo, or is a key of a different type |
| 401 | REVOKED | the key has been revoked — issue a new one |
| 401 | OWNER_UNAVAILABLE | the key owner's account is blocked or deleted |
| 403 | IP_NOT_ALLOWED | the request did not come from an address in the key; the error text shows the address we saw |
| 429 | — | request rate limit exceeded, retry the request in a minute |
Limits
A single key can send up to 30 requests per minute. The figures change along with payments, so there is no point in polling the API more than once a minute. It is better to cache the response on your server.
Example
curl -s https://api.millida.net/v2/earnings-api/v1/summary \
-H "Authorization: Bearer $MILLIDA_EARNINGS_KEY"
curl -s https://api.millida.net/v2/earnings-api/v1/subscriptions \
-H "Authorization: Bearer $MILLIDA_EARNINGS_KEY"