Back to blog
Developer working with code on a computer screen

Introducing the Free ISBN Ranges API on ISBNBarcode.org

2 months ago6 min read

We're thrilled to announce an exciting new feature at ISBNBarcode.org — a free ISBN Ranges API! As part of our mission to make ISBN-related tools accessible to everyone, we're now providing free access to our ISBN ranges database through a simple API endpoint. Whether you're a developer, publisher, or book enthusiast, this API empowers you with the data needed for proper ISBN validation and hyphenation—all at no cost.

What's the ISBN Ranges API?

The ISBN Ranges API provides access to the latest ISBN ranges dataset, sourced directly from the ISBN International Agency and updated yearly. This data is critical for breaking down an ISBN-13 into its properly hyphenated components: the prefix (e.g., 978 or 979), registration group, publisher code, publication code, and check digit. With this API, you can integrate ISBN validation and formatting into your projects effortlessly.

API Endpoint:

https://isbnbarcode.org/api/isbn-ranges.json

This returns the complete ISBN ranges dataset in JSON format, ready to use in your applications.

How to Use It

Fetching the data is as simple as making a GET request. Here's a quick example in JavaScript:

fetch('https://isbnbarcode.org/api/isbn-ranges.json')
  .then(response => response.json())
  .then(data => {
    console.log(data); // Start working with the ISBN ranges data
  });

No API key is required, and the data is free for both personal and commercial use. We just ask that you include attribution to ISBNBarcode.org in your project.

Practical Examples: ISBN Hyphenation Code

To help you get started, we've provided two code examples—one in Node.js and another in TypeScript—that use the API to hyphenate ISBN-13 numbers correctly. These scripts fetch the ISBN ranges data, parse it, and format an ISBN into its hyphenated form (e.g., turning 9780306406157 into 978-0-306-40615-7).

Node.js Example

This script uses axios to fetch the data and processes ISBNs asynchronously:

const axios = require('axios');

async function fetchISBNRanges() {
    try {
        const response = await axios.get('https://isbnbarcode.org/api/isbn-ranges.json');
        return response.data;
    } catch (error) {
        throw new Error(`Failed to fetch ISBN ranges: ${error.message}`);
    }
}

function findGroup(prefix, isbn, groups) {
    for (const group of groups) {
        if (group.Prefix.startsWith(prefix)) {
            const groupPrefix = group.Prefix.substring(4);
            if (isbn.startsWith(groupPrefix)) {
                return {
                    group: groupPrefix,
                    rules: group.Rules.Rule
                };
            }
        }
    }
    return null;
}

function findPublisher(isbn, rules) {
    for (const rule of rules) {
        const [rangeStart, rangeEnd] = rule.Range.split('-');
        const length = parseInt(rule.Length);
        
        const rangeStartLength = rangeStart.length;
        const isbnPrefix = isbn.substring(0, rangeStartLength);
        
        if (isbnPrefix >= rangeStart && isbnPrefix <= rangeEnd) {
            const publisher = isbn.substring(0, length);
            return {
                publisher: publisher,
                length: length
            };
        }
    }
    return null;
}

async function formatISBN(isbn) {
    isbn = isbn.replace(/[^0-9X]/g, '');
    if (isbn.length !== 13) {
        throw new Error('Invalid ISBN length. Must be 13 digits.');
    }

    const data = await fetchISBNRanges();
    if (!data || !data.ISBNRangeMessage || !data.ISBNRangeMessage.RegistrationGroups) {
        throw new Error('Invalid ISBN range data structure');
    }

    const prefix = isbn.substring(0, 3);
    const restOfIsbn = isbn.substring(3);

    const groups = data.ISBNRangeMessage.RegistrationGroups.Group;
    const groupInfo = findGroup(prefix, restOfIsbn, groups);
    if (!groupInfo) {
        throw new Error('Unable to determine registration group');
    }

    const publisherInfo = findPublisher(
        restOfIsbn.substring(groupInfo.group.length),
        groupInfo.rules
    );
    if (!publisherInfo) {
        throw new Error('Unable to determine publisher');
    }

    const pubStart = groupInfo.group.length + publisherInfo.publisher.length;
    const publication = restOfIsbn.substring(pubStart, restOfIsbn.length - 1);

    const parts = [
        prefix,
        groupInfo.group,
        publisherInfo.publisher,
        publication,
        isbn.slice(-1)
    ];

    return parts
        .filter(part => part !== '')
        .join('-');
}

