Lynx API reference

Reseller API · v1

Lynx Reseller API

Open interactive explorer

Browse the complete reference below. Use the explorer to try requests and generate client code.

Base URLhttps://api.lynxcheats.com/api/v1

This API gives your storefront or your bot what it needs to sell Lynx packages and Lynx Cloud credits. Read your balance. Read your prices next to the customer prices. Generate keys, and get a claim link with each key.

Two words in this document look similar. An API key is the credential that identifies your integration. A key is a license that you sell to a customer.

Get started

  1. Open the dashboard. Go to Reseller → API.
  2. Create an API key. Copy it. The dashboard shows it one time only.
  3. Store the API key on your server. Use an environment variable.
  4. Call GET /api/v1/me with the API key. This confirms that the API key works.
  5. Call GET /api/v1/products to read your prices.
  6. Call POST /api/v1/keys to buy keys and get their claim links.

Authentication

Send your API key in the Authorization header of each request. The /openapi.json endpoint is the one exception.

Authorization: Bearer lyx_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The server keeps only a hash of your API key. No page can show the API key to you again. If you lose an API key, revoke it and create another one.

An API key can spend your balance. Treat it like a password. Keep it on your server. Do not put it in a browser, in an app bundle, or in a public repository.

Scopes

Each API key holds a set of scopes. A scope permits one group of operations. The server refuses a request that is outside the scopes of the API key, and answers 403 forbidden.

Give each integration only the scopes that it needs. A price bot needs catalog:read and nothing more.

scope permits
account:read Read your reseller profile, your group, and your discount
balance:read Read your balance
catalog:read Read packages, plans, your prices, and customer prices
keys:read List and read the keys in your inventory
keys:write Generate keys, refund keys, and set gift text
orders:read Read your purchase history

Money and idempotency

POST /api/v1/keys charges your balance. POST /api/v1/keys/{key}/refund returns credits to it.

The charge endpoint is idempotent on the idempotencyKey field. If you send the same value again, the server charges you one time. The response holds the first result and alreadyMinted: true. The same value with a different request gets 409 conflict.

Make one idempotency key for each order. Use that same value for each retry of that order. A new value on each attempt charges you two times.

The refund endpoint is idempotent on the key. A second refund of one key pays you nothing and returns alreadyRefunded: true.

Lynx Cloud

Lynx Cloud runs game accounts on Lynx servers. A member pays for play with cloud credits. One credit is one hour of play for one account, on any Lynx Cloud game.

To sell credits, send cloudHours in place of priceId to POST /api/v1/keys. Each key then adds that number of credits, from 4 to 100000, in steps of 4. You pay $0.025 an hour and the customer price follows the reseller price sheet for a whole number of days and is $0.045 an hour otherwise: every 4 hours cost you one reseller credit. A key of 720 hours (30 days) sells for $22.69 and costs you 180 credits.

A cloud mint makes no order. Its orderId is null, GET /api/v1/orders does not show it, and it sends no webhook event.

Each key in a response has a claimUrl field. Give the customer the key, or the link, or both.

The link opens a claim page. The page shows the package, your store name, and your message. The customer then redeems the key. Gift codes use this same page, so one flow serves both.

Set senderLabel and message when you generate a batch. These two fields control what the customer sees. A key with one of them is a gift. You can change both later with POST /api/v1/keys/{key}/gift or in the dashboard.

Redemption

A member redeems a key or a gift link only while signed in to a Lynx account. Nobody can redeem a key without an account.

  • A cloud key adds its credits to the account of the member one time. The credits do not expire.
  • If Lynx revokes a cloud key, its credits come off the balance of the member, as far as the balance goes.
  • The mod apps refuse a cloud key.

Webhooks

Set a webhook URL in the dashboard under Reseller → API. The URL must use https and must point at a public host. The dashboard shows the signing secret one time, when you save the first URL. Rotate secret makes a new one, and the old secret stops working at once.

