apyhub
Back

Validate ISBN & Book Listing Data API

What it does

Validate ISBN & Book Listing Data helps you check and prepare the identifiers and listing text for a book before it goes on sale. Send an ISBN, a book record, a description or a listing title, and get back a structured result you can use in your own forms, imports and publishing tools.

Use the ISBN endpoint to check whether an ISBN-10 or ISBN-13 is valid. It converts between the two forms and returns the hyphenated versions, the registration group and the barcode digits. Use the ONIX endpoint to turn one book record into an ONIX 3.0 product message, the metadata format distributors and retailers use. It returns the XML and a list of warnings and errors, so you can see what is missing before you send it.

Use the description endpoint to clean a book blurb into the limited HTML that retailers accept. It tells you which tags were removed or converted and whether the text fits the length limit. Use the listing endpoint to check an online shop listing title and tags against the marketplace's rules: title length, repeated symbols, banned characters, tag count and tag length. It returns plain-language findings you can show to a seller before they save.

It fits catalog imports, publishing tools, listing editors and any backend that needs consistent book identifiers and listing data.

▣ ENDPOINT 01 / 04
POST
ISBN checker and converter
https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/isbn

QUICKSTART

GUIDE

Quickstart

Validate an ISBN by sending it in a simple JSON body.

curl -X POST "https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/isbn" \
  -H "apy-token: $APY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"isbn":"9780306406157"}'

What you'll get back

Returns a JSON object with no declared top-level fields in the output schema.

{
  "result": {
    "input": "9780306406157",
    "clean": "9780306406157",
    "kind": "isbn13",
    "wellFormed": true,
    "valid": true,
    "convertedFromCorrected": false,
    "rangesVersion": "2026-10-30",
    "givenCheck": "7",
    "expectedCheck": "7",
    "isbn10": "0306406152",
    "isbn13": "9780306406157",
    "isbn10Hyphenated": "0-306-40615-2",
    "isbn13Hyphenated": "978-0-306-40615-7",
    "groupName": "English language",
    "rangeStatus": "ok",
    "barcodeDigits": "9780306406157"
  }
}
TRY ITLIVE · 10 ATOMS
Loading your default key…
The full key is used to call the gateway and stays in this tab — never sent to orbit or saved.
body*

About this endpoint

What it does

Validates an ISBN sent in the request body and returns a success response. The detailed response shape is not yet defined in the output schema.

Request Body

ParameterTypeMandatoryDescription
isbnStringYesISBN value to validate. String with 1 to 40 characters.

Response

Returns a JSON object with a single result object describing the ISBN you sent, with its check-digit result and the converted and hyphenated forms.

FieldTypeDescription
result.inputstringThe value you sent, exactly as received.
result.cleanstringThe input with spaces, hyphens and any ISBN prefix removed.
result.kindstringThe detected type: isbn13, isbn10 or unknown.
result.wellFormedbooleantrue if the value has the right length and characters for an ISBN.
result.validbooleantrue if the check digit is correct.
result.convertedFromCorrectedbooleantrue when the converted forms were built from a corrected check digit.
result.givenCheckstringThe check digit in your input.
result.expectedCheckstringThe check digit the number should have.
result.isbn10stringThe ISBN-10 form, when one exists.
result.isbn13stringThe ISBN-13 form.
result.isbn10HyphenatedstringThe ISBN-10 with hyphens in the standard places.
result.isbn13HyphenatedstringThe ISBN-13 with hyphens in the standard places.
result.groupNamestringThe registration group, such as English language.
result.rangeStatusstringok when the number falls in an assigned range. Otherwise hyphenation isn't possible.
result.barcodeDigitsstringThe 13 digits to encode in an EAN-13 barcode.
result.rangesVersionstringThe date of the ISBN range data used for hyphenation.
result.errorstringA plain-language reason, present only when the input isn't a usable ISBN.
▣ ENDPOINT 02 / 04
POST
ONIX generator
https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/onix

QUICKSTART

GUIDE

Quickstart

Validate a book listing by sending the required ONIX fields as JSON.

