Fynd Commerce (the Fynd Platform) is an Indian commerce platform from Fynd, the trading name of Shopsense Retail Technologies. It is closest in shape to Shopify plus an order management system: a merchant gets a storefront, a catalogue, multiple sales channels, store-level inventory and a full omnichannel fulfilment stack, all behind one Platform REST API. GoFynd is Fynd's own consumer marketplace and app, which is where the name most people recognise comes from, but the developer surface documented at docs.fynd.com is the platform, not the marketplace. For a seller-side commerce database the platform API is unusually complete: orders, shipments, bags, catalogue, per-location inventory, locations and webhooks are all first-class, and the official SDKs expose every route.
At a glance
What it is
Fynd sells two related things. GoFynd is a D2C fashion and lifestyle marketplace and app aimed at Indian consumers. Fynd Commerce is the SaaS platform a brand licenses to run its own storefronts, stores and fulfilment, and it is the thing with the developer documentation. Reliance Retail took a majority stake in the company in 2019; that ownership detail and any seller-count or GMV figures were not verified from a primary source for this note.
The platform's data model has one wrinkle that shapes every integration. An order contains shipments, and a shipment contains bags. A bag is Fynd's unit of a line item inside a shipment, and it is where item-level status lives (bag_status). Order-level status is coarse; if you want to know what actually happened to a unit, you read bags. The API reflects this: the listing endpoints are orders-listing, shipments-listing and bags, and most filters take a bag_status.
The second structural point is the company and application split. A company is the seller. An application is a sales channel (a storefront, a marketplace connection, an app). Company-level endpoints see everything; application-level endpoints need both company_id and application_id. A token is scoped to exactly one company.
API access
You need a partner account at partners.fynd.com. From there you either create API credentials for a specific company, or build an extension that merchants install, which is the multi-merchant route and the only one that gets webhooks.
Official SDKs (the FDK, Fynd Development Kit) exist for JavaScript, Java, Kotlin, Swift, PHP, Python and Go, published under the gofynd GitHub organisation, plus fdk-extension-javascript for the extension lifecycle and fdk-cli for scaffolding. The JavaScript SDK is the reference implementation and its sdk/platform/* client files are the most reliable published record of the route set.
API versions are per resource and appear in the path, for example catalog/v1.0, catalog/v2.0, catalog/v3.0, order/v1.0, order-manage/v1.0, company-profile/v2.0. Several versions coexist. There is no single global version and no published deprecation calendar in the sources read.
Authentication
Base URL for everything below: https://api.fynd.com.
Client credentials, for a merchant's own integration
- Base64 encode
client_id:client_secret. - POST the token endpoint for the company, with the encoded pair as HTTP basic auth.
- Use the returned token as
Authorization: Bearer <access_token>.
curl -X POST \
"https://api.fynd.com/service/panel/authentication/v1.0/company/${COMPANY_ID}/oauth/token" \
-H "Authorization: Basic $(printf '%s' "${CLIENT_ID}:${CLIENT_SECRET}" | base64)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials"
{
"access_token": "oa-12345fb123456b2ce111f43cdb55fd317def1234",
"token_type": "Bearer",
"expires_in": 3599
}
The token lives just under an hour. The SDK refreshes at 60 seconds before expiry, which is a sensible rule to copy. A token reaches exactly one company, so a connector serving several sellers holds one credential pair and one live token per company_id.
curl -X GET \
"https://api.fynd.com/service/platform/catalog/v2.0/company/${COMPANY_ID}/products/" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
Authorization code, for an installed extension
- Send the merchant to the authorize URL for their company:
GET /service/panel/authentication/v1.0/company/{company_id}/oauth/authorizewith query parametersclient_id,scope(comma separated),redirect_uri,state,access_modeandresponse_type=code. - The SDK additionally signs that URL and appends
x-fp-dateandx-fp-signaturequery parameters, an AWS-style request signature over the path. Use the SDK rather than hand-rolling this. - On callback, exchange the
codeat the same token endpoint with basic auth andgrant_type=authorization_code&code=<code>. - Renew with
grant_type=refresh_token&refresh_token=<token>against the same endpoint.
access_mode selects an offline token (persisting after the merchant's session) versus an online one; offline is what a background sync needs.
Objects we can read
Orders
GET /service/platform/order/v1.0/company/{company_id}/orders-listing.
Query parameters (from the SDK, which is the authoritative list): lane, search_type, search_value, bag_status, time_to_dispatch, payment_methods, tags, from_date, to_date, start_date, end_date, dp_ids, stores, sales_channels, page_no, page_size, is_priority_sort, custom_meta, my_orders, show_cross_company_data, customer_id, order_type, allow_inactive, group_entity, enforce_date_filter, fulfillment_type, ordering_source, channel_account_id, include_count.
GET /service/platform/order/v1.0/company/{company_id}/order-details?order_id={order_id} returns one order, with optional my_orders and allow_inactive.
For an incremental pull, drive start_date and end_date (or from_date and to_date) with enforce_date_filter, and set include_count=false so the listing skips computing a total. When you do need the total, call GET /service/platform/order/v1.0/company/{company_id}/listing/count/ with the same filter values.
Sample response documents are not published in the sources readable here; the SDK ships response type definitions rather than examples. Plan on capturing a real response from a test company before mapping fields.
Shipments and bags
GET /service/platform/order/v1.0/company/{company_id}/shipments-listing, with lane, bag_status, status_assigned, status_override_lane, time_to_dispatch, search_type, search_value, from_date, to_date, start_date, end_date, status_assigned_start_date, status_assigned_end_date, dp_ids, stores, sales_channels, page_no, page_size, fetch_active_shipment, allow_inactive, exclude_locked_shipments, payment_methods, channel_shipment_id, channel_order_id, custom_meta and more.
channel_order_id and channel_shipment_id are the useful ones for reconciling against an upstream marketplace. dp_ids filters by delivery partner, which is Fynd's carrier identifier.
Related reads: GET .../shipment-details, GET .../bags, GET .../bag-details/, GET .../filter-listing, and GET /service/platform/order-manage/v1.0/company/{company_id}/tracking for tracking, GET .../shipment/history for the status trail.
Products and listings
GET /service/platform/catalog/v2.0/company/{company_id}/products/ with brand_ids, category_ids, item_ids, department_ids, item_code, name, slug, all_identifiers, q, tags, page_no, page_size, page_type, page_id, sort_on. One product is GET /catalog/v2.0/company/{company_id}/products/{item_id}/; sizes are GET /catalog/v2.0/company/{company_id}/products/{item_id}/all_sizes and /sizes/{size}. A v3.0 products route exists alongside v2.0.
Fynd's identifier vocabulary: item_id is the product, item_code is the seller's product code, size identifies the variant, and seller_identifier is the seller's SKU for a size at a location. seller_identifier is the field to join your own SKU on.
Inventory
GET /service/platform/catalog/v1.0/company/{company_id}/inventories with item_id, size, size_identifier, seller_identifiers, store_ids, brand_ids, sellable, qty_gt, qty_lt, qty_type, from_date, to_date, page_no, page_size, page_id, page_type, q.
This is per item, per size, per store, which is exactly the grain the unified inventory table wants. qty_gt and qty_lt let you pull only rows that moved, and from_date and to_date give a change window.
Per-size detail: GET /catalog/v2.0/company/{company_id}/products/{item_id}/sizes/{size}, and there is a lookup by size identifier as well.
Locations
GET /service/platform/company-profile/v2.0/company/{company_id}/location lists stores and warehouses; GET .../location/{location_id} fetches one; POST /company-profile/v1.0/company/{company_id}/location/bulk creates many. Brands sit at /company-profile/v1.0/company/{company_id}/brand/ and /company-profile/v2.0/company/{company_id}/company-brand.
Returns, cancellations and settlements
Returns and cancellations are not separate resources. They are states in the bag and shipment state machine, reached through bag_status and the state transition endpoints under order-manage/v1.0 (/bag/state/transition, /allowed/state/transition, /jobs/state-transition). Read them by filtering bags and shipments-listing on the relevant bag_status values, which are configurable per company through /state/manager/config, so enumerate them from the company rather than hardcoding.
No settlement, payout or seller-ledger resource appeared in the platform SDK route set. Payment status updates go through POST /order-manage/v1.0/company/{company_id}/payment/update, and refund mode configuration through /refund-mode-config, but neither is a money-movement report.
Writing back: listings, price and stock
Two write paths for stock is a deliberate split: updateInventories (POST /catalog/v2.0/.../inventory/) takes a batch, while the realtime route (POST /catalog/v2.0/.../products/{item_id}/inventory/{seller_identifier}) is the low-latency single-SKU path. Use the batch route for a scheduled sync and the realtime route for oversell protection.
Price sits on the product and on the per-size inventory record rather than on a dedicated price endpoint, so a price change goes through the product or inventory write. Confirm which field your company's catalogue treats as authoritative (price_effective versus price_marked in Fynd's vocabulary) before automating it. Bulk uploads are job based: you submit, you get a batch ID, and you poll the batch endpoint. Templates and validation schemas are published at /catalog/v1.0/company/{company_id}/products/templates/ and /inventory/templates/validation/schema/.
Webhooks and notifications
Webhooks are an extension feature. You register a publicly reachable HTTPS URL and subscribe to named, versioned event topics.
Documented topics include:
- Orders:
order/placed/v1,order/pending/v1,order/payment_failed/v1 - Shipments:
shipment/create/v1,shipment/update/v1,shipment/data_update/v1 - Inventory:
location-quantity/create/v1,location-quantity/update/v1,customfields/inventory-update/v1,customfields/inventory-delete/v1 - Products:
product/create/v3,product/update/v3,product/delete/v3,product-size/create/v2,product-size/update/v2 - Payments:
payment/complete/v1,payment/pending/v1,payment/failed/v1
Bodies are JSON carrying the event data plus metadata about the trigger. Verification is HMAC SHA-256: the delivery carries an x-fp-signature header, and the extension recomputes the HMAC over the serialised request body using its own API secret and compares. This is confirmed in fdk-extension-javascript, where verifySignature reads req.headers['x-fp-signature'] and compares it against hmacSHA256(JSON.stringify(body), api_secret). Serialise the body exactly as received or the comparison will fail on key ordering.
The overview page describes authentication on the endpoint as recommended rather than mandatory, and does not state a retry policy. Assume at-least-once delivery, make handlers idempotent on the event identifier, and keep a reconciliation pass over shipments-listing on a date window.
location-quantity/update/v1 is the event to build a stock mirror on; shipment/update/v1 is the one that drives fulfilment state.
Rate limits and pagination
No numeric rate limits, quota headers or throttling behaviour appear in the documentation or SDK source read for this note. Treat the limit as unknown, implement exponential backoff on 429 and 5xx, and keep a modest sustained rate per company.
Pagination has two modes and most listing endpoints accept both. Offset mode uses page_no and page_size. Cursor mode uses page_id together with page_type; catalogue and inventory endpoints expose both, order listings use page_no and page_size. Prefer cursor mode where offered for large catalogues, and set include_count=false on order and shipment listings so the backend skips the total, then fetch the count separately from listing/count/ when you actually need it.
Mapping to the unified model
Gaps and open questions
- No sample request or response bodies are published in the readable documentation. Every field mapping above should be confirmed against a captured response from a real company before implementation.
- No rate limits, quota headers or throttling guidance are published.
- No sandbox environment is documented; testing appears to be against a development company on the live platform.
- No settlement, payout or seller-ledger resource exists in the platform route set.
- Webhook retry policy is not stated, and endpoint authentication is described as recommended rather than required.
bag_statusvalues are company-configurable, so a connector cannot ship a fixed status map. Read them from/state/manager/configat setup time.- Several resource versions coexist (
catalog/v1.0,v2.0,v3.0) with no published deprecation calendar. Pin versions and watch the SDK changelog. - The ownership and market-share statements in "What it is" were not verified from a primary source in this pass.
Sources
- Fynd partner documentation index
- Platform REST API client libraries and authentication
- Webhooks overview
- gofynd/fdk-client-javascript, Order platform client
- gofynd/fdk-client-javascript, Catalog platform client
- gofynd/fdk-client-javascript, CompanyProfile platform client
- gofynd/fdk-client-javascript, platform OAuthClient
- gofynd/fdk-extension-javascript, webhook signature verification