Skip to content
Undrop

Undrop API

Search Undrop from your own programs: send a product's name, a store or image link, or photos, and get back where it sells for less.

Get a key

Get a key

Create a key on your account page, in the API section. You need an account with a confirmed email address.

You can have 3 keys at a time. A key is shown once, when you create it: copy it then. You can revoke a key from the same page; programs that use it stop working at once.

Authentication

Send the key in the Authorization header of every request: Authorization: Bearer ud_….

Use the key from your server only. Never put it in front-end code, a web page or an app you hand out: anyone could read it there. The API sends no CORS headers, so browsers can't call it anyway. If a key leaks, revoke it and create another.

Get the results

A search takes from a few seconds to about a minute and a half. The POST answers at once with 202 Accepted: the search, its status running, and its address in the Location header.

The first answer
HTTP/1.1 202 Accepted
Location: https://undrop.app/api/public/v1/searches/0199de4a-6f3b-7c21-9a8e-5b2d1c0f4e37
Retry-After: 3
Content-Type: application/json; charset=utf-8

{"id": "0199de4a-6f3b-7c21-9a8e-5b2d1c0f4e37", "kind": "price", "status": "running", …, "results": []}

To get the results in one call, add Prefer: wait: the answer waits until the search ends, 110 seconds at most, and comes with 200 OK. Prefer: wait=30 waits 30 seconds at most. If the search is still running when the wait ends, the answer is 202, as without it.

Wait for the results
curl https://undrop.app/api/public/v1/searches \
  -H "Authorization: Bearer $UNDROP_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait" \
  -d '{"query": "wireless earbuds with charging case", "country": "US"}'

Otherwise, read the search at its address until its status is no longer running. While it runs, the answer carries Retry-After: 3: wait that many seconds before you read it again. A key reads only its own searches: any other id answers 404.

Read a search
curl https://undrop.app/api/public/v1/searches/0199de4a-6f3b-7c21-9a8e-5b2d1c0f4e37 \
  -H "Authorization: Bearer $UNDROP_API_KEY"

The answer

A search, in JSON. Its results are the paid listings, in the site's order: the closest match first, then the lowest price.

FieldTypeWhat it is
idstringThe search's id.
kindstringprice, or repair for a replacement part.
statusstringrunning, then succeeded, partial (some sources didn't answer in time), failed, refused (content we don't search) or not_product (no product found).
countrystringWhere the listings are compared for, in two letters.
currencystringThe currency prices are converted to, in three letters.
createdAt, completedAtstring, nullISO 8601 dates in UTC; completedAt is null while the search runs.
errorobject, null{ "code": … } when the search ended without results: one of the codes under Errors.
resultsarrayThe paid listings; empty while the search runs.

Each result:

FieldTypeWhat it is
idstringThe listing's id.
titlestringThe listing's title.
sourcestringThe marketplace, such as aliexpress, temu or amazon.
storestringThe store's name, as the listing gives it.
priceobject, nullamount and currency, in the search's currency when it could be converted. Null when the price can't be shown: Amazon's never are.
imageUrlstring, nullThe listing's photo.
linkstringUndrop's link to the listing. Use it exactly as given.
matchstringHow close it is to the product: same, variant (another option of it), similar, different or unverified.
isSupplierbooleanSold on a supplier marketplace, such as AliExpress or Alibaba, rather than by a retailer.
savingsPctnumber, nullHow much less it costs than the price seen, in percent, for the same product or another option of it.
partobjectA part search only: origin (oem, compatible, used or unknown), verified (an original we can stand behind) and maker.
An answer
{
  "id": "0199de4a-6f3b-7c21-9a8e-5b2d1c0f4e37",
  "kind": "price",
  "status": "succeeded",
  "country": "US",
  "currency": "USD",
  "createdAt": "2026-10-13T14:02:11.482Z",
  "completedAt": "2026-10-13T14:02:39.907Z",
  "error": null,
  "results": [
    {
      "id": "0199de4a-8d20-7e1f-b3c4-2a6e9f1d0c58",
      "title": "Wireless earbuds with charging case, Bluetooth 5.3",
      "source": "aliexpress",
      "store": "AliExpress",
      "price": {
        "amount": 8.49,
        "currency": "USD"
      },
      "imageUrl": "https://images.example/earbuds-white.jpg",
      "link": "https://undrop.app/go/0199de4a-8d20-7e1f-b3c4-2a6e9f1d0c58",
      "match": "same",
      "isSupplier": true,
      "savingsPct": 71.6
    },
    {
      "id": "0199de4a-8d20-7e1f-b3c4-31f07a4be912",
      "title": "Wireless Earbuds, Bluetooth Headphones with Charging Case",
      "source": "amazon",
      "store": "Amazon",
      "price": null,
      "imageUrl": "https://images.example/earbuds-black.jpg",
      "link": "https://undrop.app/go/0199de4a-8d20-7e1f-b3c4-31f07a4be912",
      "match": "variant",
      "isSupplier": false,
      "savingsPct": null
    }
  ]
}

Limits

Each key can start 20 searches a day, counted from midnight UTC, and 10 searches an hour. A search that fails or finds nothing doesn't count against the day. Reading searches has its own limit, 100 reads an hour, so a key out of searches still gets its results. A key can have 3 searches running at once.

These are today's limits for every key, and they may change. Need more for a project? Write to fcarreau@gmail.com: we can raise a key's own limits.

Over a limit, the API answers 429 Too Many Requests, with Retry-After (the seconds to wait) and the reason in details.reason: hourly_limit or daily_quota.

Over the day's limit
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "This key has used today's 20 searches (UTC).",
    "details": {
      "reason": "daily_quota",
      "limit": 20,
      "used": 20,
      "retryAfterSeconds": 35940
    }
  }
}

Errors

An error answers { "error": { "code", "message", "details" } }. Rely on the code: the message is written for people, and may change.

StatusCodeWhen
400VALIDATION_FAILEDA field is missing or wrong, or advanced was asked for.
400URL_NOT_ALLOWEDThe link isn't a public http(s) address.
401UNAUTHORIZEDNo key, or a key that isn't valid or was revoked.
403FORBIDDENThe key's account is suspended.
404NOT_FOUNDNo search with that id for this key.
409SEARCH_IN_PROGRESSThe key already has 3 searches running.
413PAYLOAD_TOO_LARGEThe upload is over 4.4 MB.
415UNSUPPORTED_MEDIAA photo link doesn't lead to an image.
422URL_UNREACHABLEWe couldn't open a photo's link.
429RATE_LIMITEDOver the hourly or the daily limit: see Limits.
503MAINTENANCESearches are paused for maintenance.
503COST_CAP_REACHEDThe service has reached its capacity for the day.
500INTERNALSomething broke on our side. Try again later.

A search that ends without results says why in error.code, such as URL_UNREACHABLE, NOT_A_PRODUCT, REFUSED or ANALYSIS_UNAVAILABLE.

Changelog

v1, October 2026: the first version. Searches by name, link, photos and replacement part; answers with paid links only.