curl -X POST "https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/onix" \
  -H "apy-token: $APY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "The Pragmatic Programmer",
    "contributors": [
      {
        "name": "Andrew Hunt"
      }
    ],
    "isbn": "9780135957059",
    "publisher": "Addison-Wesley Professional",
    "pubDate": "1999-10-30"
  }'

What you'll get back

Returns a JSON object. The response schema does not declare any top-level fields.

{
  "result": {
    "issues": [
      {
        "field": "pageCount",
        "message": "Print editions usually need a page count.",
        "level": "warning"
      },
      {
        "field": "subjects",
        "message": "No subject code. Most retailers and distributors ask for at least one BISAC or Thema code.",
        "level": "warning"
      },
      {
        "field": "description",
        "message": "No description. Retailers normally show it on the product page.",
        "level": "warning"
      }
    ],
    "xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ONIXMessage release=\"3.0\" xmlns=\"http://ns.editeur.org/onix/3.0/reference\">\n  <Header>\n    <Sender>\n      <SenderName>Test Press</SenderName>\n    </Sender>\n    <SentDateTime>20261112T072538Z</SentDateTime>\n  </Header>\n  <Product>\n    <RecordReference>9780306406157</RecordReference>\n    <NotificationType>03</NotificationType>\n    <ProductIdentifier>\n      <ProductIDType>15</ProductIDType>\n      <IDValue>9780306406157</IDValue>\n    </ProductIdentifier>\n    <ProductIdentifier>\n      <ProductIDType>03</ProductIDType>\n      <IDValue>9780306406157</IDValue>\n    </ProductIdentifier>\n    <DescriptiveDetail>\n      <ProductComposition>00</ProductComposition>\n      <ProductForm>BC</ProductForm>\n      <TitleDetail>\n        <TitleType>01</TitleType>\n        <TitleElement>\n          <TitleElementLevel>01</TitleElementLevel>\n          <TitleText>Test Book</TitleText>\n        </TitleElement>\n      </TitleDetail>\n      <Contributor>\n        <SequenceNumber>1</SequenceNumber>\n        <ContributorRole>A01</ContributorRole>\n        <PersonName>Jane Doe</PersonName>\n      </Contributor>\n      <Language>\n        <LanguageRole>01</LanguageRole>\n        <LanguageCode>eng</LanguageCode>\n      </Language>\n    </DescriptiveDetail>\n    <PublishingDetail>\n      <Publisher>\n        <PublishingRole>01</PublishingRole>\n        <PublisherName>Test Press</PublisherName>\n      </Publisher>\n      <PublishingStatus>04</PublishingStatus>\n      <PublishingDate>\n        <PublishingDateRole>01</PublishingDateRole>\n        <Date dateformat=\"00\">20260115</Date>\n      </PublishingDate>\n    </PublishingDetail>\n    <ProductSupply>\n      <Market>\n        <Territory>\n          <RegionsIncluded>WORLD</RegionsIncluded>\n        </Territory>\n      </Market>\n      <SupplyDetail>\n        <Supplier>\n          <SupplierRole>01</SupplierRole>\n          <SupplierName>Test Press</SupplierName>\n        </Supplier>\n        <ProductAvailability>20</ProductAvailability>\n        <Price>\n          <PriceType>01</PriceType>\n          <PriceAmount>9.99</PriceAmount>\n          <CurrencyCode>USD</CurrencyCode>\n        </Price>\n      </SupplyDetail>\n    </ProductSupply>\n  </Product>\n</ONIXMessage>\n"
  }
}
TRY ITLIVE · 10 ATOMS
Loading your default key…
The full key is used to call the gateway and stays in this tab — never sent to orbit or saved.
body*
YYYYMMDD, YYYY-MM-DD or YYYY-MM
contributors*
prices

About this endpoint

What it does

Generates ONIX book-listing data from the submitted book metadata. The request body must include the required book fields, and the endpoint returns a success acknowledgement with no response fields defined in the schema.

Request Body

