{"id":18369168,"url":"https://github.com/ideal-postcodes/core-interface","last_synced_at":"2025-07-15T06:33:15.028Z","repository":{"id":34923457,"uuid":"184418219","full_name":"ideal-postcodes/core-interface","owner":"ideal-postcodes","description":"Ideal Postcodes JavaScript API client interface implementation","archived":false,"fork":false,"pushed_at":"2025-05-05T12:48:51.000Z","size":4937,"stargazers_count":2,"open_issues_count":10,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-09T02:13:35.547Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://core-interface.ideal-postcodes.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ideal-postcodes.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-05-01T13:12:56.000Z","updated_at":"2021-12-28T11:17:39.000Z","dependencies_parsed_at":"2024-06-19T02:58:20.578Z","dependency_job_id":"f95e68ba-74a0-4388-918f-00ce335aeeb1","html_url":"https://github.com/ideal-postcodes/core-interface","commit_stats":{"total_commits":845,"total_committers":10,"mean_commits":84.5,"dds":0.4686390532544379,"last_synced_commit":"2d01206bd0f5e6f2a111c05270d5b4163f4b9b0b"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/ideal-postcodes/core-interface","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ideal-postcodes%2Fcore-interface","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ideal-postcodes%2Fcore-interface/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ideal-postcodes%2Fcore-interface/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ideal-postcodes%2Fcore-interface/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ideal-postcodes","download_url":"https://codeload.github.com/ideal-postcodes/core-interface/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ideal-postcodes%2Fcore-interface/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265414003,"owners_count":23760911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T23:28:38.115Z","updated_at":"2025-07-15T06:33:14.967Z","avatar_url":"https://github.com/ideal-postcodes.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"https://img.ideal-postcodes.co.uk/Ideal%20Postcodes%20Core%20Logo@3x.png\" alt=\"Ideal Postcodes Core Interface\"\u003e\n\u003c/h1\u003e\n\n\u003e JavaScript API for api.ideal-postcodes.co.uk\n\n[![CI](https://github.com/ideal-postcodes/core-interface/actions/workflows/ci.yml/badge.svg)](https://github.com/ideal-postcodes/core-interface/actions/workflows/ci.yml)\n![Cross Browser Testing](https://github.com/ideal-postcodes/core-interface/workflows/Cross%20Browser%20Testing/badge.svg?branch=saucelabs)\n[![Release](https://github.com/ideal-postcodes/core-interface/workflows/Release/badge.svg)](https://github.com/ideal-postcodes/core-interface/actions)\n[![codecov](https://codecov.io/gh/ideal-postcodes/core-interface/branch/master/graph/badge.svg)](https://codecov.io/gh/ideal-postcodes/core-interface)\n![Dependency Status](https://david-dm.org/ideal-postcodes/core-interface.svg)\n\n[![npm version](https://badge.fury.io/js/%40ideal-postcodes%2Fcore-interface.svg)](https://badge.fury.io/js/%40ideal-postcodes%2Fcore-interface)\n![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@ideal-postcodes/core-interface.svg?color=%234c1\u0026style=popout)\n![npm bundle size (scoped)](https://img.shields.io/bundlephobia/minzip/@ideal-postcodes/core-interface.svg?color=%234c1\u0026style=popout)\n[![install size](https://packagephobia.now.sh/badge?p=@ideal-postcodes/core-interface)](https://packagephobia.now.sh/result?p=@ideal-postcodes/core-interface)\n\n`@ideal-postcodes/core-interface` is an environment agnostic implementation of the Ideal Postcodes JavaScript API client interface.\n\nIf you are looking for the browser or Node.js client which implements this interface, please check out the [downstream clients links](#downstream-clients).\n\n## Links\n\n- [API Documentation](https://core-interface.ideal-postcodes.dev/)\n- [npm Module](https://www.npmjs.com/package/@ideal-postcodes/core-interface)\n- [GitHub Repository](https://github.com/ideal-postcodes/core-interface)\n- [Typings Repository](https://github.com/ideal-postcodes/openapi)\n- [Fixtures Repository](https://github.com/ideal-postcodes/api-fixtures)\n\n## Downstream Clients\n\n- [Browser Client Repository](https://github.com/ideal-postcodes/core-browser)\n- [Bundled Browser Client Repository](https://github.com/ideal-postcodes/core-browser-bundled)\n- [Node.js Client Repository](https://github.com/ideal-postcodes/core-node)\n- [Axios-backed Client Repository](https://github.com/ideal-postcodes/core-axios)\n\n## Documentation\n\n- [Usage \u0026 Configuration](#usage)\n- [Quick Methods](#quick-methods)\n- [Resource Methods](#resource-methods)\n- [Error Handling](#error-handling)\n\n### Methods\n\n#### Usage\n\nTo install, pick one of the following based on your platform\n\n```bash\n# For browser client\nnpm install @ideal-postcodes/core-browser\n\n# For node.js client\nnpm install @ideal-postcodes/core-node\n\n# For generic interface (you need to supply your own HTTP agent)\nnpm install @ideal-postcodes/core-interface\n```\n\nInstantiate a client with\n\n```javascript\nimport { Client } from \"@ideal-postcodes/core-\u003cpackage-type\u003e\";\n\nconst client = new Client({ api_key: \"iddqd\" });\n\n// Only api_key is required by core-node and core-browser - all others are optional\n// The agentless interface requires explicit configuration\n```\n\n[Client configuration options](https://core-interface.ideal-postcodes.dev/interfaces/client.config)\n\n---\n\n#### Quick Methods\n\nThe library exposes a number of simple methods to get at the most common tasks when interacting with the API\n\n- [Lookup a Postcode](#lookup-a-postcode)\n- [Search for an Address](#search-for-an-address)\n- [Search for an Address by UDPRN](#search-for-an-address-by-udprn)\n- [Search for an Address by UMPRN](#search-for-an-address-by-umprn)\n- [Check Key Usability](#check-key-usability)\n\n#### Lookup a Postcode\n\nReturn addresses associated with a given `postcode`\n\nInvalid postcodes (i.e. postcode not found) return an empty array `[]`\n\n```javascript\nimport { lookupPostcode } from \"@ideal-postcodes/core-browser\";\n\nconst postcode = \"id11qd\";\n\nlookupPostcode({ client, postcode }).then(addresses =\u003e {\n  console.log(addresses);\n  {\n    postcode: \"ID1 1QD\",\n    line_1: \"2 Barons Court Road\",\n    // ...etc...\n  }\n});\n```\n\n`lookupPostcode` [docs](https://core-interface.ideal-postcodes.dev/modules/helper_methods#lookupPostcode)\n\n#### Search for an Address\n\nReturn addresses associated with a given `query`\n\n```javascript\nimport { lookupAddress } from \"@ideal-postcodes/core-browser\";\n\nconst query = \"10 downing street sw1a\";\n\nlookupAddress({ client, query }).then(addresses =\u003e {\n  console.log(addresses);\n  {\n    postcode: \"SW1A 2AA\",\n    line_1: \"Prime Minister \u0026 First Lord Of The Treasury\",\n    // ...etc...\n  }\n});\n```\n\n`lookupAddress` [docs](https://core-interface.ideal-postcodes.dev/modules/helper_methods#lookupAddress)\n\n#### Search for an Address by UDPRN\n\nReturn address for a given `udprn`\n\nInvalid UDPRN will return `null`\n\n```javascript\nimport { lookupUdprn } from \"@ideal-postcodes/core-browser\";\n\nconst udprn = 23747771;\n\nlookupUdprn({ client, udprn }).then(address =\u003e {\n  console.log(address);\n  {\n    postcode: \"SW1A 2AA\",\n    line_1: \"Prime Minister \u0026 First Lord Of The Treasury\",\n    // ...etc...\n  }\n});\n```\n\n`lookupUdprn` [docs](https://core-interface.ideal-postcodes.dev/modules/helper_methods#lookupUdprn)\n\n#### Search for an Address by UMPRN\n\nReturn address for a given `umprn`\n\nInvalid UMPRN will return `null`\n\n```javascript\nimport { lookupUmprn } from \"@ideal-postcodes/core-browser\";\n\nconst umprn = 50906066;\n\nlookupUmprn({ client, umprn }).then(address =\u003e {\n  console.log(address);\n  {\n    postcode: \"CV4 7AL\",\n    line_1: \"Room 1, Block 1 Arthur Vick\",\n    // ...etc...\n  }\n});\n```\n\n`lookupUmprn` [docs](https://core-interface.ideal-postcodes.dev/modules/helper_methods#lookupUmprn)\n\n#### Check Key Usability\n\nCheck if a key is currently usable\n\n```javascript\ncheckKeyUsability({ client }).then((key) =\u003e {\n  console.log(key.available); // =\u003e true\n});\n```\n\n`checkKeyUsability` [docs](https://core-interface.ideal-postcodes.dev/modules/helper_methods#checkKeyUsability)\n\n---\n\n#### Resources\n\nResources defined in [the API documentation](https://ideal-postcodes.co.uk/documentation) are exported by the library. Each resource exposes a method (`#retrieve`, `#list`, etc) which maps to a resource action.\n\nThese methods expose a low level interface to execute HTTP requests and observe HTTP responses. They are ideal if you have a more complex query or usecase where low level access would be useful.\n\nResource methods return a promise with a [HTTP response object type](https://core-interface.ideal-postcodes.dev/interfaces/httpresponse.html).\n\n#### Retrieve\n\nRequesting a resource by ID (e.g. a postcode lookup for postcode with ID \"SW1A 2AA\") maps to the `#retrieve` method.\n\nThe first argument is the client object. The second is the resource ID. The last argument is an object which accepts `header` and `query` attributes that map to HTTP header and the request querystring.\n\n```javascript\nresourceName.retrieve(client, \"id\", {\n  query: {\n    api_key: \"foo\",\n    tags: \"this,that,those\",\n    licensee: \"sk_99dj3\",\n  },\n  header: {\n    \"IDPC-Source-IP\": \"8.8.8.8\",\n  },\n  timeout: 5000,\n});\n```\n\n#### List\n\nRequesting a resource endpoint (e.g. an address query to `/addresses`) maps to the `#list` method.\n\n```javascript\nresourceName.list(client, {\n  query: {\n    api_key: \"foo\",\n    query: \"10 downing street\",\n  },\n  header: {\n    \"IDPC-Source-IP\": \"8.8.8.8\",\n  },\n  timeout: 5000,\n});\n```\n\nThe first argument is the client. The second is an object which accepts `header` and `query` attributes that map to HTTP header and the request querystring.\n\n#### Custom Actions\n\nSome endpoints are defined as custom actions, e.g. `/keys/:key/usage`. These can be invoked using the name of the custom action.\n\nE.g. for [key usage data extraction](https://ideal-postcodes.co.uk/documentation/keys#usage)\n\n```javascript\nkeys.usage(client, api_key, {\n  query: {\n    tags: \"checkout,production\",\n  },\n  header: {\n    Authorization: 'IDEALPOSTCODES user_token=\"foo\"',\n  },\n  timeout: 5000,\n});\n```\n\n---\n\n#### Resource Methods\n\nListed below are the available resources exposed by the library:\n\n- [Postcodes](#postcodes)\n- [Addresses](#addresses)\n- [Autocomplete](#autocomplete)\n- [UDPRN](#udprn)\n- [UMPRN](#umprn)\n- [Keys](#keys)\n\n#### Postcodes\n\nRetrieve addresses for a postcode.\n\n```javascript\nimport { postcodes } from \"@ideal-postcodes/core-browser\";\npostcodes\n  .retrieve(client, \"SW1A2AA\", {\n    header: {\n      Authorization: 'IDEALPOSTCODES api_key=\"iddqd\"',\n    },\n  })\n  .then((response) =\u003e {\n    const addresses = response.body.result;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[Postcode resource HTTP API documentation](https://ideal-postcodes.co.uk/documentation/postcodes)\n\n[Postcode resource docs](https://core-interface.ideal-postcodes.dev/interfaces/postcoderesource.html)\n\n#### Addresses\n\nSearch for an address\n\n```javascript\nimport { addresses } from \"@ideal-postcodes/core-browser\";\n\naddresses\n  .list(client, {\n    query: {\n      query: \"10 Downing street\",\n    },\n    header: {\n      Authorization: 'IDEALPOSTCODES api_key=\"iddqd\"',\n    },\n  })\n  .then((response) =\u003e {\n    const addresses = response.body.result.hits;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[Address resource HTTP API documentation](https://ideal-postcodes.co.uk/documentation/addresses)\n\n[Address resource client docs](https://core-interface.ideal-postcodes.dev/modules/resources_addresses.html)\n\n#### Autocomplete\n\nAutocomplete an address given an address partial\n\n```javascript\nimport { autocomplete } from \"@ideal-postcodes/core-browser\";\n\nautocomplete\n  .list(client, {\n    query: {\n      query: \"10 Downing stre\",\n    },\n    header: {\n      Authorization: 'IDEALPOSTCODES api_key=\"iddqd\"',\n    },\n  })\n  .then((response) =\u003e {\n    const suggestions = response.body.result.hits;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[Autocomplete resource HTTP API documentation](https://ideal-postcodes.co.uk/documentation/autocomplete)\n\n[Autocomplete resource client docs](https://core-interface.ideal-postcodes.dev/modules/resources_autocomplete.html)\n\n#### UDPRN\n\nRetrieve an address given a UDPRN\n\n```javascript\nimport { udprn } from \"@ideal-postcodes/core-browser\";\n\nudprn\n  .retrieve(client, \"12345678\", {\n    header: {\n      Authorization: 'IDEALPOSTCODES api_key=\"iddqd\"',\n    },\n  })\n  .then((response) =\u003e {\n    const address = response.body.result;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[UDPRN resource HTTP API documentation](https://ideal-postcodes.co.uk/documentation/udprn)\n\n[UDPRN resource client docs](https://core-interface.ideal-postcodes.dev/modules/resources_udprn.html)\n\n#### UMPRN\n\nRetrieve a multiple residence premise given a UMPRN\n\n```javascript\nimport { umprn } from \"@ideal-postcodes/core-browser\";\n\numprn\n  .retrieve(client, \"87654321\", {\n    header: {\n      Authorization: 'IDEALPOSTCODES api_key=\"iddqd\"',\n    },\n  })\n  .then((response) =\u003e {\n    const address = response.body.result;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[UMPRN resource HTTP API documentation](https://ideal-postcodes.co.uk/documentation/umprn)\n\n[UMPRN resource client docs](https://core-interface.ideal-postcodes.dev/modules/resources_umprn.html)\n\n#### Keys\n\nFind out if a key is available\n\n```javascript\nimport { keys } from \"@ideal-postcodes/core-browser\";\n\nkeys\n  .retrieve(client, \"iddqd\", {})\n  .then((response) =\u003e {\n    const { available } = response.body.result;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[Method docs](https://core-interface.ideal-postcodes.dev/modules/resources_keys.html#retrieve)\n\nGet private information on key (requires user_token)\n\n```javascript\nimport { keys } from \"@ideal-postcodes/core-browser\";\n\nkeys\n  .retrieve(client, \"iddqd\", {\n    header: {\n      Authorization: 'IDEALPOSTCODES user_token=\"secret-token\"',\n    },\n  })\n  .then((response) =\u003e {\n    const key = response.body.result;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[Method docs](https://core-interface.ideal-postcodes.dev/modules/resources_keys.html#retrieve)\n\nGet key usage data\n\n```javascript\nimport { keys } from \"@ideal-postcodes/core-browser\";\n\nkeys\n  .usage(client, \"iddqd\", {\n    header: {\n      Authorization: 'IDEALPOSTCODES user_token=\"secret-token\"',\n    },\n  })\n  .then((response) =\u003e {\n    const key = response.body.result;\n  })\n  .catch((error) =\u003e logger(error));\n```\n\n[Method docs](https://core-interface.ideal-postcodes.dev/modules/resources_keys.html#usage)\n\n[Keys resource HTTP API documentation](https://ideal-postcodes.co.uk/documentation/keys)\n\n[Key resource client docs](https://core-interface.ideal-postcodes.dev/modules/resources_keys.html)\n\n---\n\n#### Error Handling\n\nThis library exports a static variable `errors` which contains custom error constructors that wrap specific API errors. These constructors can be used to test for specific cases using the `instanceof` operator.\n\nFor example:\n\n```javascript\nconst { IdpcInvalidKeyError } = Client.errors;\n\ntry {\n  const addresses = await lookupPostcode({ client, postcode: \"SW1A2AA\" });\n} catch (error) {\n  if (error instanceof IdpcInvalidKeyError) {\n    // Handle an invalid key error\n  }\n}\n```\n\nNot all specific API errors will be caught. If a specific API error does not have an error constructor defined, a more generic error (determined by the HTTP status code) will be returned.\n\nFor example:\n\n```javascript\nimport {\n  IdpcRequestFailedError,\n  lookupPostcode,\n} from \"@ideal-postcodes/core-browser\";\n\ntry {\n  const addresses = await lookupPostcode({ client, postcode: \"SW1A2AA\" });\n} catch (error) {\n  if (error instanceof IdpcRequestFailedError) {\n    // IdpcRequestFailedError indicates a 402 response code\n    // Possibly the key balance has been depleted\n  }\n}\n```\n\nYou may view a [sketch of the error prototype chain](#error-prototype-chain).\n\n---\n\n### Core Interface Errors\n\nFor more advanced use cases, this core-interface library provides:\n\n- Class implementations for [Ideal Postcodes API errors](https://core-interface.ideal-postcodes.dev/classes/errors.idpcapierror) that inherit from `Error`\n- A [parser](https://core-interface.ideal-postcodes.dev/modules/errors#parse) that converts raw error data into one of these error instances\n\n#### Error Usage\n\nAside from inspecting the HTTP request status code and/or JSON body response codes, you may also test for specific error instances.\n\nErrors that don't inherit from [`IdealPostcodesError`](https://core-interface.ideal-postcodes.dev/classes/errors.idealpostcodeserror) would indicate some kind of error external to the API (e.g. bad network, request timeout).\n\n```javascript\nimport { errors } from \"@ideal-postcodes/core-browser\";\nconst { IdpcPostcodeNotFoundError } = errors;\n\n// Handle a specific error\nif (error instanceof IdpcPostcodeNotFoundError) {\n  // You got yourself an invalid API Key\n}\n\n// Alternatively use a switch statement\nswitch (true) {\n  case error instanceof IdpcPostcodeNotFoundError:\n  // You got yourself an invalid API Key\n  default:\n  // Default error handling path\n}\n```\n\n#### Error Prototype Chain\n\nAll errors inherit from JavaScript's `Error` prototype.\n\nErrors are grouped by HTTP status code classes.\n\nSpecific errors may be supplied for the following reasons:\n\n- Convenience. They are frequently tested for (e.g. invalid postcode, postcode not found)\n- Useful for debug purposes during the implementation stages\n\n```javascript\nPrototype Chain\n\n# Parent class inherits from Javascript Error. Returned if no JSON Response body\nIdealPostcodesError \u003c Error\n|\n|- IdpcApiError # Generic Error Class, returned if JSON response body present\n   |\n   |- IdpcBadRequestError          # 400 Errors\n   |- IdpcUnauthorisedError        # 401 Errors\n   |- IdpcRequestFailedError       # 402 Errors\n   |  |- IdpcBalanceDepletedError\n   |  |- IdpcLimitReachedError\n   |\n   |- IdpcResourceNotFoundError    # 404 Errors\n   |  |- IdpcPostcodeNotFoundError\n   |  |- IdpcKeyNotFoundError\n   |  |- IdpcUdprnNotFoundError\n   |  |- IdpcUmprnNotFoundError\n   |\n   |- IdpcServerError              # 500 Errors\n```\n\n#### Error Parser\n\nThe error parser consumes a HTTP API response and returns the correct error instance.\n\n```javascript\nimport { errors } from \"@ideal-postcodes/core-browser\";\nconst { parse, IdpcPostcodeNotFoundError } = errors;\n\nconst invalidPostcodeUrl = \"https://api.ideal-postcodes.co.uk/v1/postcodes/bad_postcode?api_key=iddqd\"\n\nconst response = await fetch(invalidPostcodeUrl);\n\n// Generate an error object if present, otherwise returns `undefined`\nconst error = parse(response);\n\n// Handle the error\nif (error instanceof IdpcPostcodeNotFoundError) {...}\n```\n\n## Test\n\n```bash\nnpm test\n```\n\n## Licence\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fideal-postcodes%2Fcore-interface","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fideal-postcodes%2Fcore-interface","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fideal-postcodes%2Fcore-interface/lists"}