Nunua Pro Developers
Getting started

Quickstart

Five calls against your sandbox: send products, update stock, receive a simulated order and acknowledge it. Allow ten minutes.

Before you start

  • A partner key (npv_live_…). If you don't have one, create a developer account: it takes two minutes. You can also create the sandbox there with one click and skip step 1.
  • curl, or any HTTP client. Samples in JavaScript, Python and PHP follow in syncing the catalogue.

The sandbox is a hidden shop that customers never see. Use it exactly like a real shop.

Terminal
export NUNUA_PARTNER_KEY=npv_live_...

Run it

quickstart.sh
# 1. Make your sandbox (partner key). The test key is shown once, so save it.
curl -s -X POST https://nunuapro.app/api/pos-partner/v1/sandbox \
  -H "Authorization: Bearer $NUNUA_PARTNER_KEY"
export NUNUA_KEY=npk_test_...        # the api_key from the response

BASE=https://nunuapro.app/api/pos/v1

# 2. Send two products.
curl -s -X POST $BASE/products/batch -H "Authorization: Bearer $NUNUA_KEY" -H "Content-Type: application/json" -d '{
  "products": [
    {"external_id": "SKU-1", "name": "SUKARI KILOMBERO 1KG", "barcode": "6001068705504", "price": 3500, "stock_qty": 40},
    {"external_id": "SKU-2", "name": "COLGATE TOTAL 100G",   "price": 4200, "stock_qty": 12}
  ]
}'

# 3. A sale happened in the shop: update stock and price.
curl -s -X PATCH $BASE/inventory -H "Authorization: Bearer $NUNUA_KEY" -H "Content-Type: application/json" -d '{
  "items": [{"external_id": "SKU-1", "stock_qty": 39, "updated_at": "2026-11-03T10:15:00+03:00"}]
}'

# 4. Pretend a customer ordered, then read the change feed.
curl -s -X POST $BASE/sandbox/orders -H "Authorization: Bearer $NUNUA_KEY"
curl -s "$BASE/events?after=0" -H "Authorization: Bearer $NUNUA_KEY"

# 5. Record the sale in your POS, then acknowledge (send new stock quantities BEFORE this).
curl -s -X POST $BASE/orders/123/ack -H "Authorization: Bearer $NUNUA_KEY" -H "Content-Type: application/json" \
  -d '{"status": "accepted", "pos_ref": "SALE-8841"}'

What each step did

  1. Made your sandboxPOST /pos-partner/v1/sandbox creates your test shop and returns its npk_test_… key once. Call it again with {"rotate": true} for a new key.
  2. Sent two productsPOST /pos/v1/products/batch upserts up to 200 products and answers 200 with a result for each. One bad row never fails the batch.
  3. Updated stockPATCH /pos/v1/inventory is the call you'll make most: price, stock or availability for up to 500 products or variations.
  4. Simulated an orderPOST /pos/v1/sandbox/orders pretends a customer placed and confirmed an order (pass {"type":"delivery"}, or leave it as the default pickup). GET /pos/v1/events is where your POS sees it.
  5. Acknowledged itPOST /pos/v1/orders/{id}/ack tells us you recorded the sale. Then try POST /pos/v1/sandbox/orders/{id}/cancel to see the cancellation your POS must also handle.

Reading a batch result

Every product you send gets its own result. It tells you everything you need.

Response
{
  "results": [
    { "external_id": "SKU-1", "status": "created", "product_id": 48213,
      "listed": false, "catalog": "linked", "errors": [] },
    { "external_id": "SKU-2", "status": "rejected",
      "errors": ["The price field must not be greater than 100000000."] }
  ]
}
FieldMeans
statuscreated, updated, stale (older than what we hold, so ignored), archived or rejected.
listedWhether customers can see it yet. New imports start hidden until the owner approves them.
cataloglinked (matched our shared catalogue by barcode), suggested (a likely match the owner confirms) or none.
renamed_toPresent when another product already had this name: we kept both, naming this one "Name (SKU)".
warnings, errorsHuman-readable reasons. Log rejected rows and fix the cause in your data.

Next: link a real shop with a code, then load its whole catalogue with a snapshot.