Shoptimize

Shoptimize is gone: shoptimize.in redirects to graas.ai. The live successor API is Graas at developer.graas.ai, appKey plus accountNumber headers, orders and product master.

Shoptimize was an Indian D2C ecommerce platform that built and ran branded online stores for consumer brands. It no longer exists as a product or a brand. As of 2026-09-22 shoptimize.in returns a 301 to shoptimize.ai, which in turn serves www.graas.ai, and none of the Shoptimize subdomains an integrator would look for resolve at all. Graas is the live company: a Singapore-headquartered commerce intelligence and channel operations business with offices across India and South East Asia. This page therefore does two things: it records that the Shoptimize entry should be retired or repointed, and it documents the API that a former Shoptimize merchant would actually integrate with today, which is Graas's, and which is genuinely public.

At a glance

What it is

Shoptimize was a hosted D2C storefront platform for Indian consumer brands. It is not one any more, and there is no Shoptimize product surface left to integrate with. The evidence, all from live checks on 2026-09-22:

  • https://www.shoptimize.in/ returns 301 to https://www.shoptimize.ai/, which serves https://www.graas.ai/.
  • docs.shoptimize.in, developer.shoptimize.in, api.shoptimize.in and help.shoptimize.in have no DNS records. Neither do the .ai equivalents.
  • graas.ai carries no Shoptimize branding, no migration guide and no mention of the name anywhere in its 381 URL sitemap.
Note

Graas is commonly reported to have acquired Shoptimize in 2022, and the redirect chain is consistent with that, but we could not confirm the transaction from a primary source reachable on 2026-09-22. Treat the corporate history as unverified. What is verified is that the domain now serves Graas and that no Shoptimize product surface remains.

Graas today is not a store builder. Its own pages describe "The System of Intelligence for Retail Commerce", a commerce knowledge graph, an agent product, decision intelligence, and a Storefront Ops service that will "build, operate, and grow your storefronts across Shopee, Lazada, and beyond". Its terms of use are governed by Singapore law and still refer to Solv Pte Ltd as a related entity. In September 2026 it announced a 17 million US dollar Series B and the acquisition of Trustana. So a brand that was on Shoptimize for a hosted D2C store is not being served the same product: Graas sells marketplace operations and analytics.

API access

Graas's reference is public and needs no login. Access to the API itself is by request:

  • Application registration: email developer@graas.ai. Graas's own wording, typo included, is "To register your applicaion with us, please send an email to developer@graas.ai".
  • Developer key: the same address. "To get a developer key, please email developer@graas.ai and include a request for the key."
  • Code examples are offered in Shell, Ruby and Python, but the Ruby and Python samples are unedited Slate boilerplate calling a fictional kittn library. Only the shell examples are real, and there is no published SDK.
Warning

Every HTTP example in the reference renders the host as a broken template: the curl lines read https://api. followed by the path, with the host variable missing. The paths are reliable, the host is not stated. api.graas.ai exists and answers 401 to an unauthenticated request, with a CORS allow-list naming authorization, Mudra, username and authType, so it is the likely base, but confirm it with Graas before coding.

Authentication

Two mechanisms, used for different things.

Data calls: static headers

curl "https://{api-host}/v1/orders?updatedAfter=1767196800&updatedBefore=1784701525" \
  -H "Content-Type: application/json" \
  -H "accountNumber: 12121212121212121" \
  -H "appKey: 2121212121"

Graas states it "requires inclusion of APP key and seller account number in API requests' headers", where accountNumber is the seller account number and appKey is the application key issued to you, and adds that "Endpoints on which seller authorizes the APP alone can be accessed by APP". So the app is scoped per seller by the seller's own authorization step, and accountNumber is how you address multiple sellers with one app key. Key your credential store on accountNumber.

Account linking and dashboard embed