ParameterTypeMandatoryDescription
isbnStringYesISBN for the book.
titleStringYesBook title.
pricesObject ArrayNoList of price objects. Each item includes amount and currency; type is optional.
prices[].typeStringNoPrice type.
prices[].amountStringYesPrice amount.
prices[].currencyStringYesPrice currency.
pubDateStringYesPublication date. Format: YYYYMMDD, YYYY-MM-DD, or YYYY-MM.
audienceStringNoAudience value.
languageStringNoLanguage code or value.
subjectsObject ArrayNoList of subject objects. Each item includes scheme and code. scheme is limited to bisac or thema.
subjects[].codeStringYesSubject code.
subjects[].schemeENUMYesSubject scheme. Allowed values: bisac, thema.
subtitleStringNoSubtitle.
pageCountStringNoPage count.
publisherStringYesPublisher name.
territoryStringNoTerritory value.
descriptionStringNoLong description.
productFormStringNoONIX form code, for example BC paperback or BB hardback.
availabilityStringNoAvailability value.
contributorsObject ArrayYesList of contributor objects. Each item includes name; role is optional and defaults to A01 (author).
contributors[].nameStringYesContributor name.
contributors[].roleStringNoONIX role code, default A01 (author).
contributors[].invertedStringNoInverted contributor name.
shortDescriptionStringNoShort description.

Response

Returns a JSON object with a single result object containing the ONIX 3.0 message and a list of issues found in the book record.

FieldTypeDescription
result.xmlstringThe ONIX 3.0 product message as XML. Present when the record has no error-level issues.
result.issues[]arrayProblems found in the record. Empty when the record is complete.
result.issues[].fieldstringThe request field the issue is about, such as pageCount or subjects.
result.issues[].messagestringA plain-language description of what to fix or review.
result.issues[].levelstringerror blocks the XML. warning flags missing or questionable data and the XML is still returned.
▣ ENDPOINT 03 / 04
POST
Book description HTML formatter
https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/kdp-description

QUICKSTART

GUIDE

Quickstart

Send your HTML or plain text book description for KDP-friendly cleanup.

curl -X POST "https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/kdp-description" \
  -H "apy-token: $APY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"html": "<h1>Big</h1><p>A gripping <b>debut</b> novel.</p><script>alert(1)</script>"}'

What you'll get back

Returns a JSON object.

{
  "result": {
    "html": "<h4>Big</h4><p>A gripping <b>debut</b> novel.</p>",
    "removed": {
      "script": 1
    },
    "changed": {
      "h1": 1
    },
    "stats": {
      "htmlLength": 49,
      "visible": 26,
      "words": 5,
      "overBy": 0
    },
    "notes": []
  }
}
TRY ITLIVE · 10 ATOMS
Loading your default key…
The full key is used to call the gateway and stays in this tab — never sent to orbit or saved.
body*
HTML to clean to the tags KDP allows
Plain text; blank lines make paragraphs

About this endpoint

What it does

Formats book description content for KDP by taking an input body with either HTML or plain text and returning a cleaned result. The request body supports html, text, and an optional heading level, but the output schema is not yet defined beyond a JSON object wrapper.

Request Body

ParameterTypeMandatoryDescription
htmlStringNoHTML to clean to the tags KDP allows. Maximum length: 200000 characters.
textStringNoPlain text; blank lines make paragraphs. Maximum length: 200000 characters.
headingENUMNoAllowed values: h4, h5, h6.

Response

Returns a JSON object with a single result object containing the cleaned, KDP-ready HTML, a record of what was changed, and length statistics.

FieldTypeDescription
result.htmlstringThe description as HTML that Amazon KDP accepts.
result.removedobjectTags that were stripped, as tag name to count, for example {"script": 1}. Empty when nothing was removed.
result.changedobjectTags that were converted to an allowed tag, as tag name to count, for example {"h1": 1}. Empty when nothing was changed.
result.stats.htmlLengthnumberLength of the returned html, in characters.
result.stats.visiblenumberNumber of characters of text readers will see, without the tags.
result.stats.wordsnumberWord count of the visible text.
result.stats.overBynumberHow many characters the description is over KDP's limit. 0 means it fits.
result.notes[]array of stringsPlain-language issues worth fixing, for example when nothing is bold or a heading. Empty when there are none.
▣ ENDPOINT 04 / 04
POST
Etsy listing checker
https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/etsy-listing-check