Lynx sends a POST with a JSON body for each event:

Event When
order.completed A purchase generated keys, from the API, the dashboard or the bot.
order.refunded One key of an order went back to your balance.
webhook.test You pressed Send test event.
{
  "id": "evt_k57d…",
  "type": "order.completed",
  "createdAt": 1760000000000,
  "data": {
    "orderId": "k97a…", "batchId": "…", "productId": "…", "priceId": "…",
    "quantity": 2, "unitCostCents": 600, "totalCents": 1200,
    "unitCredits": 60, "totalCredits": 120,
    "keys": [{ "key": "LYNX-…", "claimUrl": "https://…" }],
    "createdAt": 1760000000000
  }
}

order.refunded holds orderId, key, productId, priceId, refundedCents, refundedCredits and refundedAt.

Each request has three headers:

  • Lynx-Event-Id: the id of the event. A retry or a redelivery sends the same id, so store it and skip an id you have seen.
  • Lynx-Event-Type: the type of the event.
  • Lynx-Signature: t=<unix seconds>,v1=<hex>. The hex is the HMAC-SHA256 of <t>.<raw body>, keyed with your signing secret.

To verify a request, compute the HMAC over the raw body as received, compare it with v1 in constant time, and refuse a t more than five minutes old.

const [t, v1] = header.split(",").map((part) => part.split("=")[1]);
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));

Answer with any 2xx status within 10 seconds. Any other answer, a redirect or a timeout is a failure. Lynx then tries again after 1, 4, 16 and 64 minutes, then after 4 hours, then twice after 8 hours: 8 attempts over about 22 hours. The dashboard lists each delivery for 30 days, with its status and last response, and can send one again.

Errors

A failed request returns this shape. The HTTP status matches the code.

{ "error": { "code": "invalid_request", "message": "quantity must be a number" } }
code status meaning
unauthorized 401 The API key is missing, malformed, unknown, or revoked.
forbidden 403 The API key is valid, but it does not hold the necessary scope.
not_found 404 The endpoint does not exist, or the key is not in your inventory.
invalid_request 400 A field is missing, or its value is out of range.
conflict 409 You sent an idempotency key again with a different request.
rate_limited 429 You sent too many requests. The message tells you when to retry.
server_error 500 The server failed. A retry of an idempotent request is safe.

Rate limits

Each API key holds two budgets. Read requests and write requests do not share a budget.

  • Read: 600 each hour, with a burst of 120.
  • Write: 120 each hour, with a burst of 30.

Refunds also have a budget for each reseller account: 60 each hour.

Do not share one API key between integrations that do not relate to each other. Create a second API key instead.

Pagination

List endpoints accept two query parameters. limit sets the page size, from 1 to 200. cursor continues a previous listing.

A list response holds three fields: data, hasMore, and nextCursor.

To read the next page, send nextCursor as the cursor parameter. Stop when hasMore is false.

GET/me

Read your reseller profile

Returns your uid, your username, your key prefix, and your reseller group. Call this endpoint once at start-up. It confirms that an API key works, and it tells you your discount.

Authentication: Authorization: Bearer <API key>

Responses

200 Your reseller profile

application/json

Schema: Account

View JSON schema
{
  "$ref": "#/components/schemas/Account"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

GET/balance

Read your balance

Read this endpoint before you generate keys. Your balance is reseller credits: 1 credit is 10 cents, and the cents fields show that value. A purchase succeeds if its total is at or below availableCents.

Authentication: Authorization: Bearer <API key>

Responses

200 Your balance

application/json

Schema: Balance

View JSON schema
{
  "$ref": "#/components/schemas/Balance"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

GET/products

Read packages, plans, and both prices

Returns each active package with the plans that you can buy. Each plan holds customerPriceCents and yourPriceCents, and the same prices in credits. customerPriceCents is the storefront price. yourPriceCents is your cost. Your bot can set its own prices from these two numbers, and it does not need a hard-coded discount. The list holds only the plans that are public on a platform you sell.

Each entry has a kind. A mobile entry and a pc entry list mod plans. Lynx Cloud credit keys have no plan: send cloudHours to POST /keys.

Authentication: Authorization: Bearer <API key>

Responses

200 The packages you can buy

application/json

Read packages, plans, and both prices 200 response
FieldTypeDescription
dataPackage[]
View JSON schema
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/Package"
      }
    }
  }
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