A five step flow, only the first four of which produce credentials:

  1. POST /services/account/auth with the appKey header and a body of email, businessName, phoneNumber, state, redirectURL, countryCode, currencyCode and defaultLocale. It returns {"status": "success", "url": "..."} where the URL is a signup or password verification page for the merchant.
  2. The merchant completes verification and is returned to your redirectURL with an authorization grant code. The code is valid for 10 minutes.
  3. GET /services/account/longToken?code={code} with the appKey header returns {"longToken": "..."}. Graas says to send it as Authorization: Bearer {longToken} on API queries. No expiry is stated for the long token, and no refresh grant is documented.
  4. GET /services/account/shortToken with Authorization: Bearer {longToken} returns a JWT accessToken valid for one hour.
  5. The short token is only for embedding Graas's dashboard in an iframe. It is not a data API credential.

state behaves as in OAuth: Graas returns the exact value you sent as a query parameter on the redirect. Use it, since the flow has no other CSRF defence documented.

Objects we can read

Orders

GET /v1/orders?updatedAfter={unix}&updatedBefore={unix}&pageNumber=1&pageSize=200&orderStatus=DELIVERED&paymentStatus=COMPLETED

Pagination is page based and the envelope tells you the totals. Documented response, trimmed to one order and one item, with the address left as Graas published it (masked, and PII in a real response):

{
  "numberOfPages": 1,
  "numberOfRecords": 3,
  "history": [
    {
      "site": { "name": "qoo10", "nickNameID": "qoo10-1" },
      "orderID": "227973300",
      "orderNumber": "227973300",
      "buyerDetails": { "name": "Hui", "email": "ram@graas.ai" },
      "orderItems": [
        {
          "orderItemID": "227973300",
          "SKU": "AIL0006416-01",
          "customSKU": "8888200702977",
          "itemTitle": "CARTON SALES COCOLIFE 100% COCONUT WATER 1L x 12",
          "quantity": 12,
          "itemAmount": { "amount": 355, "currencyCode": "SGD" },
          "shippingAmount": { "amount": 390, "currencyCode": "SGD" },
          "settlementAmount": { "amount": 3962, "currencyCode": "SGD" },
          "orderType": "Delivery",
          "variantDetails": [{ "title": "Type", "name": "Cocolife Coconut Water 1L x 12" }]
        }
      ],
      "orderStatus": "INITIATED",
      "paymentStatus": "NOT_INITIATED",
      "shippingStatus": "NOT_SHIPPED",
      "orderAmount": { "amount": 4260, "currencyCode": "SGD" },
      "shippingAmount": { "amount": 390, "currencyCode": "SGD" },
      "sellerDiscountAmount": { "amount": 900, "currencyCode": "SGD" },
      "channelDiscountAmount": { "amount": 0, "currencyCode": "SGD" },
      "shippingDetails": {
        "address": { "name": "Hui", "street1": "*******airN*******", "phone": "+65*******1872", "postalCode": "32***60", "country": "SG" },
        "shippingTrackingDetails": { "airwayBill": "SGP95722039", "courierName": "Store Pickup", "pickupVoucherCode": "1234567891***" }
      },
      "cartNumber": "113054733",
      "invoiceNumber": "INV0000001",
      "timeLastUpdated": 1504588069,
      "timeOrderCreated": 1504587886,
      "documents": { "shippingLabelUrl": "https://docs.graas.ai/uploads/shippingLabels/..." }
    }
  ]
}

Money is integer minor units with a sibling currency code. Graas states it plainly: "Example if the amount is 10.99 it will be demoted as 1099". Do not divide by 100 blindly across currencies; carry the currencyCode through.

A specific order

GET /v1/order/{nickNameID}/{orderID}

nickNameID is the seller's identifier for one channel connection, for example lazada-1 or qoo10-1, and site.name is the channel. Together they are the account dimension.

Shipments, returns and settlements

None of the three is a separate object. Tracking lives on the order as shippingDetails.shippingTrackingDetails with airwayBill, courierName, remarks and pickupVoucherCode, plus shippingStatus and a shippingLabelUrl under documents. Returns are order states: RETURN_REQUESTED, RETURN_ACCEPTED, RETURN_SHIPPED, RETURNED, plus REFUNDED on paymentStatus. There is no settlement endpoint at all; settlementAmount on each order item is the only settlement-shaped field documented.

