Skip to main content
Selling an app, a plugin or a desktop tool? Turn on License keys for the product and every sale gets its own key. The buyer sees it in their purchase receipt and in My purchases (with a copy button), you see it on the order, and your software checks it against three public endpoints — no API key ships inside your app.
1

Turn it on

In the product editor, open License keys, switch on Generate a license key for each sale and, optionally, set an activation limit (leave it blank for unlimited).
2

Sell

Each new sale of the product gets one key, like 7KQ2M-X9D4R-T3VWB-8HNPC. It is in the buyer’s receipt email, in their purchases, on the order in your dashboard and in the order.completed webhook.
3

Check it from your app

Call POST /licenses/activate when the user enters the key, and POST /licenses/validate on launch.
License keys are for one-time products. Keys are issued for sales made after you turn the setting on. A refunded or disputed order’s key stops validating automatically.

How keys work

  • Format. Four groups of five characters (XXXXX-XXXXX-XXXXX-XXXXX) drawn from a cryptographically secure random source — 100 bits, so keys can’t be guessed. Input is forgiving: case, spaces and dashes are ignored, and O is read as 0, I/L as 1.
  • One key per order. Payment retries never create a second key.
  • Activations. An activation is one install or device, identified by an instanceId you choose (or one we generate). The activation limit you set on the product is copied onto each key when it is issued, so changing the product later never takes seats away from buyers who already paid.
  • Product-bound. Every call needs the product id and the key. A key of another product gets the same 404 as a key that doesn’t exist.

Public endpoints (called from your software)

Base URL https://api.pocketsflow.com. No Authorization header. JSON body: snake_case spellings (product_id, license_key, instance_id, instance_name) are accepted too. The same routes also answer under /v1/licenses/.... Every answer has the same shape — read valid, and code when it is false:
All three return 400 invalid_request without productId or licenseKey, and 429 (code: rate_limited) past 60 requests per minute per IP. They answer any origin, so a web app can call them from the browser.
Cache the last successful validation and allow a grace period offline — a network error on launch shouldn’t lock a paying customer out.

Managing keys (your API key)

These need your API key (Authorization: Bearer pk_live_… / pk_test_…) and only ever touch your own keys in that key’s mode. The same actions are on the order page in your dashboard (Orders → an order → License key), and as MCP tools (list_license_keys, get_license_key, disable_license_key, enable_license_key, reset_license_key_activations).

Refunds and disputes

When an order is refunded or disputed, its key is disabled with the reason (refunded / disputed), so validate answers valid: false with code: license_disabled and activate answers 403. The buyer’s purchases no longer show the key. You can still re-enable it from the order page. Per-seat subscriptions can issue one key per subscriber (see usage-based and per-seat pricing). That key is disabled with the reason subscription_ended while the subscription is canceled or expired, and switched back on automatically if it resumes.

Webhooks

order.completed for a product with license keys carries the key:
See Webhook events.