GET/keys

List your keys

Returns your keys, newest first. Use the status parameter to select one state. Unsold stock has the status dormant. A redeemed key has the status active. Use gift to select gift keys, and cloud to select Lynx Cloud keys.

Authentication: Authorization: Bearer <API key>

Parameters

NameLocation / typeDescription
limitquery
integer
How many rows one page holds, from 1 to 200.
cursorquery
string
The `nextCursor` value from the previous page.
statusquery
string
Return only the keys in this state.

Values: dormant, active, expired, revoked

productIdquery
string
Return only the keys for this package.
fromquery
integer
Return only the keys made at or after this unix time in milliseconds.
toquery
integer
Return only the keys made at or before this unix time in milliseconds.
giftquery
string
`true` returns only the keys with a sender name or a message. `false` returns only the other keys.

Values: true, false

cloudquery
string
`true` returns only the Lynx Cloud keys. `false` returns only the mod keys.

Values: true, false

Responses

200 One page of keys

application/json

List your keys 200 response
FieldTypeDescription
dataKey[]
hasMoreboolean
nextCursorstring | null
View JSON schema
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/Key"
      }
    },
    "hasMore": {
      "type": "boolean"
    },
    "nextCursor": {
      "type": [
        "string",
        "null"
      ]
    }
  }
}
400 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

POST/keys

Generate keys

Charges your reseller credits and makes up to 500 keys of one plan. The response holds each key and its claim link.

This endpoint is idempotent on idempotencyKey. Use the same value for each retry of one order. The server then charges you one time. A repeat request returns the original keys and alreadyMinted: true. A repeat request with a different plan, number of hours or quantity gets 409 conflict.

senderLabel and message control what the customer sees on the claim page. Both are optional. A key with one of them is a gift. You can change both later with POST /keys/{key}/gift or in the dashboard.

To sell Lynx Cloud credits, send cloudHours in place of priceId. Each key then adds that number of cloud credits to the account that redeems it. A cloud mint makes no order, so orderId is null.

Authentication: Authorization: Bearer <API key>

Request body required

application/json

Generate keys request body
FieldTypeDescription
priceIdstring

Take this value from GET /products. Send priceId or cloudHours, not both.

cloudHoursinteger

Makes Lynx Cloud credit keys: the cloud credits that each key adds, a multiple of 4. One credit is one hour of play.

Minimum: 4.

Maximum: 100000.

Example: 720

quantityrequiredinteger

Minimum: 1.

Maximum: 500.

idempotencyKeyrequiredstring

Your own id for this order, 8 to 64 characters. Use the same value for each retry.

senderLabelstring

The sender name the claim page shows. The default is your account name.

Maximum length: 40 characters.

messagestring

A note that the customer reads before redemption.

Maximum length: 280 characters.

notestring

Private to you. The customer never sees it.