Purchase orders and inbound stock

POST /v1/asn
GET  /v1/asn/{asnID}?warehouseID={warehouseID}
GET  /v1/asn?warehouseID={warehouseID}&supplierID={supplierID}&supplierRef={supplierRef}

Advance shipping notices, scoped by warehouseID. This is the inbound side of inventory.

Products and listings

No read endpoint is documented. Product master is write-only in the published reference, which means a full catalogue reconciliation is not possible from the API alone as documented. Raise this with Graas.

Writing back: listings, price and stock

Four endpoints, all first-party documented.

The product body is multi-currency and multi-warehouse by construction. Documented fields include sellerSKU, productID, itemTitle, shortDescription, itemDescription, locale-suffixed variants of each such as itemTitle_thTH, imageURLs, sizeChartImageURL, quantities as an array of {warehouseID, quantity}, price as an array of {currencyCode, retailPrice, salePrice} with each price an {amount, currencyCode} pair, variantAttributes and otherAttributes as key and value arrays.

That means price and stock are not scalars here. A single product carries one quantity per warehouse and one retail and sale price per currency. Model that before you write the connector, not after.

Order writes go to the same collection URL as the read:

PUT /v1/orders

with a body of {"data": [ ... ]} where each element carries orderID, the target orderStatus such as ACCEPTED, the site object, and either the orderItems being accepted or a shippingTrackingDetails object with courierName and airwayBill. It is a batch call and the response is a result array, one entry per order, so check per element rather than on the HTTP status alone. Cancellation uses the same shape with the cancel status.

Channel connections are created through POST /v1/accounts/channels/{channel}, and the reference documents kartrocket and lazada as examples.

Webhooks and notifications

None documented. Poll GET /v1/orders on a rolling updatedAfter and updatedBefore window.

A practical cadence, given no published rate limit: every 5 to 15 minutes with a window that overlaps the previous one by a few minutes to absorb clock skew, pageSize=200, and a nightly wide sweep to catch late status changes. Deduplicate on site.nickNameID plus orderID.

Rate limits and pagination

No rate limit, quota header or burst policy is published anywhere in the reference. Ask Graas for the numbers when you request the app key, and until then keep concurrency at one per seller account.

Pagination is pageNumber and pageSize with numberOfPages and numberOfRecords in the envelope. Because the window is time based rather than cursor based, an order updated mid-sweep can move between pages; sort your own output by timeLastUpdated and treat the sweep as at-least-once.

Mapping to the unified model

Gaps and open questions

  • The base host. Every example in the reference has a broken host template.
  • Whether any former Shoptimize D2C store is still served by Graas, and if so through what interface. Nothing on graas.ai suggests a hosted D2C storefront product survives.
  • No product read endpoint is documented, which blocks catalogue reconciliation.
  • No rate limits, no webhooks, no error code catalogue beyond a handful of per-endpoint messages.
  • Long token lifetime and refresh are undocumented.
  • Whether the reference is current. It still documents kartrocket as a channel, a brand that became Shiprocket years ago, so parts of the document have not been revised recently. Relatedly, whether itemAmount is unit price or line total is genuinely ambiguous in the published sample.

Sources

  • Live redirect and DNS checks on shoptimize.in, www.shoptimize.in, shoptimize.ai and the docs, developer, api and help subdomains of both, 2026-09-22
  • developer.graas.ai, the full Slate "API Reference", for every endpoint, header, parameter, status value and sample body quoted above
  • graas.ai, graas.ai/our-story and graas.ai/storefront-ops, for what Graas sells today
  • graas.ai/terms-and-conditions, Singapore governing law and the Solv Pte Ltd reference
  • api.graas.ai, HTTP 401 with its CORS allow-list, 2026-09-22