SharkShip, at sharkship.in, is an Indian multi-courier shipping aggregator: sync orders from Shopify, WooCommerce, Wix, OpenCart or EasyEcom, pick a courier, book an AWB, print the label and invoice, raise a pickup, track, work NDRs, handle RTO and weight disputes, and take COD remittance. It carries nothing itself. What makes it unusual for a company this young is that its backend serves a complete, unauthenticated OpenAPI 3.0 document, so the interface can be read precisely rather than inferred. This page is built from that spec.
At a glance
What it is
A young Indian aggregator aimed at high volume D2C brands. The domain sharkship.in was registered on 2025-11-10 through Hostinger, so the business is roughly ten months old at the time of writing. The marketing site positions it as an enterprise-ready unified logistics platform with order sync, automated courier selection, label generation, live tracking, NDR management, weight discrepancy detection, RTO management, finance reconciliation and COD remittance, plus what it calls a Smart Engine for courier allocation.
Published pricing on 2026-09-22 is volume banded and per 500 grams: Lite from 26 rupees for up to 300 orders a month, Pro from 24 rupees for 300 to 1,000 orders, Max from 19 rupees above 1,000 orders, with no subscription fee. All three tiers list the same feature set, and API access is not called out as a paid tier, which suggests it is granted on request rather than sold.
The courier partners are not named on the marketing site, but the spec names them, because a pickup address carries a separate carrier-side address identifier per courier: Delhivery, with distinct identifiers for surface, express and the 0.25, 2, 5, 10 and 20 kilogram integration slabs, Blue Dart surface and express, Shadowfax surface, DTDC surface and express, KimiPost, Shiprocket and Blitz. Shiprocket appearing as a downstream carrier is worth noting: SharkShip resells another aggregator for part of its coverage.
Sales channels are enumerated in the order filter: MANUAL, SHOPIFY, EASYECOM, WOOCOMMERCE, OPENCART, WIX.
In the unified model SharkShip is a source of shipments, returns and settlements, and a convenient but secondary source of orders.
API access
The spec is public. GET https://api.sharkship.in/api-docs returns a Swagger UI page and GET https://api.sharkship.in/api-docs-json returns the OpenAPI document, roughly 260 kilobytes, with 367 paths, both without any credential on 2026-09-22.
The document is not segmented by audience in any enforced way, so read the tag before assuming a route is yours to call. The tag groups and their operation counts:
Nearly two thirds of the published paths are internal admin routes, including impersonation. They are enumerated in a document anyone can fetch. That is an information disclosure issue on SharkShip's side, and it is also a boundary you must respect: build only against the /v1/b2c group, which is the surface they intend sellers to use. Do not call admin or partner routes, and expect them to change without notice.
Version 1.4.6 is declared in the document's info block. There is no changelog, no deprecation policy and no versioned host. The /v1 prefix in the paths is the only version signal, and it has not moved.
Authentication
Bearer JWT. The spec declares exactly one security scheme:
{
"Authorization": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
"in": "header",
"name": "JWT",
"description": "Enter your JWT token obtained from the /auth/login endpoint"
}
}
For a machine client the sequence is:
- Obtain an API key and secret from SharkShip. There is no self-serve issuance route in the spec, and admin routes exist for managing what the document calls a retail API user, so a human at SharkShip creates the credential.
- Exchange them for a token.
POST /v1/auth/api/logintakesApiLoginDto, whose required fields areapi_keyandapi_secret, both strings. This is the onlyAuthroute with no security requirement on it. - Send the token as
Authorization: Bearer <jwt>on every/v1/b2ccall. - Refresh with
GET /v1/auth/refresh_token_loginwhen the token expires. - End the session with
POST /v1/auth/logout.
curl -s -X POST https://api.sharkship.in/v1/auth/api/login \
-H 'Content-Type: application/json' \
-d '{"api_key":"<key>","api_secret":"<secret>"}'
# the token from step 1 goes on every seller call curl -s 'https://api.sharkship.in/v1/b2c/order/fetch/awb?tracking_id=<awb>' \ -H 'Authorization: Bearer <jwt>'
The spec declares no response schema for any operation, including the login. Token lifetime, refresh window, the JSON field the token arrives in and the error shape on a bad credential are all unpublished. Budget an hour with a live sandbox credential to pin these down before designing the refresh job.
Panel users authenticate differently, through POST /v1/auth/login, POST /v1/auth/generate-otp and POST /v1/auth/otp-login, with a separate POST /v1/auth/wix/login for merchants arriving from Wix. Those are not the machine path. Multi-account handling is not described: the natural reading is one key and secret per seller account, with the JWT scoped to it, but nothing states that.
Objects we can read
Orders
The seller API creates orders but does not list them. Listing lives on the panel route GET /v1/order/list, which is the richest filter surface in the spec:
The status vocabulary, taken verbatim from the filter enum, is the single most useful thing in the spec for mapping:
CANCELLED, DISPUTED, TO_BE_PROCESSED, PROCESSED, SHIPPED, DELIVERED, OUT_FOR_DELIVERY, NOT_DELIVERED, RETURNED, RETURNED_IN_TRANSIT, RETURNED_DELIVERED, NDR, RE_ATTEMPTED, LOST, PROCESSING, DELETED, ALL, ALERT, SHOPIFY.
Other order reads: GET /v1/order/single/{orderId}, GET /v1/order/search/{value}, GET /v1/order/failedOrders, GET /v1/order/order_ndr_list, POST /v1/order/export and POST /v1/order/misReport.
Sample response not published. The spec gives every operation a bare 200 or 201 with an empty description and no content block, so no field names on the read side can be quoted honestly.
Order items
Line items exist as a concept: orderDetailsDto carries a lineItems array and there is a DELETE /v1/order/lineItem/{id}. The array is typed as strings in the spec, which is almost certainly a NestJS decorator omission rather than the real shape. Treat the line item schema as unknown.
Products and listings
Not applicable. SharkShip holds no catalogue. Product name, price, quantity, category and an optional product_sku_no ride on the order.
Inventory
Not applicable.
Shipments and tracking
Tracking history is a first-class seller endpoint:
GET /v1/b2c/order/fetch/awb?tracking_id=<awb> Authorization: Bearer <jwt>
tracking_id is a required query string. The panel equivalent is GET /v1/order/fetch/awb. Sample response not published: the spec declares no response body, so the event array shape, the per-scan fields and whether SharkShip normalises carrier codes into its own vocabulary all have to be confirmed against a live call. The order status enum above is the likely target vocabulary.
Active couriers for the authenticated seller come from GET /v1/b2c/courier/courierPartner.
A public buyer-facing tracking page runs at sharkship.in/awb.
Returns and cancellations
RTO is modelled as order status rather than as a separate object: RETURNED, RETURNED_IN_TRANSIT and RETURNED_DELIVERED are order statuses, isRto is an order filter, and the money side appears as GET /v1/finance/transact-return. There is no returns resource. Cancellation on the seller API is PUT /v1/b2c/order carrying UpdateOrderDto, whose only field is an order_ids array; the panel has an explicit DELETE /v1/order. The exact semantics of that PUT are not documented and must be confirmed.
NDR
GET /v1/order/order_ndr_list for counts, isNdr as an order filter, NDR and RE_ATTEMPTED as statuses, and PUT /v1/order/ndr/re-attempt to act, taking ReattemptNdrDto with a required order_ids array and a required updated_delivery_date. The operation id on that route is reattemptEkartOrders, which hints the reattempt path was built for one carrier first; confirm it works across carriers before relying on it.
Weight disputes
A real object, and commercially important. GET /v1/weight-dispute/list, POST /v1/weight-dispute/upload to submit evidence, GET /v1/weight-dispute/getFile/{documentId} to retrieve it. Carriers push disputes in at POST /v1/webhook/weight-dispute; the declared body for Delhivery is courierName, waybill and receivedAt required, plus an optional doc. DISPUTED is also an order status.
Payments and settlements
The best covered area outside orders. All under /v1/finance:
Recharge runs through POST /v1/finance/payment-initiate, POST /v1/finance/payment-gateway-confirm, POST /v1/finance/payment-callback and POST /v1/finance/payment-webhook.
Customers
CreateCustomerDto requires name and address and optionally carries mobile_no and email. All PII. There is no customer list endpoint on the seller API, only POST /v1/customer on the panel side.
Locations
Pickup addresses are the location object, and the seller API owns them:
GET /v1/b2c/address/pickupAddressPOST /v1/b2c/address/pickupAddressDELETE /v1/b2c/address/pickupAddress/{id}- panel only:
PUT /v1/address/pickupAddress/{id}andPATCH /v1/address/pickupAddress/default/{id}
CreateAddressDto requires address_lane1, address_lane2, Pin as a number, city, state and is_rto_same, with optional landmark, name, phone_no and a full parallel RTO address block when is_rto_same is false. It then carries one carrier-side address identifier per courier and weight slab, which is how SharkShip maps its address to each carrier's registered pickup location. Those identifiers are populated by SharkShip during onboarding, not by the caller.
Writing back: listings, price and stock
Not applicable, this is a carrier and aggregator. SharkShip has no catalogue, no price and no stock to update.
The write path is the shipment lifecycle, and the seller API covers it end to end.
Create
POST /v1/b2c/order/create takes CreateOrderDto, which requires four sub-objects:
Inside order, payment_mode is one of COD, PREPAID, PARTIAL_COD; service_type is one of SDD_NDD, PAN_INDIA, SDD, NDD and defaults to PAN_INDIA; cod_amount defaults to 0; and client_orderId, channel_order_id, channel_store and product_sku_no are the fields to carry your own identifiers in. Inside shipment_details, carrier is an orderCourierInfoDto requiring carrierId as a number and base_weight, with an optional courier_type; volumetric_weight requires length, width and height.
Bulk creation exists on the panel side only, at POST /v1/order/create/bulk, with a template at GET /v1/document/bulkImportTemplate. No batch size limit is published.
Label, invoice and manifest
POST /v1/b2c/document/shipping_label takes getShippingLabelDto, a required order_ids array of strings, so labels are fetched in batches. Label layout is configurable through GET and PUT /v1/b2c/document/shipping_label_configuration.
The panel adds POST /v1/document/combined_label_invoice, POST /v1/document/generate_manifestation, POST /v1/document/invoice/download-single, POST /v1/document/invoice/download-bulk, POST /v1/document/order_invoice/bulk and GET /v1/document/getFile/{documentId}.
Rate and serviceability
GET /v1/b2c/order/shipping-rate-retail is the seller API rate call, and it has an unusual signature: three parcel dimensions and the service type go in headers, everything else in the query string.
Panel equivalents are GET /v1/calculator/rates, GET /v1/calculator/shipping-rate and GET /v1/calculator/Shipping-rate-all. Serviceability is implicit in the rate response: a pincode pair with no rate is not serviceable. There is no separate pincode endpoint.
Cancel and NDR reattempt
PUT /v1/b2c/order with order_ids on the seller API; DELETE /v1/order and PUT /v1/order/ndr/re-attempt on the panel.
Pickup request
No explicit pickup request endpoint exists. pickup_date on shipment_details and pickup_details.address_id at creation are the only pickup controls in the spec, so pickups appear to be scheduled implicitly from the booking. Confirm this, because it differs from most Indian aggregators.
Webhooks and notifications
Outbound push exists but a seller cannot configure it alone. The configuration lives behind an admin route, GET and PUT /v1/admin/user/retailApiUser/{id}/webhook, with UpdateWebhookConfigDto requiring webhook_enabled and carrying an optional webhook_url. So the practical sequence is: ask SharkShip to enable push against your API user and register your endpoint. There is an admin console behind it, GET /v1/admin/webhook-service/dashboard, GET /v1/admin/webhook-service/carriers and PATCH /v1/admin/webhook-service/carriers/{slug}, which implies push is enabled per carrier as SharkShip completes each carrier integration.
What is not published: the event types, the request body, any signature or HMAC verification header, and the retry policy. All four must be settled before an endpoint is exposed to the internet. Assume nothing about authenticity until they document a signature.
Inbound webhooks, which SharkShip receives rather than sends, are POST /v1/webhook/shopify, POST /v1/webhook/woocommerce, POST /v1/integration/wix/webhook, POST /v1/webhook/weight-dispute, POST /v1/webhook/whatsapp-confirmation and POST /v1/webhook/ivr-confirmation. The last two are the buyer address confirmation flow that feeds the whatsapp_remark filter.
If push is not available, poll GET /v1/order/list on a rolling startDate and endDate window with status filters. Every 15 to 30 minutes for open shipments, plus a daily sweep for remittance and weight disputes, is a sensible starting cadence.
Rate limits and pagination
No rate limit is published: the spec declares no quota headers and the site states nothing. Treat that as unknown rather than unlimited, and rate limit yourself.
Pagination is offset based on the list routes, skip and total, with total defaulting to 10. Raise it deliberately. The mandatory startDate and endDate on GET /v1/order/list means every sync is naturally a date window, which is the right shape for an incremental pull: walk forward in windows and keep a watermark.
Mapping to the unified model
Gaps and open questions
- No response schemas anywhere. Every operation in the spec declares a bare
200or201with an empty description and no content, so all read-side field names are unknown. This is the single biggest gap and it makes a live test credential essential before implementation. - JWT lifetime, the refresh window and the error shape on an expired token are unpublished.
- Outbound webhook event types, request body and signature verification are unpublished, and enabling push needs a SharkShip administrator.
- The semantics of
PUT /v1/b2c/orderwith onlyorder_idsare ambiguous. It may cancel, it may mark ready to ship. - No explicit pickup request endpoint. Whether pickups are implicit from
pickup_dateneeds confirming. - The NDR reattempt operation id names Ekart specifically, so cross-carrier coverage is uncertain.
- No sandbox host, no
serversblock, no rate limit, no changelog, no deprecation policy. PARTIAL_CODhas no home in the unifiedpayment_methodfield and needs a product decision.- Shiprocket appears as one of SharkShip's downstream carriers, so some shipments are two aggregators deep. That matters for support escalation and for attributing scan delays.
- The company is ten months old and its public OpenAPI document exposes 195 internal admin routes including impersonation. Factor that into a risk assessment before routing COD float through it.
Sources
- SharkShip OpenAPI 3.0 document, fetched 2026-09-22, document version 1.4.6, 367 paths. Every schema, enum, parameter and security definition on this page comes from it
- SharkShip Swagger UI, the rendered form of the same document
- SharkShip homepage, read 2026-09-22, for the product description, feature list and the
/awbpublic tracking page - SharkShip pricing, for the Lite, Pro and Max bands
- Live DNS and HTTP checks on
sharkship.in,api.sharkship.in,app.sharkship.inanddocs.sharkship.in, run 2026-09-22. Note thatdocs.sharkship.inresolves to Vercel but returns DEPLOYMENT_NOT_FOUND, so a documentation site was planned and is not live - whois for
sharkship.in, for the 2025-11-10 creation date