View JSON schema
{
  "type": "object",
  "required": [
    "quantity",
    "idempotencyKey"
  ],
  "properties": {
    "priceId": {
      "type": "string",
      "description": "Take this value from `GET /products`. Send `priceId` or `cloudHours`, not both."
    },
    "cloudHours": {
      "type": "integer",
      "minimum": 4,
      "maximum": 100000,
      "multipleOf": 4,
      "description": "Makes Lynx Cloud credit keys: the cloud credits that each key adds, a multiple of 4. One credit is one hour of play.",
      "example": 720
    },
    "quantity": {
      "type": "integer",
      "minimum": 1,
      "maximum": 500
    },
    "idempotencyKey": {
      "type": "string",
      "description": "Your own id for this order, 8 to 64 characters. Use the same value for each retry."
    },
    "senderLabel": {
      "type": "string",
      "maxLength": 40,
      "description": "The sender name the claim page shows. The default is your account name."
    },
    "message": {
      "type": "string",
      "maxLength": 280,
      "description": "A note that the customer reads before redemption."
    },
    "note": {
      "type": "string",
      "description": "Private to you. The customer never sees it."
    }
  }
}

Responses

201 The keys the server made

application/json

Generate keys 201 response
FieldTypeDescription
orderIdstring | null

null for Lynx Cloud keys. A cloud mint makes no order.

batchIdstring
quantityinteger
unitCostCentsinteger

The cost of one key, in cents.

totalCentsinteger

The cost of the batch, in cents.

balanceAfterCentsinteger

Your balance after the charge, in cents.

unitCreditsinteger

The cost of one key, in credits.

totalCreditsinteger

The cost of the batch, in credits.

balanceAfterCreditsinteger

Your balance after the charge, in credits.

alreadyMintedboolean

true means that this idempotencyKey was already used. The server did not charge you again.

cloudHoursinteger | null

The cloud credits that each key adds. null for mod keys.

keysMintedKey[]
View JSON schema
{
  "type": "object",
  "properties": {
    "orderId": {
      "type": [
        "string",
        "null"
      ],
      "description": "null for Lynx Cloud keys. A cloud mint makes no order."
    },
    "batchId": {
      "type": "string"
    },
    "quantity": {
      "type": "integer"
    },
    "unitCostCents": {
      "type": "integer",
      "description": "The cost of one key, in cents."
    },
    "totalCents": {
      "type": "integer",
      "description": "The cost of the batch, in cents."
    },
    "balanceAfterCents": {
      "type": "integer",
      "description": "Your balance after the charge, in cents."
    },
    "unitCredits": {
      "type": "integer",
      "description": "The cost of one key, in credits."
    },
    "totalCredits": {
      "type": "integer",
      "description": "The cost of the batch, in credits."
    },
    "balanceAfterCredits": {
      "type": "integer",
      "description": "Your balance after the charge, in credits."
    },
    "alreadyMinted": {
      "type": "boolean",
      "description": "true means that this idempotencyKey was already used. The server did not charge you again."
    },
    "cloudHours": {
      "type": [
        "integer",
        "null"
      ],
      "description": "The cloud credits that each key adds. null for mod keys."
    },
    "keys": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/MintedKey"
      }
    }
  }
}
400 A field is not in the request, or its value is out of range. Or you sent both `priceId` and `cloudHours`, or neither. Or you sent `cloudGame` or `seats`, which `cloudHours` replaced. Or your balance is too low.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
409 You sent this idempotencyKey before with a different plan, number of hours, or quantity.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
429 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

GET/keys/{key}

Read one key

Returns a key from your own inventory. Any other key returns 404, even if that key exists.

Authentication: Authorization: Bearer <API key>

Parameters

NameLocation / typeDescription
keyrequiredpath
string
The key, with or without its dashes.

Responses

200 One key

application/json

Schema: Key

