SDKs
pip install finbaze
Python 3.10 or newer. httpx does the HTTP (sync and async), pydantic v2 types every answer. The SDK is generated from the same GraphQL operations as the Node SDK, so the resources and names match; only the casing follows the language.
from finbaze import FinBaze
finbaze = FinBaze(secret_key="fb_sk_test_…") # fb_*_test_ keys use the sandbox API
company = finbaze.platform.companies.create({"externalId": "acme-1", "registrationCountry": "NL", "registrationNumber": "00000001"})
user = finbaze.platform.users.upsert({"externalUserId": "user-42", "firstName": "Sam"})
finbaze.platform.users.set_access(user_id=user.id, company_id=company.company.id, role="admin")
session = finbaze.platform.embed_sessions.create(
company=company.company.id, user={"id": user.id}, components={"vatReturn": {"enabled": True}},
)
return {"clientSecret": session.client_secret}
Async: from finbaze import AsyncFinBaze, the same names, await the calls and async for over auto_paging_iter(). with FinBaze(...) and async with AsyncFinBaze(...) close the connection pool.
Options: FinBaze(secret_key, api_base=…, version=…, max_retries=2, timeout=30.0, scopes=[…], app_info={"name": …}). You can also pass access_token= (a platform user token) or client_id=, client_secret= and profile_id=.
What the client does for you#
- Exchanges the key for an access token (
POST /v2/oauth2/token), caches it and refreshes it 60 seconds before it expires; a token the API rejects is dropped and exchanged again. - Sends
FinBaze-Version(the API version this SDK was built for). - Puts an
Idempotency-Keyon every mutation that can be retried and keeps the same key on every attempt. Passidempotency_key="…"to choose it, for example to tie a create to your own order id. - Retries network errors, HTTP 429 and 500/502/503/504 (not GraphQL errors) with jittered backoff; a
Retry-Afterheader is a floor.max_retries=0turns retries off.
Webhooks#
event = finbaze.webhooks.construct_platform_event(raw_body, request.headers["X-FinBaze-Signature"], secret)
Pass the body exactly as received. secret may be a list ([new, old]) while you rotate. The check is constant-time and rejects timestamps more than 300 seconds off; failures raise SignatureVerificationError. generate_test_header(payload, secret) builds a valid header for your own tests. See events and webhooks.
Errors#
FinBazeError is the base class; every error carries code, status, param, doc_url and request_id.
| Class | Raised for |
|---|---|
AuthenticationError | UNAUTHENTICATED, EMBED_SECRET_INVALID, EMBED_SESSION_REVOKED, HTTP 401 |
RateLimitError | RATE_LIMITED, HTTP 429; retry_after_seconds |
FeatureDisabledError | FEATURE_DISABLED, EMBED_FEATURE_DISABLED, PLATFORM_HEADLESS_DISABLED |
OperationNotAllowedError | EMBED_OPERATION_NOT_ALLOWED, EMBED_COMPONENT_NOT_ALLOWED, FORBIDDEN_TOKEN_TYPE, FORBIDDEN |
NotFoundError | NOT_FOUND, *_NOT_FOUND, HTTP 404 |
ValidationError | BAD_USER_INPUT, INVALID_PARAMETER, INVALID_INPUT; param names the argument |
ApiError | any other code (read code) |
NetworkError, ServiceUnavailableError | no answer, or HTTP 5xx after the retries |
The mapping is the same in every server SDK; see errors for the codes.
Resources#
platform.companies, users, user_tokens, embed_sessions, features (and features.limits), usage, data_sources, bulk (NDJSON uploads over HTTP), messages (acknowledge) and step_up (challenge, and header for retrying with a signed assertion). Lists return a Page: page.data is one page, page.auto_paging_iter() walks them all.
finbaze.graphql is the typed client for every operation in the GraphQL reference that the SDK covers, for example finbaze.graphql.sdk_platform_company(external_id="acme-1"), returning pydantic models.
The same calls in all five languages are on server SDK snippets.