تاجر جني
Which API?
Merchant API For merchants: manage your own catalogue, orders and finances through the v2 Third-Party API. Application API For partner apps: browse Gini merchants and products, send customers to checkout and follow their orders.

New: Application API docs

Pick the API you are reading here — the Merchant API for your own store, the Application API for partner apps.

Merchant dashboard
API reference
Orders

API documentation

Everything you need to integrate with the Gini v2 Third-Party API.

Orders

List your orders, fetch a single order in full detail, and move an order through its lifecycle — every route is scoped to the calling signed merchant, so an integration only ever sees and mutates its own orders. Writes made through this API do not re-trigger the merchant's own outbound order webhook.

List orders

Returns the calling merchant's orders as a paginated collection, newest first. All query parameters are optional filters. List rows eager-load the customer, delivery address, and promo code only — order items and the influencer name are omitted from the list payload and appear on the single-order detail endpoint instead.

GET /api/v2.0/third-party/orders
Signed
Query parameters
Field Type Required Description
search string Optional Fuzzy match against the order number or numeric id (max 255 chars).
status string Optional Filter by order status. One of: pending, accepted, delivery_handoff, rejected, on_the_way, delivered, cancelled, refunded, returned, delayed, rwa, expired, temp_cancelled, received, in_warehouse.
date date Optional Filter by creation date (YYYY-MM-DD), matched against created_at.
payment_method string Optional Filter by payment method. One of: e_payment, aqsati, cash_on_delivery, qi_payment, ratibi, ishtrelk, post_paid, dots.
state integer Optional Filter by the state id of the delivery address frozen on the order.
product_slug string Optional Return only orders that contain an item whose product has this slug.
late_orders string Optional Set to 'enabled' to return only orders pending for more than 12 hours. Forces status to pending and overrides the status filter. Accepts enabled or disabled.
shipping_method string Optional Filter by shipping method. One of: free, delivery, pickup.
delivery_company integer Optional Filter by carrier id. 0 means self delivery and also matches orders with no carrier assigned yet, since a null carrier id is self delivery.
handoff string Optional handed (handed to the delivery company) or not_handed (still with the merchant).
pre_order string Optional only to return just pre-order orders, exclude to leave them out.
per_page integer Optional Results per page, 1-100. Defaults to 15.
Response
{
    "data": [
        {
            "id": 5021,
            "address": {
                "id": 812,
                "name": "Home",
                "contact_phone": "+9647701234567",
                "alt_contact_phone": null,
                "city": 1,
                "city_label": "Baghdad",
                "state": 14,
                "state_label": "Karrada",
                "address": "Building 5, Floor 2, Street 14",
                "latitude": "33.315000",
                "longitude": "44.366000",
                "created_at": "2026-02-10 18:22:41"
            },
            "customer": {
                "id": 318,
                "name": "Ahmed Ali",
                "phone": "+9647701234567",
                "email": "ahmed@example.com",
                "avatar": "https://cdn.gini.iq/avatars/318.jpg",
                "phone_verified_at": "2025-11-02T10:00:00.000000Z",
                "is_verified": 1,
                "is_active": 1
            },
            "is_pre_order": false,
            "total_amount": "67500.00",
            "promo_code": {
                "promo_code_id": null,
                "promo_code_created_by": "no promo code applied",
                "code": "none",
                "amount": "IQD 0",
                "raw_amount": null
            },
            "discount_total_amount": "0.00",
            "difference_amount": 67500,
            "final_amount": 67500,
            "shipping_cost": "5000.00",
            "total_amount_with_shipping_cost": 72500,
            "formatted_amounts": {
                "final_amount": "IQD 67,500",
                "total_amount": "IQD 67,500",
                "discount_total_amount": "IQD 0",
                "difference_amount": "IQD 67,500",
                "shipping_cost": "IQD 5,000",
                "total_amount_with_shipping_cost": "IQD 72,500",
                "promo_code_amount": "IQD 0",
                "total_after_promo_code": "IQD 67,500"
            },
            "status": "pending",
            "status_label": "Pending",
            "number": "5021",
            "code": null,
            "payment_method": "e_payment",
            "payment_status": "pending",
            "shipping_method": "delivery",
            "shipped_date": null,
            "completed_date": null,
            "canceled_date": null,
            "notes": null,
            "months": null,
            "aqsati_details": [
                null
            ],
            "created_at": "Feb 11, 2026 09:15"
        }
    ],
    "links": {
        "first": "https://merchant.gini.iq/api/v2.0/third-party/orders?page=1",
        "last": "https://merchant.gini.iq/api/v2.0/third-party/orders?page=12",
        "prev": null,
        "next": "https://merchant.gini.iq/api/v2.0/third-party/orders?page=2"
    },
    "meta": {
        "current_page": 1,
        "last_page": 12,
        "per_page": 15,
        "total": 173
    }
}
Notes
  • Scoped to the signed merchant — only the caller's own orders are returned.
  • Ordered newest-first (latest created_at).
  • List rows load customer, address and promo_code only; the items array and influencer_name are omitted here and returned by GET /orders/{id}.
  • address is the delivery address frozen when the order was placed, not the customer's current address book entry — it never changes if the customer later edits or deletes that address. address.id is the snapshot id.
  • address is null for pickup orders and for orders placed without a resolvable address.
  • address.alt_contact_phone is a second number the customer gave for this delivery, from the same snapshot as contact_phone; null when none was given.
  • late_orders=enabled forces status=pending and returns only orders created more than 12 hours ago, overriding any status filter.
  • is_pre_order is always false — v2 treats pre-orders as normal stock and has no order-level pre-order flag.
  • code is always null in responses (it is a customer-only delivery-verification field).
  • aqsati_details is a single-element array; the element is null unless payment_method is aqsati.
  • Money columns (total_amount, discount_total_amount, shipping_cost) are decimal strings; every amount is also mirrored pre-formatted in IQD under formatted_amounts.
