Skip to content
Lynx API reference
OpenAPIGet an API key
OverviewAuthenticationScopesErrors
AccountGET/meGET/balanceGET/openapi.json
CatalogGET/products
KeysGET/keysPOST/keysGET/keys/{key}
OrdersGET/orders
Schemas
Reference contents
OverviewAuthenticationScopesErrorsSchemasGET/meGET/balanceGET/productsGET/keysPOST/keysGET/keys/{key}GET/ordersGET/openapi.json

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. 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 and your credit limit
catalog:read Read packages, plans, your prices, and customer prices
keys:read List and read the keys in your inventory
keys:write Generate keys
orders:read Read your purchase history

Money and idempotency

POST /api/v1/keys charges your balance.

The endpoint is idempotent on the idempotencyKey field. If you send the same value again, the server charges you one time. The response holds the same keys and alreadyMinted: true.

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.

Claim links

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. You can change both later in the dashboard.

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

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. The availableCents field already includes your credit limit. A purchase succeeds if its total is at or below that number.

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

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.

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.

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

senderLabel and message control what the customer sees on the claim page. Both are optional. You can change both later in the dashboard.

Authentication: Authorization: Bearer <API key>

Request body required

application/json

Generate keys request body
FieldTypeDescription
priceIdrequiredstring

Take this value from GET /products.

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": [
    "priceId",
    "quantity",
    "idempotencyKey"
  ],
  "properties": {
    "priceId": {
      "type": "string",
      "description": "Take this value from `GET /products`."
    },
    "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
batchIdstring
quantityinteger
unitCostCentsinteger

The cost of one key, in cents.

totalCentsinteger

The cost of the batch, in cents.

balanceAfterCentsinteger | null

Your balance after the charge, in cents.

alreadyMintedboolean

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

keysMintedKey[]
View JSON schema
{
  "type": "object",
  "properties": {
    "orderId": {
      "type": "string"
    },
    "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",
        "null"
      ],
      "description": "Your balance after the charge, in cents."
    },
    "alreadyMinted": {
      "type": "boolean",
      "description": "true means that this idempotencyKey was already used. The server did not charge you again."
    },
    "keys": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/MintedKey"
      }
    }
  }
}
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"
}
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"
}

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.

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://m.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.

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.

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
messagestring | null
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://m.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"
          ]
        },
        {
          "type": "null"
        }
      ],
      "description": "null means that the key works on each platform of the package."
    },
    "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."
    },
    "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"
      ]
    },
    "message": {
      "type": [
        "string",
        "null"
      ]
    }
  }
}

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.

groupobject | null
group.namestring
group.discountBpsinteger

Your discount in basis points. 4000 means 40 percent below the customer price.

group.perPlanPricingboolean

true means that your group sets its own price for some plans. The group discount is then not the full picture. Read /products for the real numbers.

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."
    },
    "group": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "name": {
          "type": "string"
        },
        "discountBps": {
          "type": "integer",
          "description": "Your discount in basis points. 4000 means 40 percent below the customer price."
        },
        "perPlanPricing": {
          "type": "boolean",
          "description": "true means that your group sets its own price for some plans. The group discount is then not the full picture. Read /products for the real numbers."
        }
      }
    }
  }
}

Balance

Balance schema
FieldTypeDescription
balanceCentsinteger

Your cash balance, in cents.

creditLimitCentsinteger

How far below zero you can go, in cents.

availableCentsinteger

The sum of balanceCents and creditLimitCents. This is what you can spend now.

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 cash balance, in cents."
    },
    "creditLimitCents": {
      "type": "integer",
      "description": "How far below zero you can go, in cents."
    },
    "availableCents": {
      "type": "integer",
      "description": "The sum of balanceCents and creditLimitCents. This is what you can spend now."
    },
    "currency": {
      "type": "string",
      "example": "usd",
      "description": "USD for new financial operations; historical records retain their original currency."
    }
  }
}

Package

Package schema
FieldTypeDescription
productIdstring
namestring
slugstring
platformsstring[]
plansobject[]
plans[].priceIdstring
plans[].namestring
plans[].platformstring

One of: iosandroid

plans[].durationDaysinteger
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[].discountBpsinteger

Your discount below the customer price, in basis points.

View JSON schema
{
  "type": "object",
  "properties": {
    "productId": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "slug": {
      "type": "string"
    },
    "platforms": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "ios",
          "android"
        ]
      }
    },
    "plans": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "priceId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "platform": {
            "type": "string",
            "enum": [
              "ios",
              "android"
            ]
          },
          "durationDays": {
            "type": "integer"
          },
          "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."
          },
          "discountBps": {
            "type": "integer",
            "description": "Your discount below the customer price, in basis points."
          }
        }
      }
    }
  }
}

Order

Order schema
FieldTypeDescription
idstring
kindstring
statusstring
providerstring
amountCentsinteger | null
currencystring | null
quantityinteger | null
batchIdstring | null
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"
      ]
    },
    "currency": {
      "type": [
        "string",
        "null"
      ]
    },
    "quantity": {
      "type": [
        "integer",
        "null"
      ]
    },
    "batchId": {
      "type": [
        "string",
        "null"
      ]
    },
    "productId": {
      "type": [
        "string",
        "null"
      ]
    },
    "priceId": {
      "type": [
        "string",
        "null"
      ]
    },
    "createdAt": {
      "type": "integer"
    }
  }
}
Back to the reference