v1 · Partner API

Partner API for shipping companies

Submit sourcing requests on behalf of your customers, receive priced quotations, upload proof of payment, and stream order-status updates through signed webhooks, all over HTTPS with a single API key.

Overview

The Partner API lets a third-party shipping company or sourcing partner submit orders into our platform programmatically. Each order flows through the same fulfilment pipeline as one created from our web UI, and the partner receives webhook callbacks at every meaningful state change.

Submit orders
Create sourcing requests with one or many destinations.
Receive quotations
Get priced quotes per destination via webhook + email.
Upload files
POST images, PDFs, videos to our S3 bucket, get a permanent URL back.
Discover services
List the catalog of shipping providers we support per country.
Modify & cancel
Edit destinations while the order is still in Processing or Unpaid.
Signed webhooks
HMAC-SHA256 signed event stream for quotations, status and media.
Base URL: https://kuaisourcing.com/api-backAll endpoints below are relative to this base.

Authentication

Every request must include your API key in the x-api-key header. The key identifies which partner account is calling, keep it secret.

http
POST /api/partner/sourcing HTTP/1.1
Host: kuaisourcing.com
Content-Type: application/json
x-api-key: ks_live_yourkeyhere1234567890abcdef
Keep your key secret

Never embed the key in client-side code or commit it to git. Treat it like a password. If exposed, ask your account manager to rotate it, the old key is revoked immediately.

Order lifecycle

An order moves through these states. The order.status_changed webhook fires on every transition.

ProcessingUnpaidPayment pendingPaidIn ProductionPackedShippedIn TransitDelivered to Destination

Terminal off-path statuses: Cancelled, Refunded, Order Rejected, OutOfStock.

Submit a sourcing request

POST/api/partner/sourcing

One request can include multiple destinations. Each destination must declare its shipping service, either from our catalog or self-arranged.

json
{
  "productName": "Bluetooth Earbuds Pro",
  "productImageUrl": "https://yourcdn.com/img.jpg",
  "productURL": "https://supplier-page.example/product/123",
  "category": "Electronics",
  "targetMarket": "Africa",
  "additionalNotes": "Need OEM packaging",

  "airFreight": true,
  "seaFreight": false,
  "byTrain": false,
  "expressDelivery": false,
  "normalDelivery": true,
  "domesticDelivery": "slow",
  "shippingResponsibility": "kuai",

  "destinations": [
    {
      "country": "Gabon",
      "city": "Libreville",
      "address": "1 Example Street",
      "quantity": 50,
      "variants": "[{\"color\":\"Black\",\"quantity\":30},{\"color\":\"White\",\"quantity\":20}]",
      "service": "DHL",
      "recipientName": "Jane Doe",
      "contactNumber": "+241 00 00 00 00"
    },
    {
      "country": "Tunisia",
      "city": "Tunis",
      "quantity": 30,
      "service": "Other ...",
      "customService": "Local forwarder name",
      "recipientName": "John Doe",
      "contactNumber": "+216 00 000 000",
      "isCompanyService": false
    }
  ]
}

Top-level fields

FieldRequiredNotes
productNameyesShort product label
targetMarketyese.g. "Africa"
destinationsyesAt least one entry. Each entry must have country + quantity.
airFreight / seaFreight / byTrainone must be trueIf airFreight is true, also set expressDelivery or normalDelivery.
domesticDeliveryoptional"fast" or "slow" (inside China)
shippingResponsibilityoptional"kuai" / "service" / "self"
productImageUrloptionalMust resolve. Upload via the uploads endpoint first to be safe.

Response ·
201 Created

json
{
  "success": true,
  "data": {
    "orderId": "9f5e2c3a-...",
    "customOrderId": "KS0000",
    "message": "Sourcing request submitted successfully"
  }
}

Use orderId (UUID) for all subsequent calls. customOrderId (KS0001, KS0002, …) is the same sequential id shown in our internal dashboard.

List your orders

GET/api/partner/sourcing?status=Unpaid&details=true&page=0&size=50
ParamDefaultNotes
status(any)Filter by exact status (see lifecycle section)
detailstruefalse for a slimmer payload (no quotations / real images / destinations)
page0Zero-indexed
size100Max 100

Returns a Spring Page of orders (see Get an order for shape).

Get an order

GET/api/partner/sourcing/{orderId}
GET/api/partner/sourcing/by-order-id/{customOrderId}

Either form returns the same payload.

json
{
  "success": true,
  "data": {
    "id": "9f5e2c3a-...",
    "customOrderId": "KS0000",
    "productName": "Bluetooth Earbuds Pro",
    "status": "Unpaid",
    "formCreationDate": "2026-05-10T08:14:32",
    "lastUpdated": "2026-05-13T11:02:08",
    "realImages": [
      { "id": "...", "image": "https://files.example.com/uploads/real-1.jpg",  "addedAt": "2026-05-13T10:55:00" },
      { "id": "...", "image": "https://files.example.com/uploads/demo.mp4",   "addedAt": "2026-05-13T11:00:00" }
    ],
    "destinations": [
      {
        "id": "d4...",
        "country": "Gabon",
        "city": "Libreville",
        "quantity": 50,
        "service": { "name": "DHL", "recipientName": "Jane Doe" },
        "quotation": {
          "totalCost": 1840.00,
          "unitPrice": 35.00,
          "internationalShippingCost": 90.00,
          "deliveryCostInChina": 70.00,
          "extraFees": 0.00
        }
      }
    ]
  }
}