Show order

Returns the full detail for a single order owned by the calling merchant, including line items with their product, discount and variant attributes, plus the influencer name. The {id} path segment is the numeric order id (there is no route-model binding — the order is looked up manually and scoped to the caller).

GET /api/v2.0/third-party/orders/{id}
Signed
Response
{
    "data": {
        "id": 5021,
        "influencer_name": "Sara Q",
        "address": {
            "id": 812,
            "name": "Home",
            "contact_phone": "+9647701234567",
            "alt_contact_phone": null,
            "city": 1,
            "city_label": "Baghdad",
            "state": 14,
            "state_label": "Karrada",
            "address": "Building 5, Floor 2, Street 14",
            "latitude": "33.315000",
            "longitude": "44.366000",
            "created_at": "2026-02-10 18:22:41"
        },
        "customer": {
            "id": 318,
            "name": "Ahmed Ali",
            "phone": "+9647701234567",
            "email": "ahmed@example.com",
            "avatar": "https://cdn.gini.iq/avatars/318.jpg",
            "phone_verified_at": "2025-11-02T10:00:00.000000Z",
            "is_verified": 1,
            "is_active": 1
        },
        "items": [
            {
                "discount": null,
                "product_id": 142,
                "product_variant_id": 1167,
                "product": {
                    "id": 142,
                    "name": "Wireless Headphones",
                    "slug": "wireless-headphones",
                    "sku": "WH-2026-001",
                    "price": 45000,
                    "final_price": 45000
                },
                "id": 8901,
                "quantity": 1,
                "unit_price": "45000.00",
                "discount_unit_price": "45000.00",
                "total_price": "45000.00",
                "final_amount": 45000,
                "discount_total_price": "45000.00",
                "is_installment_same_price": 0,
                "formatted_amounts": {
                    "unit_price": "IQD 45,000",
                    "discount_unit_price": "IQD 45,000",
                    "total_price": "IQD 45,000",
                    "discount_total_price": "IQD 45,000",
                    "final_amount": "IQD 45,000"
                },
                "additional": null,
                "details": [
                    {
                        "label": "Color",
                        "value": "Red"
                    },
                    {
                        "label": "Size",
                        "value": "M"
                    }
                ]
            }
        ],
        "is_pre_order": false,
        "total_amount": "67500.00",
        "promo_code": {
            "promo_code_id": null,
            "promo_code_created_by": "no promo code applied",
            "code": "none",
            "amount": "IQD 0",
            "raw_amount": null
        },
        "discount_total_amount": "0.00",
        "difference_amount": 67500,
        "final_amount": 67500,
        "shipping_cost": "5000.00",
        "total_amount_with_shipping_cost": 72500,
        "formatted_amounts": {
            "final_amount": "IQD 67,500",
            "total_amount": "IQD 67,500",
            "discount_total_amount": "IQD 0",
            "difference_amount": "IQD 67,500",
            "shipping_cost": "IQD 5,000",
            "total_amount_with_shipping_cost": "IQD 72,500",
            "promo_code_amount": "IQD 0",
            "total_after_promo_code": "IQD 67,500"
        },
        "status": "pending",
        "status_label": "Pending",
        "number": "5021",
        "code": null,
        "payment_method": "e_payment",
        "payment_status": "pending",
        "shipping_method": "delivery",
        "shipped_date": null,
        "completed_date": null,
        "canceled_date": null,
        "notes": null,
        "months": null,
        "aqsati_details": [
            null
        ],
        "created_at": "Feb 11, 2026 09:15"
    }
}
Notes
  • Returns 404 with a message of Order not found. when the id does not exist or is not owned by the calling merchant.
  • Detail payload additionally loads items (with product, discount and variant attributes), the influencer name, promo code and transaction.
  • Each item's details array is normalized: variant attribute pivots first, falling back to the legacy additional JSON snapshot (mapping size/color), and an empty array when neither is present — render it directly instead of branching on additional vs variant.
  • product_variant_id is the ordered variant id, or null for variantless items; additional is the legacy free-form attribute object kept for backward compatibility.
  • The nested product object is the full product resource; only representative fields are shown here.
  • aqsati_details is populated (single-element array with month_price, final_amount, month) only when payment_method is aqsati; otherwise it is [null].
