Building on D2K Companies House Lookup

Last updated

D2K Companies House Lookup is built to be depended on. If your Business Central extension - a customer-specific per-tenant extension, a vertical solution or another AppSource app - needs UK company data, declare a dependency on this app and call it rather than writing your own Companies House client. You get the cache, the rate limiting, the retry policy and the background filing monitor for nothing, and your users manage one Companies House API key rather than one per app.

This page covers what you can rely on, how to take the dependency, the behaviour to design around and the compatibility promise. Licensing, the API and a worked example each have their own page.

In this guide

What you can rely on

Everything in this table is the supported surface: it is what we test, document and keep compatible under the promise in Versioning and compatibility.

Area Objects
Lookup API interface "D2KL ICH Resolver", implemented by codeunit "D2KL Default Resolver"
Events The three integration events in codeunit "D2KL Events"
Filing watches codeunit "D2KL Filing Watch Mgt": RegisterWatch, UnregisterWatch, SetEnabled
Filed documents codeunit "D2KL Filing Document": Download, SuggestedFileName
Data (read only) Tables D2KL Company Snapshot, D2KL Company Snapshot SIC, D2KL Officer, D2KL Filing Event, D2KL Filing Watch
Enums D2KL Company Status, D2KL Company Type, D2KL Filing Type, D2KL Officer Role, D2KL Filing Status
Pages D2KL Company Lookup Dialog (LookupAndShow, NormaliseCRN, SetCRN, GetCRN), D2KL Company Search (SetSearchText), D2KL Company Officers (LoadFor), D2KL Company Filings (LoadFor), D2KL Company Snapshot List, D2KL Company Snapshot Card, D2KL Filing Watch List, D2KL Filing Event List
Permission sets D2KL Read, D2KL Edit, D2KL Admin

Anything not in the table - the other codeunits, the Setup table, the API call log, the rate-limiter state, the internals of the poller - is not supported, even where it compiles today. Objects outside the table may become Access = Internal before version 1.0.0, and may change without notice after it. If you need something that is not listed, ask (see Support) rather than reaching past the list.

Taking the dependency

Add the app to dependencies in your app.json:

{
  "id": "d09a6ce0-d64b-4744-85ee-845cea8af445",
  "name": "D2K Companies House Lookup",
  "publisher": "D2K Limited",
  "version": "1.0.0.0"
}

Use the lowest version that has what you need; Business Central accepts any installed version at or above it.

Symbols. The app does not ship its source, so take symbols from an environment where it is installed: install it in your development sandbox from AppSource, point your launch.json at that sandbox and run AL: Download symbols in Visual Studio Code.

Namespace. Every object is in the namespace D2K.CompaniesHouseLookup. Add using D2K.CompaniesHouseLookup; at the top of any file that refers to them, or qualify the names in full.

Installation for your customers. If your app is on AppSource, the dependency is enough: Business Central installs D2K Companies House Lookup alongside your app. If your app is a per-tenant extension, the customer installs D2K Companies House Lookup from AppSource first. Either way the app cannot be uninstalled while yours depends on it.

Behaviour to design around

  • Cache first. Three TTLs on the Setup page, set by the customer's administrator: Profile (default 7 days), Status (default 24 hours), Filings (default 1 hour). Do not fight them with ForceRefresh on every call; if a feature needs fresher data than the tenant's default, use ResolveByCRNWithMaxAge.
  • Stale data on outages. When Companies House is unavailable (a 5xx, a timeout or a rate limit) and a cached snapshot exists, the profile and status methods return the cached snapshot rather than failing. Check "Last Refreshed" if the age matters to you. Search, officers and filings have no stale fallback: they error.
  • Rate limit. Companies House allows 600 requests per five minutes per API key. The app counts every call it makes across all sessions in the tenant and refuses to exceed the limit - the user sees a "throttled locally" error - rather than have the key banned; a 429 from Companies House pauses every session for the Retry-After period. The key's budget is shared by every user and every app in the tenant, so do not loop lookups over a customer list. Work through the cache, or register watches and let the poller do it hourly.
  • Retries are built in. A rate limit is retried once after Retry-After; a 5xx up to three times with 1, 2 and 4 second back-off; a transport failure once. Do not add your own retry loop on top.
  • Errors are for the user. Every failure surfaces as an AL error with a message written for an end user: invalid CRN, company not found (404), API key missing or invalid (401), rate limited (429), service unavailable (5xx), no response. Wrap calls in a [TryFunction] when you need to carry on (a batch that skips failures); otherwise let the message reach the user.
  • Transactions. Interface calls never Commit. The cache write happens inside your transaction and rolls back with it. The poller is different: it owns its transactions and commits after each company, which is why it only ever runs from the Job Queue or the Filing Watch List.
  • The API key is the customer's. One key per Business Central company, entered by an administrator through the Assisted Setup and stored encrypted in Isolated Storage. Your app never sees it and does not need to. When a production environment is copied to a sandbox, the platform's cleanup hook clears the key so the copy never talks to Companies House with the production key; expect IsConfigured() to be false in a fresh copy.
  • Companies House sandbox. The Setup page has a Use Sandbox API switch that points the app at api-sandbox.company-information.service.gov.uk, which serves test data and needs its own key. Useful in a development tenant.

Versioning and compatibility

From version 1.0.0 the app follows strict semantic versioning, and everything in What you can rely on is covered:

  • Patch (1.0.x): bug fixes only. Nothing public changes.
  • Minor (1.x.0): additive only - new methods on the interface, new fields on the tables, new enum values, new events. Existing signatures do not change. A dependant compiled against 1.0.0 keeps working on any 1.x.
  • Major (2.0.0): the only place a breaking change can happen, and we avoid them.

Obsoletion. Nothing public is removed or changed without warning. A member that is going away is first marked ObsoleteState = Pending with an ObsoleteReason naming its replacement and an ObsoleteTag naming the version; it keeps working for at least twelve months from that release and is removed only in a major version. You see the deprecation as a compiler warning in your own build long before it bites.

AppSourceCop enforces the additive rules on our build, so the promise is checked by tooling, not only by intent.

What not to do

  • Do not write to any D2KL table. Read them; write through the API.
  • Do not depend on anything outside the supported surface, including Access = Internal objects your symbols may still show you.
  • Do not call Companies House yourself with the key this app stores: you cannot read it, and a second client would break the shared rate limit in any case.
  • Do not loop ResolveByCRN over a list of customers on a timer. Register watches; the poller does this properly.
  • Do not raise errors or open a user interface from an event subscriber.
  • Do not treat D2KL Filing Event or D2KL Officer as your archive. Copy what you need, and remember that the data comes from the Companies House public API under Companies House's own terms of use.

Support

Questions about the API, and requests for something that is not on the supported list, go to support@d2k.uk. If you ship an app that depends on this one, tell us its name and app ID: we will warn you before a deprecation lands rather than after.

Something missing or wrong on this page? Email support@d2k.uk. This page is also available as Markdown.