Fiddo GlowDevelopers
Partner portal

Reseller API · v1

Build on Fiddo Glow

Show our products on your own shop, send your customers’ orders automatically and get notified at every step. Orders are paid from your wallet and delivered in your shop’s name.

Getting started

  1. Become an approved reseller at reseller.fiddoglow.com and top up your wallet.
  2. In the portal open Developers and create an API key.
  3. Call the API from your server. All requests and responses are JSON; money is in USD.

Base URL: https://api.fiddoglow.com/api/v1

Authentication

Send your key in the Authorization header. Keep it on your server — never put it in a web page or mobile app.

curl

curl https://api.fiddoglow.com/api/v1/me \
  -H "Authorization: Bearer fg_live_xxxxxxxxxxxxxxxxxxxx"

Response

{ "shop_name": "Hodan Beauty", "level": "Gold", "discount_percent": 20, "balance": 150.00, "currency": "USD" }

Products

Every active product with your price and live stock. Use it to fill and sync your shop.

GET/products?q=&page=1&limit=100

Response

{
  "data": [
    {
      "id": "cm1x…", "sku": "CJ-STR-118", "name": "Color Juice — Strawberry",
      "brand": "Fiddo Glow", "category": "Hair colour", "group": "Color Juice", "variant": "Strawberry",
      "image": "https://api.fiddoglow.com/uploads/…jpg",
      "in_stock": 42, "retail_price": 12.00, "your_price": 9.60
    }
  ],
  "page": 1, "limit": 100, "total": 85, "has_more": false
}

GET/products/{id or sku}

GET/delivery

Delivery prices per city (the fee is added to every order).

Price check

Calculates an order without placing it — handy to show the total and check your balance first.

POST/quote

Body

{ "city": "Mogadishu", "items": [ { "sku": "CJ-STR-118", "quantity": 2 } ] }

Response

{ "items": [...], "subtotal": 19.20, "delivery_fee": 2.00, "total": 21.20, "balance": 150.00, "enough_balance": true }

Create an order

Places the order for your customer and pays it from your wallet straight away. You get back the order with a 6-digit delivery_code — send it to your customer; our rider asks for it on hand-over.

POST/orders

referencestringYour own order number. Recommended — sending the same reference again returns the existing order instead of a duplicate (safe retries). You can also use an Idempotency-Key header.
customer.namestringCustomer’s name *
customer.phonestringCustomer’s phone *
customer.citystringCity * (see /delivery)
customer.districtstringDistrict
customer.addressstringAddress / landmark *
items[]array{ product_id | sku, quantity } — up to 100 lines *
notesstringDelivery notes

curl

curl -X POST https://api.fiddoglow.com/api/v1/orders \
  -H "Authorization: Bearer $FG_KEY" -H "Content-Type: application/json" \
  -d '{
    "reference": "SHOP-1042",
    "customer": { "name": "Amina Ali", "phone": "0617778888", "city": "Mogadishu", "address": "Hodan, near KM4" },
    "items": [ { "sku": "CJ-STR-118", "quantity": 2 } ]
  }'

201 Created

{
  "data": {
    "order_number": "FG-261012-A1B2C3", "reference": "SHOP-1042",
    "status": "confirmed", "payment_status": "paid",
    "customer": { "name": "Amina Ali", "phone": "0617778888", "city": "Mogadishu", "district": null, "address": "Hodan, near KM4" },
    "items": [ { "product_id": "cm1x…", "sku": "CJ-STR-118", "name": "Color Juice — Strawberry", "quantity": 2, "unit_price": 9.60, "total": 19.20 } ],
    "subtotal": 19.20, "delivery_fee": 2.00, "total": 21.20, "currency": "USD",
    "delivery_code": "482913", "tracking_code": null,
    "history": [ { "status": "pending", "note": "Order placed by reseller Hodan Beauty", "at": "…" }, { "status": "confirmed", "note": "…", "at": "…" } ],
    "created_at": "…", "updated_at": "…", "delivered_at": null
  },
  "replayed": false
}

If your wallet does not cover the total you get a 400 error and nothing is charged.

List & get orders

GET/orders?status=delivered&updated_since=2026-10-01&page=1&limit=50

GET/orders/{order_number or your reference}

Cancel an order

Possible while the order is still pending or confirmed (before we start preparing it). The full amount goes back to your wallet.

POST/orders/{order_number or reference}/cancel

Body (optional)

{ "reason": "Customer changed their mind" }

Wallet

GET/wallet

Response

{ "balance": 128.80, "currency": "USD", "transactions": [ { "type": "order", "amount": -21.20, "balance_after": 128.80, "reference": "FG-261012-A1B2C3", "note": "Order for Amina Ali", "at": "…" } ] }

Top-ups are done in the reseller portal (EVC Plus, ZAAD, Sahal, bank or cash).

Order statuses

  • confirmed

    Paid from your wallet, waiting to be prepared

  • processing

    Being packed

  • shipped

    Left our store

  • out_for_delivery

    With the rider

  • delivered

    Handed over with the delivery code

  • cancelled

    Cancelled — money back in your wallet

  • returned

    Came back — money back in your wallet

Webhooks

Add your URL in Developers. We POST JSON to it for these events, and retry after 30 seconds and 5 minutes if your server does not answer with a 2xx:

  • order.created · order.status_changed — data.order is the order object above
  • wallet.topup_confirmed — data.topup and the new data.balance
  • ping — the “Send test” button

Request we send

POST https://myshop.com/webhooks/fiddoglow
X-FG-Event: order.status_changed
X-FG-Delivery: evt_8f2c…
X-FG-Signature: t=1760180000,v1=5d41402abc4b2a76b9719d911017c592…

{ "id": "evt_8f2c…", "event": "order.status_changed", "created_at": "…", "data": { "order": { … } } }

Always verify the signature: HMAC-SHA256 of "<t>.<raw body>" with your signing secret, compared with v1. Reject requests older than 5 minutes.

Node.js (Express)

app.post('/webhooks/fiddoglow', express.raw({ type: 'application/json' }), (req, res) => {
  const [t, v1] = req.get('X-FG-Signature').split(',').map((p) => p.split('=')[1]);
  const expected = crypto.createHmac('sha256', process.env.FG_WEBHOOK_SECRET)
    .update(`${t}.${req.body}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
  if (!fresh || v1?.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) return res.sendStatus(400);
  const event = JSON.parse(req.body);
  // event.event === 'order.status_changed' → update your order using event.data.order.reference
  res.sendStatus(200);
});

PHP

$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_FG_SIGNATURE']), $sig);
$expected = hash_hmac('sha256', $sig['t'] . '.' . $body, getenv('FG_WEBHOOK_SECRET'));
if (abs(time() - (int)$sig['t']) > 300 || !hash_equals($expected, $sig['v1'])) { http_response_code(400); exit; }
$event = json_decode($body, true);
http_response_code(200);

Errors & limits

Errors return a normal HTTP status with a JSON body:

{ "error": "Not enough money in the wallet — please top up first" }
  • 400 invalid data, not enough stock or balance · 401 missing / wrong key · 403 account paused · 404 not found · 429 too many requests
  • Limit: 120 requests per minute per key, 300 new orders per hour. See the RateLimit-Remaining and Retry-After headers.

Questions? WhatsApp us on 0610218518.