Modify an order

PUT/api/partner/sourcing/{orderId}

Same body shape as submit. Pass each destination's id back to update it in place (keeps the linked quotation attached). Destinations not in the payload are removed; new ones (no id) are created.

Editable only when the status is Processing or Unpaid. Any other status returns 409 Conflict.

Upload a file

POST/api/partner/uploads

Multipart form. Returns a permanent S3 URL you can reuse as productImageUrl, proof-of-payment url, etc.

bash
curl -X POST https://kuaisourcing.com/api-back/api/partner/uploads \
  -H "x-api-key: $KEY" \
  -F "file=@receipt.pdf" \
  -F "purpose=proof-of-payment"

# Response
{
  "success": true,
  "data": {
    "url": "https://files.example.com/uploads/receipt.pdf",
    "size": 27695,
    "contentType": "application/pdf"
  }
}

Accepted: jpg, jpeg, png, webp, pdf, mp4, mov, webm. Max 25 MB.

Submit proof of payment

POST/api/partner/sourcing/{orderId}/proof-of-payment

Attach a receipt to an existing order. Upload the file via the uploads endpoint first and pass the returned URL here.

json
{
  "country": "Gabon",
  "url": "https://files.example.com/uploads/receipt.pdf",
  "paymentNote": "Bank transfer EUR to USD, reference KS0000"
}

On success the order's status auto-moves Unpaid → Payment pending and an order.status_changed webhook fires.

List available services

Deduplicated by name (case-insensitive). One service can operate in many countries, each row shows the coverage list.

GET/api/partner/services
json
{
  "success": true,
  "data": [
    { "id": "00000000-0000-4000-8000-000000000001", "name": "Example Freight Co", "countries": ["Morocco"] },
    { "id": "00000000-0000-4000-8000-000000000002", "name": "Sample Logistics",   "countries": ["Senegal", "Madagascar"] },
    { "id": "00000000-0000-4000-8000-000000000003", "name": "Demo Shipping Line", "countries": ["Spain"] }
  ]
}

Service selection rules

Field passedBehaviour
serviceIdPreferred, unambiguous, links to that catalog row
serviceName match, case-insensitive. "DHL" = "dhl" = "Dhl".
service: "Other ..."See self-arranged shipping, extra fields required.
Anything else400 with "Service 'X' is not in our catalog…"

Self-arranged shipping

When you handle the shipping yourself, your own courier, a local forwarder, or personal pickup, set service: "Other ..." on the destination and provide the same fields a normal user would fill in our UI.

FieldRequiredPurpose
customService
yes
Free-text forwarder / courier name (e.g. "My local Tunis forwarder")
recipientName
yes
Person receiving at destination
contactNumber
yes
Recipient phone, used by the local courier
isCompanyServiceoptionalDefault false. Set true for registered company forwarders.
address, cityoptionalInherited from the destination, also used as the shipping address.

These rows are flagged userSubmitted=true server-side, so they never appear in the shared services catalog.

Missing any required field returns 400 with a pointer to this section.

Webhooks

Configure a webhook URL when your API key is provisioned. We deliver events asynchronously with HMAC-SHA256 signatures and retry on failure.

EventFired when…
quotation.createdAdmin issues a priced quotation on one of your destinations
quotation.updatedAn existing quotation is edited
order.status_changedStatus moves (e.g. Unpaid → Paid → In Production → Shipped)
realimages.addedPhotos / videos of the actual product are uploaded

If a notificationEmail is also configured on your key, the same events trigger a parallel email digest. Either channel is optional.

Delivery + retries

Best-effort. We retry on non-2xx responses with exponential backoff (1s, 2s, 4s, 8s, 16s). Respond 2xx within 10 seconds or we treat the attempt as a failure.

Error format

All errors share the same envelope. The HTTP status is meaningful, your client should branch on it before reading the body.

json
HTTP 400 Bad Request
{
  "success": false,
  "data": null,
  "error": "destinations: At least one destination is required",
  "timestamp": "2026-05-18T11:42:03.581"
}
CodeMeaning
400Validation failed, see the error field for the specific issue. Don't retry without fixing.
401Missing or invalid x-api-key
403Key revoked or quota exceeded
404Order or resource not found (or not owned by your key)
409Order in a non-editable status, can't modify
429Rate limit, back off and retry
500Server error, safe to retry with exponential backoff

Endpoint cheatsheet

Method · PathWhat it does
POST /api/partner/sourcingCreate sourcing request
GET /api/partner/sourcingList your orders (paginated, filterable)
GET /api/partner/sourcing/{orderId}Fetch one order (full detail)
GET /api/partner/sourcing/by-order-id/{customOrderId}Same, by KS code
PUT /api/partner/sourcing/{orderId}Modify (only Processing / Unpaid)
POST /api/partner/uploadsUpload file → permanent S3 URL
POST /api/partner/sourcing/{orderId}/proof-of-paymentAttach receipt; status moves Unpaid → Payment pending
GET /api/partner/servicesList the shipping-services catalog
Want to integrate?
Email with your company name + the webhook URL you'll receive on. We provision keys in less than 24 hours.
Status & uptime
We aim for 99.9% on the API. If you see persistent 5xx errors or webhook silence, email contact@kuaisourcing.com.
Kuai Sourcing: China Sourcing & Freight to 85+ Countries