anyshop docs homeStatusOpen the dashboard

Get startedQuickstart

Sell your first key
with the API.

Create a product, give it keys, put it on sale, and have your server told the moment someone pays. Everything here runs in test mode: the checkout uses a simulated payment and no money moves.

  • 7 steps
  • curl, Node or Python
  • A public https server for the webhook

Step 1: Make two API keys

In the dashboard, open Developers, API keys. Make a live key with products:write (a live key asks for your two-factor code, and needs a reviewed store), then a test key with stock:write and webhooks:write. Each key is shown once; keep them in your server's environment, never in a browser or an app.

.env
ANYSHOP_LIVE_KEY=as_live_7Fq2...Q7pX
ANYSHOP_TEST_KEY=as_test_M4c9...b2Rt

Step 2: Create the productlive key

A product starts as a draft. Its price is an integer in minor units of your store's currency: 1999 is $19.99. Send an Idempotency-Key so a retry after a timeout never makes two products.

curl https://api.anyshop.io/v1/products \
  -H "Authorization: Bearer $ANYSHOP_LIVE_KEY" \
  -H "Idempotency-Key: first-product-1" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Lumen Studio Pro",
    "type": "serial",
    "category": "software_licenses",
    "price": 1999,
    "platform": "Windows and macOS",
    "delivery_instructions": "In Lumen Studio Pro, choose Help, Enter license key, and paste this key."
  }'
200Response, shortened
{
  "object": "product",
  "id": "prod_01m3rr5kmbeb2s18x1kpntjxqb",
  "slug": "lumen-studio-pro",
  "status": "draft",
  "currency": "USD",
  "variants": [
    { "id": "var_01m3rr5kmd6h0q2t8w4y9zb7ce", "name": "Standard", "price": 1999 }
  ],
  "published_at": null
}

Step 3: Add test keys to its stocktest key

Keys go into the stock of the mode your API key is in, so these are test keys: only test checkouts can sell them. Duplicates within the upload and keys already in stock are left out and counted, never added twice.

curl \
  https://api.anyshop.io/v1/products/prod_01m3rr5kmbeb2s18x1kpntjxqb/stock_items \
  -H "Authorization: Bearer $ANYSHOP_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "keys": ["TEST1-K2LM-3F9Q", "TEST2-P8WN-4H7R", "TEST2-P8WN-4H7R"] }'
200Response
{
  "object": "stock_upload",
  "product": "prod_01m3rr5kmbeb2s18x1kpntjxqb",
  "livemode": false,
  "submitted": 3,
  "added": 2,
  "repeated_in_upload": 1,
  "already_in_stock": 0
}

Step 4: Put it on salelive key

Publishing makes the product active. A serial key product can go on sale with no stock in a mode; it shows as sold out there until keys arrive.

curl -X POST \
  https://api.anyshop.io/v1/products/prod_01m3rr5kmbeb2s18x1kpntjxqb/publish \
  -H "Authorization: Bearer $ANYSHOP_LIVE_KEY"

Step 5: Tell anyshop where to send eventstest key

Add a webhook endpoint for order.paid. It must be a public https address; anyshop never follows redirects or calls private networks. The answer holds the signing secret, shown this once.

curl https://api.anyshop.io/v1/webhook_endpoints \
  -H "Authorization: Bearer $ANYSHOP_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://api.pixelforge-supply.com/anyshop",
        "events": ["order.paid"] }'
200Response, shortened
{
  "object": "webhook_endpoint",
  "id": "whe_01m3rs9d2f4k6m8p0r2t4v6x8z",
  "livemode": false,
  "signing": "hmac",
  "status": "enabled",
  "secret": {
    "object": "webhook_secret",
    "algorithm": "hmac",
    "value": "whsec_Q3s9mV1...kP4="
  }
}

Step 6: Verify, then act

Events are signed with Standard Webhooks, so any Standard Webhooks library checks them. Verify against the raw body, answer with a 2xx quickly, and do the slow work after. The same event can arrive twice: use its webhook-id header to do the work once.

server.js
import express from "express";
import { Webhook } from "standardwebhooks";

const webhook = new Webhook(process.env.ANYSHOP_WEBHOOK_SECRET); // whsec_...
const app = express();

app.post("/anyshop", express.raw({ type: "application/json" }), (req, res) => {
  let event;
  try {
    event = webhook.verify(req.body, req.headers);
  } catch {
    return res.sendStatus(400);
  }
  if (event.type === "order.paid") {
    // yours: do it once per req.headers["webhook-id"]
    grantAccess(event.data.buyer.email, event.data.items);
  }
  res.sendStatus(204);
});

app.listen(3000);

Step 7: Buy it yourself

On the dashboard home, choose Buy it yourself (once you have made a test purchase, the button leaves the home page: open app.anyshop.io/test-purchase instead). It opens a test checkout for your newest product; pay with the simulated rail's Succeeds. The key is delivered on the spot, and your server gets this:

POST /anyshop
{
  "type": "order.paid",
  "timestamp": "2026-10-02T14:32:05.112Z",
  "data": {
    "object": "order",
    "id": "ord_01m3rt5x2c7q9f0a4d6k8h1n3p",
    "number": 1001,
    "livemode": false,
    "status": "paid",
    "currency": "USD",
    "total": 1999,
    "buyer": { "email": "you@pixelforge.dev" },
    "paid_with": "simulated",
    "items": [
      {
        "product": { "id": "prod_01m3rr5kmbeb2s18x1kpntjxqb", "name": "Lumen Studio Pro" },
        "quantity": 1,
        "unit_amount": 1999
      }
    ]
  }
}