Check a customs description in Node.js
Check customs goods descriptions before you ship. Flags the vague wording EU customs (ICS2) rejects, category-only descriptions, product codes and missing materials. Here is the whole call in Node.js, with the output it produced when we ran it.
Before you start
- An API key. Create a free account; it comes with free tokens every month. Put the key in an environment variable so it stays out of your code:
export BLOODWEB_KEY=your_key - Node.js 18 or later. Nothing to install:
fetch,FormDataandBlobare built in. Save the file with the.mjsending soawaitworks at the top level.
The code
Save it as customs-description-check.mjs and run node customs-description-check.mjs.
// Node.js 18 or later: fetch, FormData and Blob are built in.
const url = new URL("https://bloodweb.net/api/v1/customs-description-check");
url.search = new URLSearchParams({ descriptions: "Gifts" });
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.BLOODWEB_KEY}` },
});
if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).error.message}`);
console.log(await res.json());
What you get
Tested 19 October 2026: this exact code ran against our test copy of the API, which runs the same service code as bloodweb.net, and produced this.
The API answers with JSON:
{
"results": [
{
"description": "Gifts",
"level": "bad",
"issues": [
"Too vague. \"gifts\" does not say what is in the parcel, and EU customs (ICS2) rejects descriptions like this."
],
"tips": [
"\"Gift\" is a reason for sending, not a description, and goods a customer paid for are not gifts."
],
"cut": null,
"length": 5
}
],
"summary": {
"good": 0,
"warn": 0,
"bad": 1
}
}
Change the call
Every option the Customs description checker takes. Add or change them the same way as the ones in the code.
descriptionsrequired: One description per line, or a JSON array. Up to 50.max_length: Flag descriptions longer than this many characters and show where they would be cut.
If it fails
A failed call is not charged. The answer is JSON with an error object; the code above prints its message. The usual ones:
- 401
missing_keyorinvalid_key:BLOODWEB_KEYis not set in the shell that runs the code, or the key was revoked. - 400
bad_param: a value is wrong or missing. The message names the parameter. - 402
insufficient_tokens: the balance does not cover the call. Top up in the dashboard. - 429
rate_limited: too many calls at once. Wait the seconds in theRetry-Afterheader and send it again.
Every code and its fix is in the docs.
Next
- The Customs description checker page: every option, the limits, and Try it now in your browser.
- Getting started: keys, errors and rate limits for all the services.