Go-Swift

GoSwift (Swift) Indian shipping and checkout platform, public OpenAPI at app.goswift.in with Bearer tokens, shipments, tracking, NDR and webhooks.

GoSwift, branded simply Swift, is an Indian e-commerce logistics and checkout platform operated by Gosprint Logistics Private Limited of Bengaluru. It bundles three things a direct to consumer brand usually buys separately: multi-carrier shipping with courier allocation and non-delivery handling, a checkout with cash on delivery verification, and analytics with customer engagement. It claims more than 10,000 businesses. Unusually for this segment it publishes a real OpenAPI 3.1 specification, served openly at app.goswift.in/api/docs, which makes it one of the few Indian aggregators you can scope a connector against without a sales call. For a unified commerce database it is a shipments, NDR, RTO and serviceability source, plus an abandoned-checkout source through the checkout product.

At a glance

What it is

Gosprint Logistics Private Limited, Bengaluru, Karnataka, trading as Swift and reachable at goswift.in. The marketing positions it as "India's Top eCommerce Logistics & Checkout Solution" with "a widespread network spanning multiple warehouses across India".

Three product areas:

  • Shipping and fulfilment: order management, courier allocation across vendor partners, warehousing and NDR management.
  • Payments and checkout: a checkout builder, payments and conversion optimisation. The named COD feature is CODify, described as cash on delivery order verification.
  • Analytics and engagement: insights, customer communication and retention.

The RTO story is the commercial hook: an "RTO protection suite" aimed at dropshippers, claimed to improve delivery percentage by 50 percent, plus "Anomaly Detection" with "RTO risk tagging and automated WhatsApp order verification". None of the risk scoring is exposed in the API specification, which is a gap worth noting up front.

Courier partners are not named on the marketing site, but the API returns a vendor field on shipment creation and the webhook examples use "vendor": "BLUEDART", so the model is multi-vendor allocation behind a single Swift tracking identifier. Swift issues its own tracking id (for example 500999A3408005) separate from the vendor waybill number, and the public tracking page is https://app.goswift.in/track/{swift tracking id}.

Four service levels are enumerated in the specification: SURFACE, EXPRESS, NDD (next day delivery) and SDD (same day delivery).

API access

The specification is public and readable without credentials. Calling it is not: you need a client_id "provided by Swift during onboarding" plus a username and password, so the account relationship comes first.

  • Base URL: https://app.goswift.in
  • Specification: https://app.goswift.in/api/swagger/spec.yaml, OpenAPI 3.1, title "Swift API Docs", version 3.8.7 as read on 22 September 2026
  • Support contact: tech-integrations@goswift.in, listed in the specification as "Tech API Support"

Versioning. There is no clean version boundary. The live surface mixes /api/v1/..., /api/v2/..., /integrations/v2/... and /data/v2/... on one host, and the tags in the specification distinguish "Serviceability V2", "NDR V2", "Address V2", "Webhook V2" and "Manifest V2" from unversioned Shipments, Label and Track tags. Shipment creation, cancellation, label and track are still v1 paths. The token endpoint's own note says "This API works with both v1 and v2 APIs", so the two coexist deliberately rather than one superseding the other. Expect the mix to persist and do not assume a v1 path will be retired.

SDKs. None published. The specification is the deliverable, and it is a good one: generate a client from it rather than writing requests by hand.

Errors. A single documented error schema with statusCode, code, message, description and severity, all required. Every endpoint returns it on default. There is no per-endpoint error catalogue, so the code values have to be collected from live traffic.

Authentication

  1. Obtain a client_id, a username and a password from Swift during onboarding.
  2. POST to /integrations/v2/auth/token/{client_id} with a body of username and password. This endpoint itself requires no authentication.
  3. The response carries access_token, token_type (always Bearer), scope (always core:all) and expires_in in seconds, generally 24 hours.
  4. Send Authorization: Bearer <access_token> on every other call.
curl --request POST \
  --url 'https://app.goswift.in/integrations/v2/auth/token/YOUR_CLIENT_ID' \
  --header 'Content-Type: application/json' \
  --data '{ "username": "seller_user", "password": "seller_password" }'
{
  "access_token": "abc123",
  "scope": "core:all",
  "expires_in": 86400,
  "token_type": "Bearer"
}
GET /api/v2/serviceability/560008 HTTP/1.1
Host: app.goswift.in
Authorization: Bearer abc123
Note

The token endpoint is described in the specification as "a caching API and will return the same token for a period of 24h. The expires_in will keep decreasing appropriately with subsequent fetches." So calling it repeatedly does not mint new tokens or invalidate the old one, and the correct pattern is to call it once, cache the token, and refresh when expires_in runs low. Do not call it per request, and do not assume a fresh call gives you a fresh 24 hours.