View JSON schema
{
  "$ref": "#/components/schemas/Key"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
404 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

POST/keys/{key}/refund

Refund a key

Revokes a key that nobody redeemed and that you bought with your balance. The server returns the full cost of the key to your reseller credits. Nobody can redeem a revoked key.

This endpoint is idempotent. A second call on the same key refunds nothing and returns alreadyRefunded: true.

Each reseller account can send 60 refunds in one hour. This budget is in addition to the write budget of the API key.

Authentication: Authorization: Bearer <API key>

Parameters

NameLocation / typeDescription
keyrequiredpath
string
The key, with or without its dashes.

Responses

200 The refund

application/json

Schema: KeyRefund

View JSON schema
{
  "$ref": "#/components/schemas/KeyRefund"
}
400 A member redeemed the key, or staff revoked it. Or you did not buy it with your balance, or a device holds it.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
404 The key is not in your inventory.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
429 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

POST/keys/{key}/gift

Wrap or unwrap a key as a gift

Sets the sender name and the message that the claim page shows for a key. A key with one of them is a gift. Send an empty string to clear a field. When you clear both fields, the key is not a gift.

A field that you do not send does not change.

Authentication: Authorization: Bearer <API key>

Parameters

NameLocation / typeDescription
keyrequiredpath
string
The key, with or without its dashes.

Request body required

application/json

Wrap or unwrap a key as a gift request body
FieldTypeDescription
senderLabelstring

The sender name that the claim page shows. It cannot be an email address. An empty string clears it.

Maximum length: 40 characters.

messagestring

A note that the customer reads before redemption. An empty string clears it.

Maximum length: 280 characters.

View JSON schema
{
  "type": "object",
  "properties": {
    "senderLabel": {
      "type": "string",
      "maxLength": 40,
      "description": "The sender name that the claim page shows. It cannot be an email address. An empty string clears it."
    },
    "message": {
      "type": "string",
      "maxLength": 280,
      "description": "A note that the customer reads before redemption. An empty string clears it."
    }
  }
}

Responses

200 The gift fields of the key

application/json

Schema: KeyGift

View JSON schema
{
  "$ref": "#/components/schemas/KeyGift"
}
400 The body is not a JSON object. Or the sender name is an email address, or it is longer than 40 characters. Or the message is longer than 280 characters.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
404 The key is not in your inventory.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
429 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

GET/orders

Read your purchase history

Returns your orders, newest first. The batchId field connects an order to the keys that it made. Use batchId to reconcile a charge against GET /keys. A Lynx Cloud mint makes no order. An order that added Lynx Cloud seats, before cloud credits, has no batchId.

Authentication: Authorization: Bearer <API key>

Parameters

NameLocation / typeDescription
limitquery
integer
How many rows one page holds, from 1 to 200.
cursorquery
string
The `nextCursor` value from the previous page.

Responses

200 One page of orders

application/json

Read your purchase history 200 response
FieldTypeDescription
dataOrder[]
hasMoreboolean
nextCursorstring | null
View JSON schema
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/Order"
      }
    },
    "hasMore": {
      "type": "boolean"
    },
    "nextCursor": {
      "type": [
        "string",
        "null"
      ]
    }
  }
}
400 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
401 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}
403 The server refused the request.

application/json

Schema: Error

View JSON schema
{
  "$ref": "#/components/schemas/Error"
}

GET/openapi.json

Read this document

This is the one endpoint that does not need an API key.

Authentication is not required.

Responses

200 This OpenAPI document

Schemas

Error

Error schema
FieldTypeDescription
errorobject
error.codestring
error.messagestring
View JSON schema
{
  "type": "object",
  "properties": {
    "error": {
      "type": "object",
      "properties": {
        "code": {
          "type": "string"
        },
        "message": {
          "type": "string"
        }
      }
    }
  }
}

Key

Key schema
FieldTypeDescription
keystring

Example: "LYNX-A4KD-92JM-P3QR-7WTX"

claimUrlstring | null

Give this link to the customer in place of the raw key.

Example: "https://app.lynxcheats.com/redeem?code=LYNX-A4KD-92JM-P3QR-7WTX"

statusstring

One of: dormantactiveexpiredrevoked

productIdstring | null
packageNamestring | null
priceIdstring | null
planNamestring | null
platformstring | null

null means that the key works on each platform of the package. A Lynx Cloud key also has null.

durationDaysinteger

How many days the license runs. 0 means that it never expires.

deviceLimitinteger

How many devices the key permits. 0 means no limit.