// Example usage
async function testHyphenation() {
    const testISBNs = [
        '9780306406157', // Expected: 978-0-306-40615-7
        '9781421571508', // Expected: 978-1-4215-7150-8
        '9791032702284'  // Expected: 979-10-327-0228-4
    ];

    for (const isbn of testISBNs) {
        try {
            const hyphenated = await formatISBN(isbn);
            console.log(`Original: ${isbn}`);
            console.log(`Hyphenated: ${hyphenated}`);
            console.log('---');
        } catch (error) {
            console.error(`Error with ${isbn}: ${error.message}`);
        }
    }
}

testHyphenation().catch(console.error);

TypeScript Example

For those who prefer TypeScript's type safety, here's a version with interfaces and proper error handling:

interface ISBNRanges {
    ISBNRangeMessage: {
        RegistrationGroups: {
            Group: {
                Prefix: string;
                Rules: {
                    Rule: {
                        Range: string;
                        Length: string;
                    }[];
                };
            }[];
        };
    };
}

async function hyphenateISBN(isbn: string): Promise<string> {
    const response = await fetch('https://isbnbarcode.org/api/isbn-ranges.json');
    if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    const data: ISBNRanges = await response.json();
    const cleanISBN = isbn.replace(/[^0-9X]/g, '');
    
    if (cleanISBN.length !== 13) {
        throw new Error('Invalid ISBN length');
    }

    const prefix = cleanISBN.substring(0, 3);
    const restOfIsbn = cleanISBN.substring(3);
    
    // Find matching group
    const group = data.ISBNRangeMessage.RegistrationGroups.Group
        .find(g => g.Prefix.startsWith(prefix) && 
                  restOfIsbn.startsWith(g.Prefix.substring(4)));
    
    if (!group) {
        throw new Error('Invalid registration group');
    }

    const groupPrefix = group.Prefix.substring(4);
    const publisherPart = restOfIsbn.substring(groupPrefix.length);
    
    // Find matching rule
    const rule = group.Rules.Rule.find(r => {
        const [start, end] = r.Range.split('-');
        const pubLength = start.length;
        const pubPrefix = publisherPart.substring(0, pubLength);
        return pubPrefix >= start && pubPrefix <= end;
    });
    
    if (!rule) {
        throw new Error('Invalid publisher code');
    }

    const publisherLength = parseInt(rule.Length);
    const publisher = publisherPart.substring(0, publisherLength);
    const publication = publisherPart.substring(publisherLength);
    
    return [
        prefix,
        groupPrefix,
        publisher,
        publication.slice(0, -1),
        cleanISBN.slice(-1)
    ].join('-');
}

// Example usage
async function test() {
    try {
        const result = await hyphenateISBN('9780306406157');
        console.log(result); // Expected: 978-0-306-40615-7
    } catch (error) {
        console.error('Error:', error);
    }
}

test();

Why This Matters

Proper ISBN hyphenation isn't just about aesthetics—it's about accuracy and compliance with international standards. The ISBN Ranges API ensures your ISBNs are correctly formatted, whether you're:

  • Generating barcodes
  • Validating ISBN data
  • Building publishing tools
  • Managing book databases
  • Creating bibliographic references

Best Practices

When using the API, keep these tips in mind:

  1. Cache the Data

    • The ranges data changes infrequently
    • Consider caching it locally
    • Update your cache yearly
  2. Error Handling

    • Always validate input ISBNs
    • Handle network errors gracefully
    • Provide meaningful error messages
  3. Performance

    • Process ISBNs in batches when possible
    • Implement local caching
    • Consider using Web Workers for large datasets

Get Started Today

Ready to integrate the ISBN Ranges API into your project? Here's how:

  1. Test the API endpoint
  2. Choose your implementation (Node.js or TypeScript)
  3. Adapt the code examples to your needs
  4. Add proper error handling
  5. Test with various ISBN numbers

Support and Feedback

We're committed to maintaining this free service for the publishing community. If you have questions, suggestions, or need help implementing the API, reach out to us through:

  • GitHub Issues
  • Our contact form
  • Developer forums

Looking Forward

This API release is just the beginning. We're planning more features to help streamline ISBN management and book publishing workflows. Stay tuned for updates!


Data provided with attribution to ISBNBarcode.org, powered by the ISBN International Agency.