Scope is a single value, core:all, so there is no least-privilege option: one credential has everything. Multi-seller handling is one client_id, username and password triple per seller, stored against your channel_account_id.

Objects we can read

Base URL https://app.goswift.in.

Orders

No order object in the API. Swift has an internal order identifier, surfaced in webhooks as channelId ("swift order id"), and it carries your order_number through from shipment creation, but there is no endpoint that lists or fetches orders. Read orders from the sales channel connector and join on order_number.

Order items

Accepted on shipment creation as an optional items[] array, described in the specification as "Optional for metadata purposes only". Not readable back through any documented endpoint. The abandoned checkout webhook is the one place line items come back out, with id, name, sku_code, product_id, variant_id, description, images[], quantity, listed_price and tax_inclusive, all sourced from Shopify.

Products and listings

None. Swift holds no catalogue.

Inventory

None.

Shipments and tracking

Tracking. GET /api/v1/track/{id} where id is the Swift tracking id. The specification marks this as an open API: security: [], no token required. That is convenient and also worth flagging, because anyone holding a tracking id can read the shipment.

The response is a track_obj with _id, a track object, an optional edd (estimated delivery timestamp, "only available for picked up shipments") and order_number. The track object carries the current status, ctime (last updated, epoch milliseconds), pickupTime, desc, location, attempts, an optional ndrStatus, an optional ndrActions[] listing the actions currently permitted, and details[], "Details of every status update", each with its own status, ctime, desc, location and ndrStatus.

The status vocabulary is fully enumerated, which is the single most useful thing about this API:

Order Placed, In Transit, Out for Delivery, Delivered, Cancelled, Seller Cancelled, RTO Requested, Seller RTO Requested, RTO In Transit, RTO Delivered, RTO Out for Delivery, RTO Failed, Picked Up, Pickup Cancelled, Pickup Pending, Pickup Scheduled, Lost, Damaged, Shipment Delayed, Not Serviceable, Not Picked, Not Picked - QC Failed, Undelivered, Out for Pickup, RTO Shipment Delayed.

The NDR vocabulary is enumerated too, and it is the best-specified NDR taxonomy of any Indian aggregator read for this project:

Unknown Exception, Customer Unavailable, Rejected by Customer, Delivery Rescheduled, Pickup Rescheduled, Customer Unreachable, Address Issue, Payment Issue, Out Of Delivery Area, Order Already Cancelled, Self Collect, Shipment Seized By Customer, Dispute, Maximum Attempt Reached, Not Attempted, OTP Not Received/OTP Mismatch, OTP Verified Cancellation, On Hold, RTO Delivery Failed.

Note that statuses and NDR statuses are human-readable strings with spaces and mixed case, not codes. Store them verbatim and map in your own layer; do not normalise at ingest.

Serviceability. GET /api/v2/serviceability/{pincode} returns an acknowledgement with status (true if serviceable), the pincode, a remark and a details object:

Four separate booleans for forward and reverse, pickup and drop, is a better model than most, and max_cod_amount per pin code is a genuinely useful field that nothing else in this segment exposes.

There is no rate or pricing endpoint in the specification. A pricing_estimate schema exists but no path references it, which suggests rating is either internal or exposed elsewhere.

Label. POST /api/v1/package/label with {"ids": [...]}, maximum 100 waybill numbers at a time. Returns a PDF as an octet stream, or JSON if json_only=true is passed as a query parameter.

Manifest. POST /data/v2/generate/manifest with the same {"ids": [...]} shape, also capped at 100. Returns JSON with ctime, manifestNumber and manifestDownloadUrl.

Returns and cancellations

Reverse shipments are first-class: create them with payment_mode set to Pickup and a return_reason string.

Warning

The address semantics on a reverse shipment are inverted relative to what actually happens on the ground, and the specification says so explicitly: "Note this is semantically opposite to what is happening on the ground; the drop_location is the customer address and the pickup_location is the seller address." So on a reverse shipment drop_location is still the customer and pickup_location is still the seller, even though the parcel travels the other way. Getting this backwards will send every return to the wrong place.

Reverse with quality check. Set qc_shipment: true and supply product_name (required), plus optional product_sku, product_color, product_size, product_desc, brand_name, product_category, ean_barcode, serial_number, imei_number and product_images. Quality check applies only to payment_mode of Pickup; the specification warns "Do not send qc_details for payment_mode Prepaid and COD." A failed check surfaces as the status Not Picked - QC Failed.

RTO is modelled as its own status family rather than as a separate object: RTO Requested, Seller RTO Requested, RTO In Transit, RTO Out for Delivery, RTO Delivered, RTO Failed, RTO Shipment Delayed.

Payments and settlements