Update order status

Transitions an order to a new status. The set of legal target statuses depends on the order's current status AND its fulfilment mode (pickup, gini delivery company, or merchant own delivery). An illegal transition returns 400 without mutating the order. Required body fields vary by target status: rejecting needs a reason, delivering needs the verification code. On success the endpoint returns a plain confirmation message rather than the order.

PUT /api/v2.0/third-party/orders/{id}
Signed
Body parameters
Field Type Required Description
status string Required Target status. Accepted enum values: pending, accepted, delivery_handoff, rejected, on_the_way, delivered, cancelled, refunded, returned, delayed, rwa, expired, temp_cancelled, received, in_warehouse. The value must also be a legal transition from the order's current status (see the transition matrices in notes) or the request is rejected with 400. received and in_warehouse are reported by delivery courier scans: they can be filtered on, but not set through this endpoint.
reject_reason_id integer Optional Id from the reject_order_reasons table. Required when status is rejected; must reference an existing reason.
reject_reason_notes string Optional Free-text note (max 1000 chars). Required only when reject_reason_id is 8 (the 'other' reason); optional otherwise.
Request body
{
    "status": "rejected",
    "reject_reason_id": 3,
    "reject_reason_notes": "Item damaged in warehouse"
}
Response
{
    "data": {
        "message": "Order status updated successfully."
    }
}
Notes
  • Returns 404 with a message of Order not found. when the id is not owned by the caller.
  • An illegal transition for the current status returns 400 with a message of This action is not allowed for the current order status.
  • Allowed transitions - Pickup orders: pending to accepted or rejected.
  • Allowed transitions - Gini delivery company (merchant has a delivery_company_id): pending to accepted or rejected; accepted to delivery_handoff; delivery_handoff to on_the_way; on_the_way to returned.
  • Allowed transitions - Merchant own delivery: pending to accepted or rejected; accepted to on_the_way; delivery_handoff to on_the_way; on_the_way to returned. Delivered is set by the delivery company or the customer's QR scan, never through this endpoint.
  • An order can be rejected only while it is pending. Once it is accepted, only Gini can end it.
  • Server-side effects: accepted creates the delivery shipment and bumps sold_count (stock itself is deducted upstream when the order is created); rejected creates a refund for e-payment/aqsati and cancels installments (requires reject_reason_id); on_the_way marks in-transit; returned processes the return.
  • Minimal accept body sends only status set to accepted.
  • Writes here run with webhook suppression, so a status change made via this API does not re-notify the merchant's own order webhook.
  • A successful response is a fixed confirmation message; re-fetch the order via GET /orders/{id} to read the new state.