devicesUsedinteger
costCentsinteger

The amount you paid, in cents.

retailCentsinteger

The customer price when the key was made, in cents.

costCreditsinteger

The amount you paid, in credits.

retailCreditsinteger

The customer price when the key was made, in credits.

currencystring

USD for new financial operations; historical records retain their original currency.

Example: "usd"

batchIdstring
createdAtinteger

Unix time in milliseconds.

activatedAtinteger | null
expiresAtinteger | null
notestring | null
senderLabelstring | null

The sender name that the claim page shows.

messagestring | null

The note that the claim page shows.

giftboolean

true means that the key has a sender name or a message. The key is then a gift.

cloudHoursinteger | null

The cloud credits that a Lynx Cloud key adds to the account that redeems it. One credit is one hour of play. null means that the key is a mod key.

Example: 720

View JSON schema
{
  "type": "object",
  "properties": {
    "key": {
      "type": "string",
      "example": "LYNX-A4KD-92JM-P3QR-7WTX"
    },
    "claimUrl": {
      "type": [
        "string",
        "null"
      ],
      "description": "Give this link to the customer in place of the raw key.",
      "example": "https://app.lynxcheats.com/redeem?code=LYNX-A4KD-92JM-P3QR-7WTX"
    },
    "status": {
      "type": "string",
      "enum": [
        "dormant",
        "active",
        "expired",
        "revoked"
      ]
    },
    "productId": {
      "type": [
        "string",
        "null"
      ]
    },
    "packageName": {
      "type": [
        "string",
        "null"
      ]
    },
    "priceId": {
      "type": [
        "string",
        "null"
      ]
    },
    "planName": {
      "type": [
        "string",
        "null"
      ]
    },
    "platform": {
      "oneOf": [
        {
          "type": "string",
          "enum": [
            "ios",
            "android",
            "desktop"
          ]
        },
        {
          "type": "null"
        }
      ],
      "description": "null means that the key works on each platform of the package. A Lynx Cloud key also has null."
    },
    "durationDays": {
      "type": "integer",
      "description": "How many days the license runs. 0 means that it never expires."
    },
    "deviceLimit": {
      "type": "integer",
      "description": "How many devices the key permits. 0 means no limit."
    },
    "devicesUsed": {
      "type": "integer"
    },
    "costCents": {
      "type": "integer",
      "description": "The amount you paid, in cents."
    },
    "retailCents": {
      "type": "integer",
      "description": "The customer price when the key was made, in cents."
    },
    "costCredits": {
      "type": "integer",
      "description": "The amount you paid, in credits."
    },
    "retailCredits": {
      "type": "integer",
      "description": "The customer price when the key was made, in credits."
    },
    "currency": {
      "type": "string",
      "example": "usd",
      "description": "USD for new financial operations; historical records retain their original currency."
    },
    "batchId": {
      "type": "string"
    },
    "createdAt": {
      "type": "integer",
      "description": "Unix time in milliseconds."
    },
    "activatedAt": {
      "type": [
        "integer",
        "null"
      ]
    },
    "expiresAt": {
      "type": [
        "integer",
        "null"
      ]
    },
    "note": {
      "type": [
        "string",
        "null"
      ]
    },
    "senderLabel": {
      "type": [
        "string",
        "null"
      ],
      "description": "The sender name that the claim page shows."
    },
    "message": {
      "type": [
        "string",
        "null"
      ],
      "description": "The note that the claim page shows."
    },
    "gift": {
      "type": "boolean",
      "description": "true means that the key has a sender name or a message. The key is then a gift."
    },
    "cloudHours": {
      "type": [
        "integer",
        "null"
      ],
      "description": "The cloud credits that a Lynx Cloud key adds to the account that redeems it. One credit is one hour of play. null means that the key is a mod key.",
      "example": 720
    }
  }
}

MintedKey