Nothing in the API. There is no COD remittance endpoint, no invoice, no wallet ledger and no charge breakdown. Given that COD is central to the product, this is the largest gap in the specification and the first thing to ask about.

Customers

No customer object. Buyer identity rides on the shipment as consignee_name and the drop_location address block, and on the abandoned checkout webhook as a customer object with phone, name and a full shipping_address. All PII, unmasked.

Locations

  • POST /api/v2/address registers an address, used for "both Pickup and RTO Warehouses". Required fields: alias, phone, address_line1, pincode.
  • GET /api/v2/addresses lists the addresses saved against a user.

The alias is the key mechanism: once registered, a shipment can reference a warehouse by alias alone rather than repeating the full address. The specification spells out the autofill rules: with one registered pickup or return location you can omit the fields entirely; with several, send only {"name": "alias"}; and if return_location is omitted, Swift assumes it is the same as pickup_location. Note the specification also says registering a new pickup or return location may require contacting an account manager ("We do plan to expose an api for this soon"), which sits oddly beside the documented POST /api/v2/address. Verify which is authoritative.

Writing back: listings, price and stock

Not applicable, this is a carrier. Swift owns no listing, price or stock. Catalogue and price writes belong to the sales channel connector.

The write path is shipment creation and cancellation.

Create: PUT /api/v1/package/create. Note the verb, it is a PUT, not a POST.

The shipment schema has an unusually long required list, driven by Indian GST invoicing: tax_value, seller_name, seller_address, seller_gst_tin, consignee_gst_amount, order_number, invoice_number, invoice_date, consignee_name, payment_mode, category_of_goods, products_desc, total_amount, cod_amount, taxable_amount, commodity_value, return_reason, quantity, weight, drop_location, pickup_location, return_location, length, height, width.

Key constraints worth designing around:

  • payment_mode is COD, Prepaid or Pickup, where Pickup means a reverse shipment.
  • total_amount must equal taxable_amount plus tax_value, and the specification defines taxable_amount as "Value of goods after removing tax, i.e: total_amount - tax-value". Both have a minimum of 1.
  • cod_amount has a minimum of 0 and a maximum of 49999. Anything above that cannot be shipped COD through this API.
  • weight is in grams, length, height and width in centimetres, all integers with a minimum of 1.
  • ewbn, the e-way bill number, must match exactly twelve digits.
  • service must be one of SURFACE, EXPRESS, NDD, SDD.
  • templateName selects a pre-defined packaging template from the Swift dashboard. The specification is blunt about the conflict: "Only one of templateName or length, width, height will be accepted" and "Do not send templateName and length, width, height both, there is a higher chance of request rejection." If a template name is sent and not found, the request is rejected outright.
  • what3words_address is accepted as an optional three-word location.

Response:

{
  "status": true,
  "remark": "Successfully created shipment",
  "tracking_id": "500999A3408005",
  "vendor": "XYZ",
  "barcodes": {
    "wbn": "vendor_waybill_plain_text",
    "order": "order_number",
    "cod": "vendor_cod_waybill_plain_text"
  }
}

Three identifiers come back and all three matter: tracking_id is Swift's own id and the key for tracking, NDR and cancellation; barcodes.wbn is the underlying vendor waybill, which is what a customer service agent will find on the carrier's own site; and barcodes.cod is a separate COD waybill that some vendors issue. Store all three.

Cancel: DELETE /api/v1/package/cancel?tracking_id=.... One shipment per call.

NDR action: POST /api/v2/package/ndr with action and wbn (the Swift tracking id, despite the field name). The v2 action enum is Re-Attempt or RTO. A date is required when the action is Re-Attempt, in epoch milliseconds, and the constraint is precise: "should be within seven days of the current day, excluding today". Optional phone (exactly ten digits), address, instructions and links[] for uploaded files.

The older v1 ndr_data schema also had an Edit action for updating address or phone without re-attempting. The v2 enum drops it, so address correction now rides along with Re-Attempt. Use the ndrActions[] array returned on the track response to know which actions a given shipment will actually accept, rather than assuming.

Webhooks and notifications

Full CRUD on subscriptions:

  • GET /api/v2/webhook lists them
  • POST /api/v2/webhook creates one
  • PUT /api/v2/webhook/{webhook_id} updates one

Request fields: url (required), secret (required, 6 to 30 characters), topics[] (required, at least one), active (default true) and alertEmail for failure notifications. The secret is documented as the "Webhook secret to hash the webhook post body with for calculating h-mac", so verification is an HMAC over the raw body with your own secret. The specification does not name the header that carries the signature or the hash algorithm, which is the one important omission; ask tech-integrations@goswift.in before going live.

The alertEmail field is a nice touch: Swift will email you when deliveries fail, which most platforms in this segment do not do.