QUICKSTART

GUIDE

Quickstart

Check whether an Etsy listing title and optional tags are valid for an ISBN book listing.

curl -X POST "https://api.eu.apyhub.com/freedailypro/validate-isbn-book-listing-data/etsy-listing-check" \
  -H "apy-token: $APY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "Salt & Pepper & Spice Set", "tags": "kitchen, spice rack, gift"}'

What you'll get back

Returns a JSON object. The output schema doesn’t declare any top-level fields, so the response shape is intentionally unspecified here.

{
  "result": {
    "title": {
      "length": 25,
      "front": "Salt & Pepper & Spice Set",
      "findings": [
        {
          "severity": "ok",
          "text": "25 of 140 characters used."
        },
        {
          "severity": "error",
          "text": "The title uses \"&\" 2 times. Etsy allows each of % : & only once in a title."
        },
        {
          "severity": "advice",
          "text": "A very short title leaves search phrases unused. Add what it is, who it is for and one or two details such as material or size."
        }
      ],
      "errors": 1
    },
    "tags": {
      "tags": [
        {
          "tag": "kitchen",
          "length": 7,
          "problems": [],
          "inTitle": false
        },
        {
          "tag": "spice rack",
          "length": 10,
          "problems": [],
          "inTitle": false
        },
        {
          "tag": "gift",
          "length": 4,
          "problems": [],
          "inTitle": false
        }
      ],
      "findings": [
        {
          "severity": "advice",
          "text": "3 of 13 tags used. Each unused tag is a search phrase left on the table."
        }
      ],
      "errors": 0,
      "titleWordsNotInTags": [
        "salt",
        "pepper",
        "set"
      ],
      "cleaned": [
        "kitchen",
        "spice rack",
        "gift"
      ]
    }
  }
}
TRY ITLIVE · 10 ATOMS
Loading your default key…
The full key is used to call the gateway and stays in this tab — never sent to orbit or saved.
body*
Tags separated by commas or new lines

About this endpoint

What it does

Checks Etsy listing data by sending a listing title and optional tags to the endpoint. The response schema is not yet defined, so the exact success payload shape is not documented here.

Request Body

ParameterTypeMandatoryDescription
titleStringYesListing title. Maximum length: 1000 characters.
tagsStringNoTags separated by commas or new lines. Maximum length: 5000 characters.

Response

Returns a JSON object with a single result object holding the title check and the tags check.

FieldTypeDescription
result.title.lengthnumberLength of the title in characters. Etsy allows up to 140.
result.title.frontstringThe first 40 characters of the title, the part buyers see first in search results.
result.title.findings[]arrayFindings about the title.
result.title.findings[].severitystringok, advice or error. error means Etsy's rules are broken.
result.title.findings[].textstringA plain-language description of the finding.
result.title.errorsnumberNumber of error findings in the title.
result.tags.tags[]arrayOne entry per tag, in the order sent, after removing duplicates.
result.tags.tags[].tagstringThe tag text.
result.tags.tags[].lengthnumberLength of the tag in characters. Etsy allows up to 20.
result.tags.tags[].problems[]array of stringsProblems with this tag, such as being too long. Empty when the tag is fine.
result.tags.tags[].inTitlebooleantrue if the tag's words already appear in the title.
result.tags.findings[]arrayFindings about the tag list as a whole, with the same severity and text fields as the title findings.
result.tags.errorsnumberNumber of error findings in the tags.
result.tags.titleWordsNotInTags[]array of stringsWords in the title that no tag covers yet.
result.tags.cleaned[]array of stringsThe tag list with duplicates removed.
▣ COMMON ERRORS

Errors any endpoint can return

400bad_request

Required parameter missing or malformed body.

401unauthorized

API key missing, revoked, or not authorized for this service.

429rate_limited

Your plan's per-second rate exceeded. Retry with exponential backoff.

503upstream_busy

Backend temporarily unavailable. Try again in a few seconds.