There are no published clients yet. Rather than list packages you cannot install, this page shows the four calls you need in the languages people ask for, and how to generate a typed client yourself today.
When clients do ship they will be generated from the published contract at
GET /v1/openapi, so every language will expose the same operations under the same names.
TypeScript, Ruby and Python are planned first. No date is committed for any of them; the
changelog records each as it lands.
Call it directly
Four endpoints, all GET, all authenticated with one header.
curl
read -rs FIRMUS_KEY && export FIRMUS_KEY
curl -H "Authorization: Bearer $FIRMUS_KEY" \
https://api.firmus.sh/v1/fr/legal-entities/552032534Ruby
require "net/http"
require "json"
class Firmus
BASE_URL = "https://api.firmus.sh".freeze
def initialize(key) = @key = key
def legal_entity(country, registry_number)
get("/v1/#{country}/legal-entities/#{registry_number}")
end
def establishments(country, registry_number, **params)
get("/v1/#{country}/legal-entities/#{registry_number}/establishments",
**params)
end
def suggest(country, query, **params)
get("/v1/#{country}/suggest", q: query, **params)
end
private
def get(path, **params)
uri = URI("#{BASE_URL}#{path}")
uri.query = URI.encode_www_form(params) if params.any?
response = Net::HTTP.get_response(uri, "Authorization" => "Bearer #{@key}")
body = JSON.parse(response.body)
# Every failure carries the same shape; branch on
# the code, never on the message.
unless response.is_a?(Net::HTTPSuccess)
raise "#{body.dig('error', 'code')}: #{body.dig('error', 'message')}"
end
body
end
endPython
import os
import urllib.parse
import urllib.request
import json
BASE_URL = "https://api.firmus.sh"
def get(path, key=None, **params):
url = f"{BASE_URL}{path}"
if params:
url += "?" + urllib.parse.urlencode(params)
token = key or os.environ["FIRMUS_KEY"]
request = urllib.request.Request(
url, headers={"Authorization": f"Bearer {token}"}
)
try:
with urllib.request.urlopen(request) as response:
return json.load(response)
except urllib.error.HTTPError as error:
# The error body is JSON too, and says which of the codes this is.
raise RuntimeError(json.load(error)["error"]["code"]) from error
def legal_entity(country, registry_number):
return get(f"/v1/{country}/legal-entities/{registry_number}")
def suggest(country, query, **params):
return get(f"/v1/{country}/suggest", q=query, **params)JavaScript
From a server, with a secret key:
const BASE_URL = "https://api.firmus.sh";
export async function legalEntity(country: string, registryNumber: string) {
const path = `/v1/${country}/legal-entities/${registryNumber}`;
const response = await fetch(`${BASE_URL}${path}`, {
headers: { Authorization: `Bearer ${process.env.FIRMUS_KEY}` },
});
const body = await response.json();
if (!response.ok) throw new Error(body.error.code);
return body;
}From a browser, with a publishable key โ no Authorization header, so no preflight before
every keystroke:
const PUBLISHABLE_KEY = "fk_pub_...";
export async function suggest(query: string, signal?: AbortSignal) {
const url = new URL("/v1/fr/suggest", "https://api.firmus.sh");
url.searchParams.set("q", query);
url.searchParams.set("key", PUBLISHABLE_KEY);
const response = await fetch(url, { signal });
if (!response.ok) throw new Error((await response.json()).error.code);
return response.json();
}Only a publishable key may be sent that way, and only on this endpoint โ see authentication.
Generate your own client
The contract is public and needs no key, so a typed client is one command away in most languages. For TypeScript:
npx openapi-typescript https://api.firmus.sh/v1/openapi.json -o firmus.d.tsPin the copy you generate from and regenerate deliberately โ the changelog is where contract changes are announced.