SDKs
The server SDKs share their behaviour (see the language pages: Node, Python, PHP, Kotlin and Java): client-credentials exchange with a cached token, the FinBaze-Version header, an Idempotency-Key on every mutation that can be retried, retries that honour Retry-After, typed errors, auto-paging, and a constant-time webhook check. This page is generated from one snippet catalogue, so the five versions of each call cannot drift apart.
Install#
Node
npm install @finbaze/platform-sdk
Python
pip install finbaze
PHP
composer require finbaze/finbaze-php
Kotlin
implementation("com.finbaze:finbaze-java:0.1.0")
Java
<dependency> <groupId>com.finbaze</groupId> <artifactId>finbaze-java</artifactId> <version>0.1.0</version> </dependency>
Create the client#
A fb_sk_test_ or fb_rk_test_ key uses the sandbox API, a live key the live API. The SDK exchanges the key for an access token, caches it and refreshes it a minute before it expires.
Node
import Finbaze from "@finbaze/platform-sdk";
const finbaze = new Finbaze({ secretKey: process.env.FINBAZE_SECRET_KEY });
Python
import os from finbaze import FinBaze finbaze = FinBaze(secret_key=os.environ["FINBAZE_SECRET_KEY"])
PHP
use FinBaze\FinBaze;
$finbaze = new FinBaze(getenv('FINBAZE_SECRET_KEY'));
Kotlin
val finbaze = FinBaze(secretKey = System.getenv("FINBAZE_SECRET_KEY"))
Java
FinBaze finbaze = FinBaze.builder().secretKey(System.getenv("FINBAZE_SECRET_KEY")).build();
Create a company#
Idempotent by externalId: calling it again returns the same company with created false. The sandbox accepts the magic KvK number 00000001.
Node
const company = await finbaze.platform.companies.create({
externalId: "acme-1",
registrationCountry: "NL",
registrationNumber: "00000001",
});
Python
company = finbaze.platform.companies.create(
{"externalId": "acme-1", "registrationCountry": "NL", "registrationNumber": "00000001"}
)
company_id = company.company.id
PHP
$company = $finbaze->platform->companies->create([
'externalId' => 'acme-1',
'registrationCountry' => 'NL',
'registrationNumber' => '00000001',
]);
$companyId = $company->company->id;
Kotlin
val company = finbaze.platform.companies.create(
externalId = "acme-1",
registrationCountry = Country.NL,
registrationNumber = "00000001",
)
val companyId = company.company.sdkPlatformCompanyFields.id
Java
var company = finbaze.getPlatform().getCompanies().createAsync("acme-1", Country.NL, "00000001").get();
String companyId = company.getCompany().getSdkPlatformCompanyFields().getId();
Upsert a user and give it access#
Users are yours: identify them by your own id. role is admin, member or viewer.
Node
const user = await finbaze.platform.users.upsert({ externalUserId: "user-42", firstName: "Sam", lastName: "Jansen" });
await finbaze.platform.users.setAccess({ userId: user.id, companyId: company.id, role: "admin" });
Python
user = finbaze.platform.users.upsert({"externalUserId": "user-42", "firstName": "Sam", "lastName": "Jansen"})
finbaze.platform.users.set_access(user_id=user.id, company_id=company_id, role="admin")
PHP
$user = $finbaze->platform->users->upsert(['externalUserId' => 'user-42', 'firstName' => 'Sam', 'lastName' => 'Jansen']); $finbaze->platform->users->setAccess(companyId: $companyId, role: 'admin', userId: $user->id);
Kotlin
val user = finbaze.platform.users.upsert(externalUserId = "user-42", firstName = "Sam", lastName = "Jansen") finbaze.platform.users.setAccess(companyId = companyId, role = PermissionSet.admin, userId = user.id)
Java
var user = finbaze.getPlatform().getUsers().upsertAsync("user-42", "Sam", "Jansen").get();
finbaze.getPlatform().getUsers().setAccessAsync(companyId, PermissionSet.admin, user.getId()).get();
Mint a user token#
A short-lived token that acts as one platform user on the companies you name. asUser does this for you and caches the token.
Node
const token = await finbaze.platform.userTokens.create({ userId: user.id, companyIds: [company.id] });
Python
token = finbaze.platform.user_tokens.create(user_id=user.id, company_ids=[company_id]) as_user = finbaze.as_user(user_id=user.id, company_ids=[company_id])
PHP
$token = $finbaze->platform->userTokens->create(userId: $user->id, companyIds: [$companyId]); $asUser = $finbaze->asUser(userId: $user->id, companyIds: [$companyId]);
Kotlin
val token = finbaze.platform.userTokens.create(userId = user.id, companyIds = listOf(companyId)) val asUser = finbaze.asUser(userId = user.id, companyIds = listOf(companyId))
Java
var token = finbaze.getPlatform().getUserTokens().createAsync(user.getId(), null, List.of(companyId), null).get(); FinBaze asUser = finbaze.asUser(user.getId(), null, List.of(companyId), null);
Create an embed session#
The client secret works once: create a new session for every mount and refresh, and hand only clientSecret to the browser.
Node
const session = await finbaze.platform.embedSessions.create({
company: company.id,
user: { id: user.id },
components: { vatReturn: { enabled: true } },
previousSessionId, // from the browser SDK's fetchClientSecret
});
return { clientSecret: session.clientSecret };
Python
session = finbaze.platform.embed_sessions.create(
company=company_id,
user={"id": user.id},
components={"vatReturn": {"enabled": True}},
)
client_secret = session.client_secret
PHP
$session = $finbaze->platform->embedSessions->create(
company: $companyId,
user: ['id' => $user->id],
components: ['vatReturn' => ['enabled' => true]],
);
$clientSecret = $session->clientSecret;
Kotlin
val session = finbaze.platform.embedSessions.create(
company = companyId,
user = EmbedUser.id(user.id),
components = EmbedComponents.builder().vatReturn().build(),
)
val clientSecret = session.clientSecret
Java
var session = finbaze.getPlatform().getEmbedSessions().createAsync(
companyId, EmbedUser.id(user.getId()), EmbedComponents.builder().vatReturn(true).build()).get();
String clientSecret = session.getClientSecret();
List with auto-paging#
Lists are cursor pages. data is the current page; the auto-paging helper walks every page and fetches the next one only when you reach it.
Node
const page = await finbaze.platform.companies.list({ limit: 100 });
await page.autoPagingEach(async (c) => console.log(c.externalId));
Python
for c in finbaze.platform.companies.list(limit=100).auto_paging_iter():
print(c.external_id)
PHP
foreach ($finbaze->platform->companies->list(limit: 100)->autoPaging() as $c) {
echo $c->externalId, "\n";
}
Kotlin
finbaze.platform.companies.list(limit = 100).autoPaging().collect { println(it.externalId) }
Java
for (var c : finbaze.getPlatform().getCompanies().listAsync(100, null).get().autoPagingIterable()) {
System.out.println(c.getExternalId());
}
Verify a webhook#
Pass the body exactly as received, before any JSON parsing. The check is constant-time, accepts any of several signatures while a secret rotates, and rejects timestamps more than five minutes off.
Node
const event = await finbaze.webhooks.constructPlatformEvent(rawBody, req.header("x-finbaze-signature"), process.env.FINBAZE_WEBHOOK_SECRET);
Python
event = finbaze.webhooks.construct_platform_event(raw_body, request.headers["X-FinBaze-Signature"], secret)
PHP
$event = $finbaze->webhooks->constructPlatformEvent(file_get_contents('php://input'), $_SERVER['HTTP_X_FINBAZE_SIGNATURE'] ?? null, $secret);
Kotlin
val event = Webhooks.constructPlatformEvent(rawBody, request.header("X-FinBaze-Signature"), secret)
Java
Map<String, Object> event = Webhooks.constructPlatformEvent(rawBody, request.getHeader("X-FinBaze-Signature"), secret);
Handle errors#
Errors are typed from extensions.code (see errors). Network errors, 429 and 5xx are retried for you; a mutation that can be retried carries an Idempotency-Key.
Node
try {
await finbaze.platform.companies.retrieve("c_missing");
} catch (error) {
if (error instanceof FinbazeRateLimitError) await sleep(error.retryAfterSeconds * 1000);
else throw error;
}
Python
from finbaze import FeatureDisabledError, RateLimitError
try:
finbaze.platform.features.effective(company_id)
except RateLimitError as error:
time.sleep(error.retry_after_seconds or 1)
except FeatureDisabledError as error:
log.warning("hidden: %s (request %s)", error.code, error.request_id)
PHP
use FinBaze\Errors\FeatureDisabledError;
use FinBaze\Errors\RateLimitError;
try {
$finbaze->platform->features->effective($companyId);
} catch (RateLimitError $e) {
sleep((int) ($e->retryAfterSeconds ?? 1));
} catch (FeatureDisabledError $e) {
error_log("hidden: {$e->errorCode} (request {$e->requestId})");
}
Kotlin
try {
finbaze.platform.features.effective(companyId)
} catch (e: RateLimitError) {
delay(((e.retryAfterSeconds ?: 1.0) * 1000).toLong())
} catch (e: FeatureDisabledError) {
log.warn("hidden: ${e.code} (request ${e.requestId})")
}
Java
try {
finbaze.executeBlocking(new SdkPlatformCompanyFeaturesQuery(companyId));
} catch (RateLimitError e) {
Thread.sleep((long) ((e.getRetryAfterSeconds() != null ? e.getRetryAfterSeconds() : 1.0) * 1000));
} catch (FeatureDisabledError e) {
log.warn("hidden: {} (request {})", e.getCode(), e.getRequestId());
}
Upload many objects (NDJSON)#
One request, applied in the background. The API requires an Idempotency-Key; the SDK generates one, and reusing it retries the same upload safely.
Node
const job = await finbaze.platform.bulk.create({
object: "relations",
lines: [{ externalId: "r1", name: "First" }, { externalId: "r2", name: "Second" }],
company: { externalId: "acme-1" },
});
Python
job = finbaze.platform.bulk.create(
object="relations",
lines=[{"externalId": "r1", "name": "First"}, {"externalId": "r2", "name": "Second"}],
company={"external_id": "acme-1"},
)
PHP
$job = $finbaze->platform->bulk->create(
object: 'relations',
lines: [['externalId' => 'r1', 'name' => 'First'], ['externalId' => 'r2', 'name' => 'Second']],
company: ['externalId' => 'acme-1'],
);
Kotlin
val job = finbaze.platform.bulk.create(
objectType = "relations",
lines = listOf(mapOf("externalId" to "r1", "name" to "First"), mapOf("externalId" to "r2", "name" to "Second")),
company = "ext:acme-1",
)
Java
var lines = List.of(Map.<String, Object>of("externalId", "r1", "name", "First"), Map.<String, Object>of("externalId", "r2", "name", "Second"));
var job = finbaze.getPlatform().getBulk().createAsync("relations", lines, "ext:acme-1").get();