Open the panel

How Requests Work PRO ​

Everything here applies to every route.

The basics ​

Every address starts with:

https://api.fastyvendor.com/api/v1
WhatHow it works
FormatJSON in UTF-8, with snake_case field names. Send Content-Type: application/json with a body.
PricesWhole L$, as numbers: 299, never "299" or 299.00.
DatesISO 8601 in UTC: 2026-11-04T18:02:55.895Z. A date with no value is null.
AvatarsTheir UUID (the key), like a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d.
IdsText with a prefix: prd_… for products, grp_… for groups, vd_… for vendors. Sales and gift cards use a UUID. Keep them as text.
New fieldsWe add fields, but never rename or remove them. Ignore the ones you don't know.

Finding a product id

Search by name with GET /products?q=Riot and read id in the answer.

Long lists ​

Lists come in pages, with the next page's address in next_cursor:

json
{
  "items": [ { "id": "prd_mxbjm9xtpchmet", "name": "Riot Boots" } ],
  "next_cursor": "p:1791315729083183~prd_3catv3h84c677g"
}

Pass it back as ?cursor= for the next page. null means you've reached the end. Choose the page size with ?limit=: the default is 50 and the maximum is 200.

js
const BASE = 'https://api.fastyvendor.com/api/v1'
const headers = { Authorization: `Bearer ${process.env.FASTY_KEY}` }

async function allProducts() {
  const all = []
  let cursor = null
  do {
    const url = new URL(`${BASE}/products`)
    url.searchParams.set('limit', '200')
    if (cursor) url.searchParams.set('cursor', cursor)
    const page = await (await fetch(url, { headers })).json()
    all.push(...page.items)
    cursor = page.next_cursor
  } while (cursor)
  return all
}
python
import os, requests

BASE = "https://api.fastyvendor.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['FASTY_KEY']}"}

def all_products():
    items, cursor = [], None
    while True:
        params = {"limit": 200}
        if cursor:
            params["cursor"] = cursor
        page = requests.get(f"{BASE}/products", params=params, headers=HEADERS).json()
        items += page["items"]
        cursor = page["next_cursor"]
        if not cursor:
            return items

A cursor is only for the same list with the same filters. Treat it as text: don't try to read or build one.

Changing things ​

PATCH changes only the fields you send. Everything else stays as it is:

bash
curl -X PATCH "https://api.fastyvendor.com/api/v1/products/prd_mxbjm9xtpchmet" \
  -H "Authorization: Bearer $FASTY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"price": 250}'

The answer is the whole object, already changed. A field the route doesn't know is refused with 400 BAD_REQUEST, so a typo never passes silently.

Vendors pick up changes by themselves, usually within seconds.

Your tool can't send PATCH? Send a POST with the header X-HTTP-Method-Override: PATCH.

Safe retries ​

Say your script sends 10 points and the connection drops. Did Fasty get it? If you send again, the player could get 20.

The Idempotency-Key header solves this. Send any unique text with a POST and use the same text when you retry: Fasty does it once and gives you the first answer again.

bash
curl -X POST "https://api.fastyvendor.com/api/v1/customers/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/points" \
  -H "Authorization: Bearer $FASTY_KEY" \
  -H "Idempotency-Key: round-42-a1b2c3d4" \
  -H "Content-Type: application/json" \
  -d '{"delta": 10, "note": "Won round 42"}'
js
await fetch(`${BASE}/customers/${avatarKey}/points`, {
  method: 'POST',
  headers: {
    ...headers,
    'Content-Type': 'application/json',
    'Idempotency-Key': `round-${round}-${avatarKey}`,
  },
  body: JSON.stringify({ delta: 10, note: `Won round ${round}` }),
})
python
requests.post(
    f"{BASE}/customers/{avatar_key}/points",
    headers={**HEADERS, "Idempotency-Key": f"round-{round_id}-{avatar_key}"},
    json={"delta": 10, "note": f"Won round {round_id}"},
)
lsl
llHTTPRequest(API + "/customers/" + (string)winner + "/points",
    [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/json",
     HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + KEY,
     HTTP_CUSTOM_HEADER, "Idempotency-Key", "round-" + (string)round + "-" + (string)winner],
    "{\"delta\":10,\"note\":\"Won a round\"}");
  • Make the key mean the action, like round-42-<avatar>. A random value made fresh on each attempt protects nothing.
  • Fasty remembers a key for 24 hours, and up to 255 characters of it.
  • The same key with a different body is refused with 409 IDEMPOTENCY_MISMATCH, because it is probably a bug.
  • A failed attempt with a 5xx or 429 doesn't count, so you can retry with the same key.

Always use it to give points, gift cards and deliveries.

From a browser ​

The API doesn't answer JavaScript running in a web page, on purpose: anyone could read your key in the page source. Call it from your server, and let your page talk to your server.