Frameworkist API 🖍️ 🧑‍💻 API serios OpenAPI JSON
⚑ click pe steag

Chappa POS API (for React devs)

v2.0.0-but-with-pictures

The exact same API. Now with rounded corners, bigger fonts, and fewer scary words.

🐱 Două blocuri. Le tragi cu mouse-ul. Nimic nu se re-randează. Promit.
Bloc Scratch
🔑
Stickerul tău secret: pune-l într-un header numit X-API-Token.
Your venue token. Goes in a header. Looking at the menu doesn't need it; ordering does.

Hi 👋

This is the whole API. Two blocks. You send JSON, you get JSON back. Nothing re-renders. There is no useEffect. Nobody gets hydrated.

If you can write fetch(), you can use this. If you can't write fetch() yet — that's fine, a renderer is on the way that draws this whole thing as little colored blocks you drag around. Like Scratch. Like when you were eight and actually shipped something.

The two things you can do

That's the entire framework. Sorry — API. Force of habit.

Logging in

Put your token in a header called X-API-Token. A header. The part that isn't the body. You've met them — they live in the Network tab, between npm installs.

Looking at the menu is public: no token needed. You only need the token to actually order, because ordering does something real in the real world.

What you get back

Everything looks like this:

{ "v": 2, "status": 0, "data": { ...the good stuff... } }

status is 0 when it worked and 1 when it didn't. When it's 1 we put what went wrong in error.msg, in actual human sentences. No stack-trace archaeology. You're welcome.

Rate limiting

There is one. You won't reach it.

🧩 Blocurile tale (trage-le cu mouse-ul)
📖 when I want the menu
Look ✨ you can do this 🎉 public, fără sticker POST /api/v2/client/getinfo
🐱 „give me the venue. all of it. one request.”

Ask for the parts of the venue you want — all at once, in one request. One. Not one request per component. Not one per useQuery. One.

List what you want inside query. Want the menu and the categories? Send { "query": { "items": {}, "categories": {} } }. Each thing you ask for comes back in data under the same name.

Things you can ask for: info (the venue), categories, items (the menu), tables, zones, events. Use {} as the value — they're useful with no options at all.

No loading spinner required. We know you'll add three anyway.

Ce trimiți 👇 (se prind ca bulinuțe)
Give me the venue, its categories, and the menu
venue3query{info: {}, categories: {}, items: {}}
Honestly I just want the food list
venue3query{items: {}}
⬇️
Ce primești înapoi
{
    "v": 2,
    "status": 0,
    "data": {
        "info": {
            "name": "Demo Bistro"
        },
        "categories": [
            {
                "id": 1,
                "name": "Burgers"
            }
        ],
        "items": [
            {
                "id": 220,
                "name": "Classic Burger",
                "price": 32
            }
        ]
    },
    "meta": []
}
🍔 order food for table ( )
Do ✨ still fine, breathe 🔑 are nevoie de X-API-Token POST /api/v2/client/order
🐱 „table plus a list of things. food appears. magic.”

Send a table and a list of items. Each item is { "item": <product id>, "count": <how many> }. Add "notes" if the customer is particular.

The kitchen finds out immediately. You don't wire up a single websocket — we already did that part, in C++, while you were picking a state library.

Bonus, because we both know your users double-tap buttons: add any number as idempotency_key and retry as much as you like. Same number = same order, no duplicates. It's that easy, and no, you don't need a reducer for it.

Ce trimiți 👇 (se prind ca bulinuțe)
Two burgers, one with no onions
table11items[{item: 220, count: 2}, {item: 104, count: 1, notes: "no onions"}]
Same thing, but safe to retry forever
table11idempotency_key7items[{item: 220, count: 1}]
⬇️
Ce primești înapoi
{
    "v": 2,
    "status": 0,
    "data": {
        "placed": true,
        "id_sep": 1
    },
    "meta": []
}
🙈când ceva merge prost
🐱 „nu intri în panică — îți spunem în propoziții, nu în stack trace.”
{
    "v": 2,
    "status": 1,
    "error": {
        "code": "INVALID_ITEM",
        "msg": "Format invalid pentru produs sau cantitate."
    }
}
📦 Piesele din care sunt făcute blocurile
🧱 MenuRequest
Ask for the parts of the venue you want.
venue integer
query * object
🧱 OrderRequest
A table, and the things on it.
table * integer
items * array
id_sep integer
idempotency_key integer
🧱 OrderItem
item * integer
count * integer
notes string
🧱 Ok
It worked.
v * integer
status * integer
data * object
meta object
🧱 Oops
It didn't work, and here's why.
v * integer
status * integer
error * object

🍔 Asta e tot framework-ul. Pardon — API-ul. Forța obișnuinței.

🧑‍💻 Du-mă la versiunea serioasă  ·  📄 OpenAPI JSON