MintedKey schema
FieldTypeDescription
keystring
claimUrlstring | null
View JSON schema
{
  "type": "object",
  "properties": {
    "key": {
      "type": "string"
    },
    "claimUrl": {
      "type": [
        "string",
        "null"
      ]
    }
  }
}

Account

Account schema
FieldTypeDescription
idstring
uidinteger
usernamestring | null
rolestring
keyPrefixstring | null

The four letters at the start of the keys you make. It is null if you do not have one.

View JSON schema
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "uid": {
      "type": "integer"
    },
    "username": {
      "type": [
        "string",
        "null"
      ]
    },
    "role": {
      "type": "string"
    },
    "keyPrefix": {
      "type": [
        "string",
        "null"
      ],
      "description": "The four letters at the start of the keys you make. It is null if you do not have one."
    }
  }
}

Balance

Balance schema
FieldTypeDescription
balanceCentsinteger

Your reseller credits, in cents (1 credit is 10 cents). Below zero is debt.

availableCentsinteger

What you can spend now, in cents.

debtCentsinteger

What you owe, in cents. A top-up repays it first.

balanceCreditsinteger

Your reseller credits. Below zero is debt.

currencystring

USD for new financial operations; historical records retain their original currency.

Example: "usd"

View JSON schema
{
  "type": "object",
  "properties": {
    "balanceCents": {
      "type": "integer",
      "description": "Your reseller credits, in cents (1 credit is 10 cents). Below zero is debt."
    },
    "availableCents": {
      "type": "integer",
      "description": "What you can spend now, in cents."
    },
    "debtCents": {
      "type": "integer",
      "description": "What you owe, in cents. A top-up repays it first."
    },
    "balanceCredits": {
      "type": "integer",
      "description": "Your reseller credits. Below zero is debt."
    },
    "currency": {
      "type": "string",
      "example": "usd",
      "description": "USD for new financial operations; historical records retain their original currency."
    }
  }
}

Package

Package schema
FieldTypeDescription
productIdstring
kindstring

A mobile entry sells mobile mod keys. A pc entry sells PC mod keys.

One of: mobilepc

namestring
slugstring
iconUrlstring | null

The URL of the package icon. null means that the package has no icon.

platformsstring[]

The platforms of the plans.

plansobject[]
plans[].priceIdstring
plans[].namestring
plans[].platformstring

One of: iosandroiddesktop

plans[].durationDaysinteger

How many days the license runs.

plans[].currencystring
plans[].customerPriceCentsinteger

The price a customer pays on the storefront, in cents.

plans[].yourPriceCentsinteger

Your cost for this plan, in cents. Sell above it to make a margin.

plans[].customerPriceCreditsinteger

The storefront price, in credits.

plans[].yourPriceCreditsinteger

Your cost, in credits.

plans[].discountBpsinteger

Your discount below the customer price, in basis points.

View JSON schema
{
  "type": "object",
  "properties": {
    "productId": {
      "type": "string"
    },
    "kind": {
      "type": "string",
      "enum": [
        "mobile",
        "pc"
      ],
      "description": "A `mobile` entry sells mobile mod keys. A `pc` entry sells PC mod keys."
    },
    "name": {
      "type": "string"
    },
    "slug": {
      "type": "string"
    },
    "iconUrl": {
      "type": [
        "string",
        "null"
      ],
      "description": "The URL of the package icon. null means that the package has no icon."
    },
    "platforms": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "ios",
          "android",
          "desktop"
        ]
      },
      "description": "The platforms of the plans."
    },
    "plans": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "priceId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "platform": {
            "type": "string",
            "enum": [
              "ios",
              "android",
              "desktop"
            ]
          },
          "durationDays": {
            "type": "integer",
            "description": "How many days the license runs."
          },
          "currency": {
            "type": "string"
          },
          "customerPriceCents": {
            "type": "integer",
            "description": "The price a customer pays on the storefront, in cents."
          },
          "yourPriceCents": {
            "type": "integer",
            "description": "Your cost for this plan, in cents. Sell above it to make a margin."
          },
          "customerPriceCredits": {
            "type": "integer",
            "description": "The storefront price, in credits."
          },
          "yourPriceCredits": {
            "type": "integer",
            "description": "Your cost, in credits."
          },
          "discountBps": {
            "type": "integer",
            "description": "Your discount below the customer price, in basis points."
          }
        }
      }
    }
  }
}

