Skip to content

Optimizations

The primary workflow: submit a product image, then poll for the shipping-optimized results.

Try it

Run a real call against POST /api/v1/optimizations. Your key is kept in sessionStorage only — never persisted, never sent to our backend except as the request's Bearer token.

Category

POST /api/v1/optimizations#

Submit a new optimization job. Returns 202 Accepted within ~2 seconds with a job_id you can poll.

Authentication: required (Authorization: Bearer meeship_<token>).

Request — multipart/form-data#

FieldTypeRequiredNotes
imagefileyesjpeg/png/webp, ≤ 10 MB, min 400×400 px, ≤ 50 MP.
categorystringyesSlug (e.g. womens-kurtis). Discover slugs via GET /api/v1/categories.
selling_price_inrintegernoDefaults to 299. Used for the transfer-price calculation.

Request headers#

HeaderPurpose
AuthorizationBearer meeship_<token>
Idempotency-KeyOptional. Any client-chosen string (max 255). Same key within 24h → same job_id.

Response — 202 Accepted#

JSON
{
  "job_id": "8d7e9b3c-1f4a-4d2e-9f50-aabbccdd1122",
  "status": "queued",
  "status_url": "https://api.meeship.in/api/v1/jobs/8d7e...",
  "submitted_at": "2026-05-26T11:42:03Z",
  "category": {
    "slug": "womens-kurtis",
    "name": "Women Kurtis",
    "breadcrumb": "Women Ethnic > Kurtis"
  }
}

Response headers: X-Correlation-Id, X-Credits-Remaining.

Error codes#

StatusCodeMeaning
400invalid_imageBad format, decoding failed, or below the 400×400 min dimension.
400missing_imageImage part was empty.
400invalid_categoryUnknown slug/id. Response includes suggestions array (up to 5).
401unauthorized / invalid_api_keyMissing or revoked key.
402quota_exhaustedCredit balance is 0. Buy a pack or upgrade.
402subscription_expiredSubscription is cancelled or past grace period.
403ip_not_allowedCaller's source IP isn't in this key's allowlist.
413image_too_largeImage exceeds 10 MB.
429rate_limitedExceeded your tier's per-minute submit limit. Response includes Retry-After header.

GET /api/v1/jobs/{job_id}#

Poll a job. Returns the current state and, when terminal, the full result.

Authentication: required. Tenant-scoped — a foreign job_id returns 404, not 403 (we don't leak the existence of other tenants' jobs).

Response — 200 OK#

When status is queued or processing:

JSON
{
  "job_id": "8d7e...",
  "status": "processing",
  "submitted_at": "2026-05-26T11:42:03Z",
  "processing_started_at": "2026-05-26T11:42:09Z",
  "category": { "slug": "womens-kurtis" },
  "credits_charged": 0
}

Response header Retry-After: 5 suggests how long to wait before the next poll.

When status is complete:

JSON
{
  "job_id": "8d7e...",
  "status": "complete",
  "submitted_at": "2026-05-26T11:42:03Z",
  "completed_at": "2026-05-26T11:43:18Z",
  "expires_at": "2026-05-27T11:42:03Z",
  "category": { "slug": "womens-kurtis" },
  "credits_charged": 1,
  "result": {
    "baseline_shipping_charges_inr": 82,
    "variants": [
      {
        "rank": 1,
        "image_url": "https://blob.meeship.in/...",
        "shipping_charges_inr": 55
      }
    ]
  }
}

> ⚠️ Image URLs expire after 24 hours. Each image_url is a signed, > read-only link to Azure Blob Storage and stops resolving at the time > shown in expires_at (24h after completed_at). Download the bytes > within that window and store them in your own system if you need them > longer — re-polling GET /jobs/{id} after expiry returns the same URLs, > which will return 403 from storage.

When status is failed:

JSON
{
  "job_id": "8d7e...",
  "status": "failed",
  "credits_charged": 0,
  "error": {
    "code": "upstream_unavailable",
    "message": "Meesho shipping API returned no valid variants.",
    "retryable": false
  }
}

Job lifecycle#

Code
queued ──► processing ──┬──► complete   (credits_charged = 1)
                        └──► failed     (credits_charged = 0)
                                ↓
                            expired     (24h after complete; image URLs stop resolving)

expires_at in the response is the hard deadline for image_url freshness. The job_id itself remains queryable for longer (we periodically garbage-collect), but the image URLs become unusable after expires_at — download the bytes before then.

Polling rate#

Polling is free (no credits charged) and has a separate, generous rate limit (10× your submit limit). Respect Retry-After; aggressive polling returns 429.


Snippets#

Python (requests)#

Python
import time, requests

API = "https://api.meeship.in/api/v1"
KEY = "meeship_live_..."

# Submit
with open("product.jpg", "rb") as f:
    r = requests.post(
        f"{API}/optimizations",
        headers={"Authorization": f"Bearer {KEY}",
                 "Idempotency-Key": "sku-12345"},
        files={"image": f},
        data={"category": "womens-kurtis", "selling_price_inr": 499},
    )
r.raise_for_status()
job_id = r.json()["job_id"]

# Poll
while True:
    r = requests.get(f"{API}/jobs/{job_id}",
                     headers={"Authorization": f"Bearer {KEY}"})
    r.raise_for_status()
    job = r.json()
    if job["status"] in ("complete", "failed", "expired"):
        break
    time.sleep(int(r.headers.get("Retry-After", "5")))

if job["status"] == "complete":
    for v in job["result"]["variants"]:
        print(v["rank"], v["image_url"], v["shipping_charges_inr"])

JavaScript (fetch)#

JavaScript
const API = 'https://api.meeship.in/api/v1';
const KEY = 'meeship_live_...';

async function optimize(file, category) {
  const fd = new FormData();
  fd.append('image', file);
  fd.append('category', category);

  const submit = await fetch(`${API}/optimizations`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${KEY}`,
      'Idempotency-Key': crypto.randomUUID(),
    },
    body: fd,
  });
  if (!submit.ok) throw new Error(await submit.text());
  const { job_id } = await submit.json();

  while (true) {
    const r = await fetch(`${API}/jobs/${job_id}`, {
      headers: { Authorization: `Bearer ${KEY}` },
    });
    const job = await r.json();
    if (['complete', 'failed', 'expired'].includes(job.status)) return job;
    await new Promise((s) => setTimeout(s, +(r.headers.get('Retry-After') || 5) * 1000));
  }
}

curl#

Shell
# Submit
curl -X POST https://api.meeship.in/api/v1/optimizations \
  -H "Authorization: Bearer meeship_live_..." \
  -H "Idempotency-Key: sku-12345" \
  -F image=@./product.jpg \
  -F category=womens-kurtis \
  -F selling_price_inr=499

# Poll (replace JOB_ID with the value above)
curl -H "Authorization: Bearer meeship_live_..." \
     https://api.meeship.in/api/v1/jobs/JOB_ID