Flipkart is the other horizontal marketplace an Indian seller has to be on, alongside Amazon. It runs a genuine public developer programme at seller.flipkart.com/api-docs, with a stable v3 REST API over api.flipkart.net, OAuth 2.0 credentials a seller can mint themselves from the seller dashboard, and a partner flow for aggregators managing many sellers. The shape of the API is different from Amazon's in one important way: Flipkart's unit of work is the shipment, not the order. You search shipments by state, you pack them, you mark them ready to dispatch, you pull the label and the invoice. Orders and order items exist, but they are attributes hanging off a shipment rather than the thing you poll.
At a glance
What it is
Flipkart is India's largest home grown marketplace, majority owned by Walmart, with Myntra for fashion and Shopsy for value commerce under the same group. For sellers it is a pure marketplace: Flipkart owns the customer, sets the commission, and in most categories controls the logistics. Two fulfilment models matter to a connector. In the standard marketplace model, the seller holds stock at their own location, packs against a Flipkart generated label and invoice, and hands over to a Flipkart logistics partner. In Fulfilled By Flipkart (FBF), stock sits in a Flipkart warehouse and Flipkart does everything, which shows up in the API as a serviceProfile of FBF rather than NON_FBF and as a different set of reports. There is also a Self Ship model where the seller arranges their own courier, and its shipment states differ from the standard flow.
The catalogue is shared, like Amazon's. A product has a Flipkart Serial Number (FSN), which the API exposes as product_id, and a seller's offer against it is a listing with a listing_id and the seller's own sku_id. Cash on delivery is a large share of volume, and returns, both customer returns and courier returns, are a first class object with their own API.
API access
A single seller gets credentials from the seller dashboard. A partner or aggregator managing many sellers registers through the Partner Dashboard and receives an application id and application secret, which in the docs are written as appId and appSecret. The same credential pair drives both OAuth flows: Basic authentication on the token call for self access, and the authorisation code redirect for third party access.
Everything runs on HTTPS against https://api.flipkart.net. The seller API paths sit under /sellers, so the shipment filter is https://api.flipkart.net/sellers/v3/shipments/filter/ and a listing update is https://api.flipkart.net/sellers/listings/v3/update/price. The OAuth service is a sibling at https://api.flipkart.net/oauth-service/oauth/..., not under /sellers.
Versioning is per resource family rather than global. Shipments and listings are on v3, returns are still on v2, and the Report Management API is unversioned in its path. There is no published deprecation calendar; changes land in the Release Notes page.
There is no official Flipkart SDK. The documentation's own code samples use Unirest for Java and RestSharp for .NET, which tells you the expectation is that you write the HTTP client yourself.
Three things are not self serve on Flipkart and each one is a support ticket: getting a sandbox, registering a notification callback URL, and getting a partner application approved. Budget for the ticket cycle at the start of an integration, not the end. For single sellers the ticket path is Seller Dashboard, then Help, then API. For aggregators it is Partner Dashboard, then API, then Help and Support, then Create Ticket.
Authentication
Self access: client credentials
A seller integrating their own account uses the client credentials grant. The application id and secret go in an HTTP Basic header on the token call, and the grant type and scope go in the query string.
curl -u <appid>:<app-secret> \ 'https://api.flipkart.net/oauth-service/oauth/token?grant_type=client_credentials&scope=Seller_Api'
{ "access_token": "<token>", "token_type": "bearer", "expires_in": 3330779, "scope": "Seller_Api" }
The documented scope is Seller_Api. The docs also show scope=Seller_Api,Default in one example, so accept both as valid.
Partner access: authorisation code
An aggregator sends the seller to the Flipkart authorisation page, gets a code back on the redirect URI, and swaps it for a token pair.
GET https://api.flipkart.net/oauth-service/oauth/authorize ?client_id=<client-id> &redirect_uri=<redirect-uri> &response_type=code &scope=Seller_Api &state=<state>
GET https://api.flipkart.net/oauth-service/oauth/token ?redirect_uri=<redirect-uri> &grant_type=authorization_code &state=<state> &code=<code>
{
"access_token": "f638949a-c979-4172-b33c-23311a168647", "token_type": "bearer",
"refresh_token": "860e03da-d58a-4988-9149-a4a7f365bba1",
"expires_in": 5183999, "scope": "Seller_Api", "refresh_token_expires_in": 10703805
}
Refresh with the same Basic header:
curl -u <appid>:<app-secret> \ 'https://api.flipkart.net/oauth-service/oauth/token?grant_type=refresh_token&refresh_token=<refresh_token>'
Token lifetimes
The documentation states that access token validity is 60 days and refresh token validity is 180 days. The worked examples are consistent with the access token (expires_in of 5183999 seconds is 59.99 days) but not with the refresh token (refresh_token_expires_in of 10703805 seconds is about 124 days), and the client credentials example returns 3330779 seconds, about 38.5 days. Treat the stated 60 and 180 days as the policy and the expires_in on each response as the truth for that token. Do not hardcode either.
There is a dedicated endpoint for checking a token without spending a call on a real operation:
curl --location 'https://api.flipkart.net/oauth-service/oauth/token/expiry?token_type=access&token=<access_token>' \ --header 'Authorization: Basic <base64_encoded_credentials>' \ --header 'Content-Type: application/json'
{ "expired": false, "token_type": "access_token", "expires_in": 5183981 }
Calling the API
curl -X POST 'https://api.flipkart.net/sellers/v3/shipments/filter/' \
-H 'Authorization: Bearer <access_token>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"filter":{"type":"preDispatch","states":["APPROVED"]},"pagination":{"pageSize":20}}'
Authorization is mandatory on every call and Content-Type: application/json; charset=utf-8 is required on every POST.
Multiple sellers
For a partner application, one application id and secret serve every seller, and each seller has their own access and refresh token pair from the authorisation code flow. Store the pair keyed by Flipkart seller id, along with the seller's location ids, because almost every write operation takes a locationId and the wrong one fails the call rather than silently routing elsewhere. A seller with several dispatch locations is the normal case, not the exception.
Objects we can read
Orders
Flipkart does not give you an orders endpoint. The order lives inside the shipment: orderId and orderItemId are fields on the order items array of a shipment. So the sync loop is a shipment search, and orders are reconstructed by grouping order items on orderId.
POST /v3/shipments/filter/. The request has three blocks: filter, pagination and sort.
{
"filter": {
"type": "preDispatch",
"states": ["APPROVED", "PACKED", "READY_TO_DISPATCH"],
"hold": false,
"sku": ["SKU001", "SKU002"],
"locationId": "LOC123",
"serviceProfiles": "NON_FBF",
"shipmentTypes": ["NORMAL"],
"orderDate": { "from": "2026-09-01T00:00:00Z", "to": "2026-09-21T23:59:59Z" },
"dispatchAfterDate": { "from": "2026-09-02T00:00:00Z", "to": "2026-09-22T00:00:00Z" },
"dispatchByDate": { "from": "2026-09-05T00:00:00Z", "to": "2026-09-25T00:00:00Z" }
},
"pagination": { "pageSize": 20 },
"sort": { "field": "dispatchByDate", "order": "desc" }
}
type splits the search into the pre dispatch world and the post dispatch world, which is the single most important filter: a shipment you still have to act on is preDispatch, a shipped or delivered one is postDispatch. hold is the flag for shipments Flipkart has frozen pending a cash on delivery check, an address check or a verification, and you must not pack a held shipment.
Response shape, with the field names as published:
{
"nextPageUrl": "https://api.flipkart.net/sellers/v3/shipments/filter/?pageToken=abc123",
"hasMore": true,
"shipments": [
{
"shipmentId": "SHP001",
"dispatchByDate": "2026-09-25T18:30:00Z", "dispatchAfterDate": "2026-09-02T10:00:00Z",
"updatedAt": "2026-09-15T12:45:30Z", "hold": false, "locationId": "LOC123",
"orderItems": [
{
"orderItemId": "OI123456", "orderId": "ORD789", "status": "PACKED",
"quantity": 2, "sku": "SKU001", "listingId": "LST001", "cancellationGroupId": "CG001",
"priceComponents": {
"sellingPrice": 500.00, "totalPrice": 1050.00, "shippingCharge": 50.00,
"customerPrice": 450.00, "flipkartDiscount": 50.00
}
}
],
"subShipments": [
{
"subShipmentId": "SS001", "status": "PACKED", "trackingId": "TRK12345",
"dispatchByDate": "2026-09-25T18:30:00Z", "serviceProfile": "NON_FBF",
"packages": [{ "packageId": "PKG001", "quantity": 2 }]
}
],
"deliveryAddress": {
"firstName": "John", "lastName": "Doe", "pincode": "560001",
"city": "Bangalore", "stateName": "Karnataka",
"addressLine1": "123 Main Street", "addressLine2": "Apt 4B"
}
}
]
}
The field names above come from the Order Management API Reference. The values are illustrative. deliveryAddress is PII and Flipkart does not mask it, so encrypt it at rest and keep it out of any log line.
Pagination is a full URL, not a token you assemble: follow nextPageUrl verbatim while hasMore is true. The pageToken embedded in that URL is opaque.
To fetch specific shipments rather than search, use the direct read, which accepts three mutually exclusive identifier lists:
GET /v3/shipments?shipmentIds={csv}
GET /v3/shipments?orderItemIds={csv}
GET /v3/shipments?orderIds={csv}
Order items
Order items are the orderItems array inside a shipment, never a separate resource. The fields that matter are orderItemId (the stable primary key, unique across the account), orderId, status, quantity, sku (the seller's own SKU), listingId, cancellationGroupId and priceComponents.
priceComponents is the money breakdown and it repays careful reading. sellingPrice is what the seller charges, flipkartDiscount is the part Flipkart funds, customerPrice is what the buyer actually paid, shippingCharge is the delivery fee on the line, and totalPrice is the line total. Seller revenue is not customerPrice: the discount Flipkart funds is still owed to the seller and shows up in the settlement.
cancellationGroupId groups order items that can only be cancelled together. When you cancel, you cancel the group.
Products and listings
GET /listings/v3/{sku-ids} takes a comma separated list of the seller's own SKU ids and resolves them to Flipkart identifiers:
{
"available": { "sku": { "listing_id": "<flipkart-system-identifier>", "product_id": "<flipkart-product-identifier>" } },
"unavailable": ["<sku1>"],
"invalid": ["<sku>"]
}
Three buckets, and the distinction matters: unavailable means Flipkart knows the SKU but the listing is not live, invalid means it does not know the SKU at all.
POST /listings/v3/details takes the same SKUs in a body and returns price as well, up to ten at a time:
{ "sku_ids": ["<sku1>", "<sku2>", "<sku3>"] }
{
"available": {
"sku": {
"listing_id": "<flipkart-system-identifier>", "product_id": "<flipkart-product-identifier>",
"product_title": "<product_title>",
"price": { "mrp": 0, "flipkart_selling_price": 0, "currency": "INR" }
}
},
"unavailable": ["<sku1>"],
"invalid": ["<sku>"]
}
POST /listings/v3/search is the one that walks the whole catalogue, which is what a nightly refresh needs:
{ "filters": { "listing_status": "ACTIVE" }, "page_id": null }
{
"next_page_id": "AAAASbmqpzzYL4xOFBusBgggUaR+KyCGVsSKW02qGQFV...",
"has_more": true,
"listings": [{ "listing_id": "LSTIRNDHUFTRNDMZRWFENDU2H", "product_id": "IRNDHUFTRNDMZRWF", "sku_id": "HD 1920/29" }]
}
Pagination here is a page_id cursor echoed back as page_id on the next request, with has_more as the stop condition. Note that this search returns identifiers only. To get price and stock you still have to call /listings/v3/details in batches of ten, which is the real cost of a full listings refresh: a seller with ten thousand SKUs is a thousand detail calls.
POST /listings/v3/product/search searches the Flipkart catalogue rather than your own listings and returns up to twenty listings per batch. Use it to find the product_id to attach a new listing to.
Listing status is ACTIVE or INACTIVE, and the documentation warns that the semantics differ between a product only you sell and a product several sellers share.
Inventory
Stock is an attribute of a listing, held per location, so there is no separate inventory endpoint. It comes back in the listing update shape as locations[] { id, status, inventory } and is written the same way. For FBF stock held in a Flipkart warehouse, the current position comes from the Report Management API rather than from the listing: current_inventory_report for sellable stock, stranded_inventory_report for inventory that has gone inactive in a warehouse, and unsellable_inventory_report for write offs. stock_ledger gives the day by day transaction record at a chosen warehouse and mir_ledger gives the finalised monthly reconciliation.
Shipments and tracking
The shipment is the primary object, so everything in the Orders section above applies here too. The tracking identifier is subShipments[].trackingId and the carrier is expressed as serviceProfile, which is the service tier (FBF, NON_FBF) rather than a named courier. Flipkart does not expose a courier name or a scan by scan event list through the seller API. Movement is visible only as state transitions on the shipment, either by polling the filter with type of postDispatch or by consuming notifications.
The standard marketplace forward states, in order:
Self Ship runs a shorter forward flow of Approved, Shipped, Delivered, Completed, with its own reverse states for courier returns (RVP) and return to origin (RTO).
Returns and cancellations
Returns are a real API, on v2 rather than v3, at https://api.flipkart.net/sellers/v2/returns.
GET /v2/returns?source=customer_return&createdAfter=2026-09-01T00:00:00Z&locationId=LOC123
The full response schema for this endpoint is not reproduced on the reference page we read, so the exact field list is marked as not published here. The return lifecycle states are documented: CREATED when a return is initiated, COMPLETED when the product has reached the seller, and CANCELLED when the return is dropped and the product never arrives.
The write side of returns is well specified:
Cancellations of forward orders are a separate call, POST /v3/shipments/cancel, taking a shipments array of shipmentId, locationId, cancellationGroupIds and a reason from cannot_procure_item, not_enough_inventory and b2b_order. Every seller initiated cancellation counts against the seller's performance metrics, so treat this as a last resort rather than an inventory management tool.
Payments and settlements
Settlements come only through the Report Management API, which is a request, poll, download cycle.
POST /reports/settled_transaction_ledger
{ "correlation_id": "59297562-eada-49c9-bdd1-447f778e5037", "parameters": { "from_date": "2026-05-02", "to_date": "2026-06-02" } }
{ "report_id": "R-01BX5ZZKBKACTAV9WEVGEMMVRY" }
Then poll:
GET /reports/R-01BX5ZZKBKACTAV9WEVGEMMVRY/detail
{
"report_id": "R-01BX5ZZKBKACTAV9WEVGEMMVRY", "status": "COMPLETED",
"location": "https://api.flipkart.net/storage/reports/R-01BX5ZZKBKACTAV9WEVGEMMVRY?x_secret_key=<secret_key>",
"metadata": { "expiry": "2026-05-05 23:59:59" }
}
The location URL is pre signed and carries an expiry in metadata, so download promptly and store the file rather than the link. The correlation_id is yours to set and is the idempotency handle: reuse it to avoid triggering a duplicate generation.
The published report type identifiers:
For a unified settlements table, settled_transaction_ledger is the source of record and commission_invoice_transaction_report is what explains the fee lines.
Customers
There is no customer object and no customer endpoint. The only customer data exposed is deliveryAddress on a shipment, carrying firstName, lastName, addressLine1, addressLine2, city, stateName and pincode. There is no email address and no reliable buyer identifier, so repeat purchase can only be inferred from an address match, which is weak.
Locations
Locations exist as locationId strings and are required on most write calls, but there is no endpoint that lists a seller's locations. The list has to be read out of the seller dashboard or supplied during onboarding and stored alongside the credentials. This is a real gap and a common cause of failed first integrations.
Writing back: listings, price and stock
This is Flipkart's strongest point compared with most Indian marketplaces: price and stock are plain synchronous POSTs with an immediate per SKU result, no feed job and no polling.
Every one of these takes a map of SKU to change, and every one is capped at ten SKUs per call.
Price
POST /listings/v3/update/price
{ "<sku>": { "product_id": "<product_id>", "price": { "mrp": 1000, "selling_price": 800, "currency": "INR" } } }
{ "sku": { "status": "success|failure|warning", "errors": [{ "severity": "ERROR|WARNING", "code": "<code>", "description": "<description>" }] } }
Both mrp and selling_price are sent together. MRP is a legal maximum in India and Flipkart validates the selling price against it, so a price push that omits MRP or sends an inconsistent pair comes back as a per SKU failure while the other nine in the batch succeed. Always read the per SKU status; a 200 on the call does not mean the change landed.
Stock
POST /listings/v3/update/inventory
{ "<sku>": { "product_id": "<product_id>", "locations": [{ "id": "<location-id>", "inventory": 100 }] } }
The response has the same per SKU status and errors shape. Stock is per location, so a seller with three dispatch locations sends three entries in locations.
Everything at once
POST /listings/v3/update
{
"<sku>": {
"product_id": "<product-id>",
"price": { "mrp": 1000, "selling_price": 800, "currency": "INR" },
"listing_status": "ACTIVE|INACTIVE",
"locations": [{ "id": "<location-id>", "status": "ENABLED|DISABLED", "inventory": 50 }]
}
}
{ "sku": { "status": "success|failure|warning", "errors": [], "attribute_errors": [] } }
This is the one to build the connector on: it sets price, stock, listing status and per location enablement in a single call, and it separates errors from attribute_errors so you can tell a rejected price from a rejected attribute. POST /listings/v3 creates new listings with the same batch limit of ten. For a seller uploading a whole catalogue rather than updating one, Flipkart also offers a seller FTP drop, which is the right tool for initial load and the wrong one for ongoing sync.
Fulfilment writes
The pack and dispatch sequence is three calls plus two downloads.
Steps 1 and 4 both return a shipments array with a per shipment processingStatus of SUCCESS or FAILURE plus errorCode and errorMessage, the same partial success pattern as the listings calls.
The invoice is generated by Flipkart, not by the seller, which is why the pack call takes taxItems: the HSN code and tax rates you supply there end up on a legal document.
Webhooks and notifications
The Order Management Notification Service pushes shipment and return events to a URL you own.
Registration is not self serve. You raise a ticket supplying the seller id, the notification receiver URL, VAPT and NDA certificates, the location ids, and the OAuth application id and secret. Once registered, you can toggle delivery yourself:
POST https://api.flipkart.net/sellers/v3/notification/subscription
{ "seller_id": "<seller_id>", "location_id": "<location_id>", "disable_order": true, "disable_returns": false }
Every notification has the same envelope:
{ "shipmentId": "", "eventType": "", "source": "flipkart", "locationId": "", "timestamp": "", "version": "v3", "attributes": {} }
Shipment event types: shipment_created, shipment_hold, shipment_unhold, shipment_packed, shipment_ready_to_dispatch, shipment_pickup_complete, shipment_shipped, shipment_delivered, shipment_dispatch_dates_changed, shipment_cancelled, shipment_form_failed.
Return event types: return_created, return_item_tracking_id_update, return_expected_date_changed, return_picked_up, return_completed, return_cancelled.
Verification is a signature, not an HMAC secret in a single header. Each callback carries two headers:
X_Date, an HTTP-Date format timestamp.X_Authorization, of the formFKLOGIN Base64(OAuth-appid:fk_signature).
The signature is SHA-1(timestamp + url + method + OAuth-secret). Your receiver recomputes it from the X_Date header, the request URL, the HTTP method and your application secret, and compares. SHA-1 is weak by modern standards, so treat the signature as an authenticity check and not as the only control: also restrict the receiver by source address and keep the endpoint unguessable.
Delivery is at least once, not exactly once, and the documentation is explicit that all incoming events must be consumed for subsequent events in the same group to be delivered. A receiver that returns an error or sits on a request stops the stream for that group, it does not just delay one message. Make the receiver idempotent on shipmentId plus eventType plus timestamp, acknowledge fast, and do the real work on a queue behind it.
No retry policy is published.
Rate limits and pagination
Flipkart publishes no rate limits, no quota headers and no throttling response code. The documented response codes are 200, 202, 400, 403, 404, 422, 500, 503 and 599 (connection timed out), with no 429. That absence is not permission to hammer the API: without a published limit, the safe assumption is that throttling shows up as a 503 or a 599 rather than a clean 429, which is much harder to distinguish from a real outage. Build a client that backs off exponentially on 503, 599 and any 5xx, and that caps concurrency to a handful of connections per seller.
The hard numbers that are published are batch sizes:
Pagination has three different shapes in one API, which is worth writing down once:
- Shipments: follow
nextPageUrlas an absolute URL whilehasMoreis true. - Listings search: send back
next_page_idaspage_idwhilehas_moreis true. - Returns: date windows on
modifiedAfterandmodifiedBefore, no cursor documented.
Practical cadence. Subscribe to notifications and let them drive the pre dispatch work, since a shipment you have not packed is time critical and dispatchByDate is a contractual deadline. Back the notifications with a preDispatch filter poll every ten to fifteen minutes so a dropped event does not cost a late dispatch. Poll postDispatch hourly for delivery status. Pull returns every hour on modifiedAfter. Refresh listings nightly through /listings/v3/search then /listings/v3/details in batches of ten. Request settlement and commission reports once a day and download as soon as status is COMPLETED.
Mapping to the unified model
orders
order_items
listings
inventory
shipments and returns
Settlements map from settled_transaction_ledger, with commission_invoice_transaction_report supplying the fees[] breakdown.
Gaps and open questions
- No sandbox host is published. The best practices page tells you to test in the sandbox, but does not say where it is. This has to come through a support ticket.
- No rate limits, no quota headers and no 429 in the documented response codes. Throttling behaviour is unknown and will have to be measured.
- The full
GET /v2/returnsresponse schema is not reproduced on the reference page, so the exact return field names are unverified. - There is no endpoint that lists a seller's
locationIdvalues, yet almost every write requires one. - The order item
ordered_attimestamp is exposed as a filter (orderDate) but we did not confirm the corresponding response field name. - Payment method (prepaid against cash on delivery) is not clearly exposed on the shipment. It may only be derivable from the invoice or the
orders_report. - The shipment filter request and response samples on this page have field names taken from the official reference but illustrative values. Validate against a live account before writing a parser that assumes types.
- Myntra and Shopsy sit in the same group but are not covered by these APIs. Treat them as separate connectors.
Sources
- Flipkart Marketplace Seller APIs, overview and OAuth
- Order Management API overview and Order Management API Reference
- Order Management Notification Service and Notification Reference
- Listing Management API overview and Listing Management API Reference
- Report Management API overview and Report Management API Reference
- Response codes and Best practices
- Seller FTP for listings