Topics in the enumerated schema: track_updated, shipment_created, shipment_recreated. The prose documentation adds a fourth, abandoned_checkout, with a full sample body. That discrepancy between the enum and the prose is unresolved; if you need abandoned checkout, confirm it is subscribable.

track_updated:

{
  "ctime": 1657523187604,
  "status": "Delivered",
  "location": "",
  "desc": "Delivered Successfully",
  "attempts": "0",
  "pickupTime": 1655980197000,
  "wbn": "318019134877",
  "id": "501346BN6838925",
  "orderNumber": "41839",
  "edd": 1657523187609
}

Note attempts arrives as a string here but is an integer on the track response. Parse defensively.

shipment_created and shipment_recreated share a shape:

{
  "id": "509271DS0153341",
  "wbn": "3496549343",
  "vendor": "BLUEDART",
  "orderNumber": "RAZNE009",
  "channelId": "66111e20da60dcb528a11cad"
}

shipment_recreated is worth handling explicitly: it means a shipment was re-shipped, so a new Swift tracking id and vendor waybill now supersede the old ones for the same orderNumber. Without handling it you will end up with orphaned shipment rows.

abandoned_checkout carries a full Shopify-shaped cart with items[], token, currency, subtotal, current_total_cart_value, current_total_discount, checkout_url, and a customer object with phone, name and shipping_address. This is the only place Swift emits commerce data rather than logistics data, and it is all PII.

No retry policy is published. Track updates can also be pulled from the open GET /api/v1/track/{id} endpoint, which makes reconciliation cheap: no token needed, one call per tracking id.

Rate limits and pagination

No rate limits are documented anywhere in the specification, and no quota headers are described. Treat that as unknown rather than unlimited.

Documented caps that function as limits:

  • Label and manifest: maximum 100 waybill numbers per request, with uniqueItems: true on the ids array
  • cod_amount: maximum 49999
  • NDR re-attempt date: within seven days of the current day, excluding today
  • Webhook secret: 6 to 30 characters
  • Cancellation: one tracking_id per call

There is no pagination anywhere. GET /api/v2/addresses and GET /api/v2/webhook return plain arrays with no cursor, page or total. That is fine at the scale those objects exist, but it means there is no bulk shipment listing at all: you can only track shipments you already know the id of. A connector therefore has to record every tracking_id at creation time, or depend entirely on shipment_created webhooks, because there is no way to enumerate shipments after the fact.

Mapping to the unified model

orders

No order object. Populate orders from the sales channel and join on order_number, which Swift carries through creation, tracking and every webhook.

order_items

listings, inventory

Not applicable.

shipments

edd on the track response is the estimated delivery timestamp and is only populated once the shipment is picked up. Store it; it is what lets you measure promise versus actual without keeping your own model.

returns

Model RTO separately from a customer-initiated return. An RTO is the forward parcel coming back; a reverse shipment is a separate consignment with its own tracking id.

settlements

Not available. No COD remittance, invoice or charge surface exists in the API.

customers

locations

Gaps and open questions

  • No shipment listing endpoint. There is no way to enumerate shipments. Every tracking_id must be captured at creation or from a shipment_created webhook, or it is lost. This is the single biggest design constraint and it makes the connector stateful from day one.
  • No rate or pricing endpoint. A pricing_estimate schema exists in the specification but no path references it. Rating and cost are therefore invisible, which also means shipments.shipping_cost cannot be filled.
  • No COD remittance surface. For a platform whose headline feature is COD verification and RTO protection, the absence of any settlement, payout or charge endpoint is striking. Ask whether one exists outside the published specification.
  • Webhook signature details are incomplete. The secret is documented as being used "to hash the webhook post body with for calculating h-mac", but neither the header name nor the algorithm is stated. Without both, verification cannot be implemented.
  • Webhook topic enum and prose disagree. The enum lists three topics; the prose documents four, including abandoned_checkout with a full sample. Confirm whether the fourth is subscribable.
  • Address creation is contradictory. POST /api/v2/address is documented, yet the shipment creation notes say to register a new pickup or return location "by contacting your account manager" and that an API is planned. Verify which is live.
  • No rate limits published. Nothing at all, not even a 429 in the error documentation.
  • No sandbox. Nothing in the specification describes a test mode, so shipment creation appears to be live and billable from the first call.
  • RTO risk scores are not exposed. Anomaly Detection, RTO risk tagging and CODify order verification are all marketed features that produce exactly the signals a commerce database wants, and none of them appears in the API.
  • attempts type inconsistency. Integer on the track response, string in the track_updated webhook.
  • Type mixing in the specification. Pincode in the serviceability path is an int32, which will silently drop a leading zero if any Indian pin code ever needed one. Not a live problem today, but a smell.

Sources