Order

Order schema
FieldTypeDescription
idstring
kindstring
statusstring
providerstring
amountCentsinteger | null
amountCreditsinteger | null

The order total in credits. null for orders from before credits.

currencystring | null
quantityinteger | null

How many keys the order made. On an order that added Lynx Cloud seats, before cloud credits, how many seats it added.

batchIdstring | null

The batch of keys that the order made. null on an order that added Lynx Cloud seats.

productIdstring | null
priceIdstring | null
createdAtinteger
View JSON schema
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "kind": {
      "type": "string"
    },
    "status": {
      "type": "string"
    },
    "provider": {
      "type": "string"
    },
    "amountCents": {
      "type": [
        "integer",
        "null"
      ]
    },
    "amountCredits": {
      "type": [
        "integer",
        "null"
      ],
      "description": "The order total in credits. null for orders from before credits."
    },
    "currency": {
      "type": [
        "string",
        "null"
      ]
    },
    "quantity": {
      "type": [
        "integer",
        "null"
      ],
      "description": "How many keys the order made. On an order that added Lynx Cloud seats, before cloud credits, how many seats it added."
    },
    "batchId": {
      "type": [
        "string",
        "null"
      ],
      "description": "The batch of keys that the order made. null on an order that added Lynx Cloud seats."
    },
    "productId": {
      "type": [
        "string",
        "null"
      ]
    },
    "priceId": {
      "type": [
        "string",
        "null"
      ]
    },
    "createdAt": {
      "type": "integer"
    }
  }
}

KeyRefund

KeyRefund schema
FieldTypeDescription
keystring
refundedCentsinteger

The amount that the server returned to your balance, in cents.

refundedCreditsinteger

The amount that the server returned to your balance, in credits.

balanceAfterCentsinteger

Your balance after the refund, in cents.

balanceAfterCreditsinteger

Your balance after the refund, in credits.

alreadyRefundedboolean

true means that the server refunded this key before. It did not pay you again.

View JSON schema
{
  "type": "object",
  "properties": {
    "key": {
      "type": "string"
    },
    "refundedCents": {
      "type": "integer",
      "description": "The amount that the server returned to your balance, in cents."
    },
    "refundedCredits": {
      "type": "integer",
      "description": "The amount that the server returned to your balance, in credits."
    },
    "balanceAfterCents": {
      "type": "integer",
      "description": "Your balance after the refund, in cents."
    },
    "balanceAfterCredits": {
      "type": "integer",
      "description": "Your balance after the refund, in credits."
    },
    "alreadyRefunded": {
      "type": "boolean",
      "description": "true means that the server refunded this key before. It did not pay you again."
    }
  }
}

KeyGift

KeyGift schema
FieldTypeDescription
keystring
giftboolean

true means that the key has a sender name or a message.

senderLabelstring | null
messagestring | null
claimUrlstring | null

Give this link to the customer in place of the raw key.

View JSON schema
{
  "type": "object",
  "properties": {
    "key": {
      "type": "string"
    },
    "gift": {
      "type": "boolean",
      "description": "true means that the key has a sender name or a message."
    },
    "senderLabel": {
      "type": [
        "string",
        "null"
      ]
    },
    "message": {
      "type": [
        "string",
        "null"
      ]
    },
    "claimUrl": {
      "type": [
        "string",
        "null"
      ],
      "description": "Give this link to the customer in place of the raw key."
    }
  }
}