Print order receipt

Returns a printable HTML page for an order (receipt, invoice, or sticker) — meant to be opened in a browser or embedded in an iframe, not parsed as JSON. Because a browser navigation cannot send custom headers, this endpoint signs in the query string with a scheme distinct from the rest of the API, and it lives on the web host, not the api/v2.0/third-party base.

GET https://merchant.gini.iq/print/receipt/{order}
Signed
Query parameters
Field Type Required Description
api_key string Required Your API Client ID.
timestamp integer Required Unix time in seconds. Must be within 300 seconds of server time.
signature string Required HMAC-SHA256 of GET + PATH + TIMESTAMP (no body), keyed with your API secret. This differs from the header scheme, which also signs the request body.
type string Optional Which layout to render: receipt (default), invoice, or sticker.
Signed URL
https://merchant.gini.iq/print/receipt/5021?api_key={api_client_id}&timestamp=1739270400&signature={hmac_sha256_hex}
Notes
  • This returns an HTML page, not JSON — open it in a browser or an iframe, then print or save as PDF.
  • Signing differs from the rest of the API: a query-string signature over GET + PATH + TIMESTAMP with NO body (the URL is the whole request).
  • PATH is the receipt path only, e.g. /print/receipt/5021 — no host and no query string.
  • The order must belong to you; a mismatch or unknown order returns 404.
  • The 300-second timestamp window applies here too, so build and open the link promptly.
Rejection reasons

The valid reasons for rejecting an order — use an id here as the reject_reason_id when you transition an order to rejected. requires_note flags the reason that needs reject_reason_notes.

GET /api/v2.0/third-party/orders/rejection-reasons
Signed
Hand off to delivery

Stamp an accepted, non-pickup order as handed to the delivery captain. 400 if the order is not accepted or is a pickup order.

POST /api/v2.0/third-party/orders/{id}/handoff
Signed
Reset delivery handoff

Retired: once an order is handed to delivery, the handoff cannot be undone. This endpoint always answers 400 with the message A handoff cannot be undone, or 404 if the order is not yours. It is kept so existing calls get a clear refusal.

POST /api/v2.0/third-party/orders/{id}/handoff/reset
Signed
Request cancellation

Ask the delivery network to cancel an accepted or in-transit order. The order's status does not change here — Gini's delivery team reviews the request and resolves it through the normal flow.

POST /api/v2.0/third-party/orders/{id}/request-cancellation
Signed
Body parameters
Field Type Required Description
reason string Required Why the cancellation is being requested, max 1000 chars.
Notes
  • Only accepted or in-transit orders can be requested for cancellation, else 400.
  • Send the body as JSON so the reason is covered by the signature.