How to Use OpenAPI to Generate and Maintain an SDK
Why contract-first API design helps teams generate typed SDKs, reduce drift, and ship embedded accounting integrations faster.
Evaluating this for a platform, firm, or fintech product? Explore our embedded accounting infrastructure overview

If you are exposing an API and expect other teams to build on it, the SDK question arrives quickly.
Should you hand-write one?
Should you generate one?
Should the spec drive everything?
For embedded accounting platforms, the answer is usually clearer than people expect:
Use OpenAPI as the contract, generate as much of the SDK as you reasonably can, and add human polish only where developer experience truly needs it.
That approach is usually more reliable than hand-maintaining a client library endpoint by endpoint.
This guide reflects how Paprel exposes its public API documentation and OpenAPI specification as of June 11, 2026 and is reviewed by the Paprel Product Team.
Why Hand-Written SDKs Drift
Hand-written SDKs often start strong and decay quietly.
The problem is not that engineers are careless. The problem is that APIs evolve in many places at once:
- new endpoints appear
- fields change
- enums expand
- filters are added
- auth requirements tighten
- response shapes become more specific
When the OpenAPI contract and the SDK are maintained separately, drift becomes likely.
That drift shows up as:
- SDK methods missing newer parameters
- stale model types
- undocumented headers
- response parsing bugs
- examples that no longer match production behavior
For accounting APIs, drift is especially expensive because the workflows are not trivial. A small mismatch in journals, reconciliation fields, or document states can waste real integration time.
Why OpenAPI Should Be The Source Of Truth
An SDK should not become the secret place where the API is actually defined.
The API contract should live in the spec first.
That is what makes OpenAPI valuable. It creates one machine-readable source for:
- paths and methods
- request bodies
- response models
- query parameters
- authentication expectations
- reusable schemas
From there, teams can generate:
- typed client methods
- request and response models
- example docs
- validation layers
- test fixtures
Paprel already treats the public API documentation and OpenAPI specification as real integration materials. The public API documentation is rendered from /openapi.json, and the current spec covers a broad finance surface including accounts, journals, reconciliations, clients, bills, company settings, and access-control related endpoints.
That is the right starting point for SDK generation: a real contract, not a marketing diagram.
What A Good Spec Needs Before You Generate Anything
Generating an SDK from a weak spec does not solve the problem. It automates the weakness.
Before generation, the spec needs enough quality that the output will actually help developers.
Stable Operation Identity
Generated SDKs become much easier to trust when operations map to clear names.
That means each operation should have:
- a deliberate
operationId - a clear summary
- consistent grouping by tag or domain
If the names in the spec are messy, the generated SDK will feel messy too.
Reusable Schemas
If every response shape is described ad hoc, the generated types will be noisy and repetitive.
Reusable component schemas help teams generate:
- cleaner models
- stronger type reuse
- more understandable docs
- lower maintenance overhead
Paprel's public spec already exposes reusable response and model components, which is a strong sign that the contract is structured for tooling, not only for human reading.
Query Parameters That Are Actually Typed
List endpoints are where weak specs often reveal themselves.
For example, a list operation should make filters explicit rather than leaving developers to guess.
In Paprel's public spec, list-oriented endpoints such as journal and client retrieval already expose typed query parameters like:
pagepage_sizecurrencydate_rangeposted
That matters because a generated SDK can then expose those filters as proper typed inputs instead of undocumented string bags.
Authentication Requirements That Match Reality
A generated SDK is only useful if auth is represented accurately.
Paprel's public spec currently exposes bearer authentication and also shows that write-oriented endpoints such as journal creation and bill creation require both:
authorizationx-data-signature
That is important. If a spec leaves out required headers or signing expectations, the generated SDK may compile nicely and still fail at the exact moment a developer tries to create real accounting activity.
Error Surfaces That Are Intentional
Generated clients become more useful when response codes are meaningful.
If the spec distinguishes outcomes like:
200400401412500
then the SDK can map those cases into clearer client behavior, better errors, or better retry decisions.
Why Accounting APIs Need More Than CRUD Generation
A lot of SDK discussions assume the API is just CRUD.
Embedded accounting APIs usually are not.
They involve workflows like:
- listing and filtering journals
- creating draft or posted accounting records
- matching transactions
- voiding or saving reconciliations
- reading company configuration
- working with finance documents and status transitions
That means the SDK should not only generate primitive HTTP wrappers. It should make these workflow surfaces legible.
If the underlying contract is strong, generation can help expose domain-shaped client methods instead of forcing developers to manually assemble every request from scratch.
What SDK Generation Should Give You For Free
Once the spec is strong enough, generation should handle the repetitive work.
A generated SDK should usually provide:
- typed request and response models
- method signatures for each operation
- enum-like safety where the schema allows it
- pagination and filter inputs for list calls
- serializer and deserializer behavior
- language-native package structure
For a platform API, that saves real time.
Instead of reading raw docs for every call, developers can discover the API through autocomplete and model definitions.
For example, Paprel's current public OpenAPI contract defines POST /v1/accounting/journals with:
authorizationheader requiredx-data-signatureheader required- a request body based on
BankingJournalFormModel - a success response based on
ApiResponse_BankingJournalFormResponseModel
Using the schema published in openapi.json, the request shape looks like this:
{
"currency": "USD",
"date": "2026-06-11",
"description": "Initial journal",
"exchange_rate": "1",
"is_manual": true,
"lines": [
{
"account_code": "1010",
"debit": "100.00",
"credit": null,
"description": "Cash movement",
"is_tax": false,
"is_taxable": false
},
{
"account_code": "4000",
"debit": null,
"credit": "100.00",
"description": "Revenue entry",
"is_tax": false,
"is_taxable": false
}
],
"meta_data": {
"root_entity_type": "journal",
"root_entity_id": "external-journal-001",
"description": "Initial journal import"
},
"override": false,
"override_reason": null,
"posted": true,
"reference": "INIT-001",
"reversal_of": null
}
And the success response shape resolves to something like this:
{
"data": {
"journals": [
{
"id": "jrnl_123",
"user_id": "user_123",
"company_id": "comp_123",
"date": "2026-06-11",
"currency": "USD",
"transaction_hash": "hash_abc123",
"exchange_rate": "1",
"is_locked": false,
"created_at": "2026-06-11T10:00:00Z",
"is_voided": false,
"is_reversal": false,
"is_manual": true,
"identifier": "JRN-000123",
"is_manual_override": false,
"is_posted": true,
"description": "Initial journal",
"reference": "INIT-001",
"related_entity_id": null,
"related_entity_type": null,
"reversal_of": null,
"root_entity_id": null,
"root_entity_type": null
}
]
}
}
That is exactly the sort of contract shape a generated SDK should absorb and expose through typed client methods, so developers spend time on workflow logic instead of reconstructing headers, payload shapes, and response models by hand.
What Still Needs Human Polish
OpenAPI generation is powerful, but it should not be romanticized.
A generated SDK still benefits from human-written layers in a few places.
Authentication Helpers
If your API requires more than a simple bearer token, developers should not have to rediscover that every time they write a mutation.
For Paprel-style finance APIs, a good SDK wrapper would usually add:
- token configuration helpers
- signing helpers for request bodies
- transport hooks for shared headers
That is often better implemented as a thin handwritten layer around generated code.
Better Error Messages
Generated SDKs can surface status codes, but production-grade developer experience often needs more context.
Examples include:
- clearer auth failure messages
- validation summaries
- request correlation identifiers
- more specific mutation failure explanations
Domain Convenience Methods
Sometimes the raw contract is correct, but the ergonomics can still improve.
A strong SDK may add optional helpers like:
- iterator utilities for paginated lists
- finance-domain aliases
- higher-level draft or post workflows
- request builders for complex accounting bodies
The goal is not to hide the API. The goal is to make the most common integrations easier without breaking alignment with the contract.
How To Keep A Generated SDK Maintainable
Generation is not a one-time event.
It works best when the team treats the spec, the SDK, and release discipline as one workflow.
That usually means:
- Update the OpenAPI contract first.
- Review the contract diff before release.
- Regenerate the SDK from the updated spec.
- Run compatibility checks and examples.
- Publish the SDK with a version that matches the scope of change.
That discipline matters because a generated SDK can only stay trustworthy if consumers know:
- what changed
- whether the change is breaking
- whether the generated client was rebuilt from the latest contract
For embedded accounting infrastructure, this is part of platform trust, not only developer convenience.
Common Mistakes Teams Make
Teams usually get worse results when they:
- generate from an incomplete or inconsistent spec
- treat the SDK as more important than the contract
- let handwritten patches accumulate directly inside generated files
- change operation names carelessly and break method stability
- forget to model auth and signing requirements explicitly
- publish generated code without regression tests or example validation
The worst outcome is not a missing SDK.
The worst outcome is an SDK that looks official but quietly disagrees with production behavior.
Where Paprel Fits
Paprel's public API surface is broad enough that SDK generation is not just a nice-to-have pattern.
The current public OpenAPI contract already represents:
- ledger and journal workflows
- reconciliation endpoints
- client, vendor, and document flows
- company configuration surfaces
- access-control and activity-oriented endpoints
That is exactly the kind of API surface where contract-first SDK generation becomes more valuable over time.
When the platform contract is explicit, typed, and reviewable, developers can build faster and with fewer surprises.
The Real Goal
The real goal is not to say you have an SDK.
The goal is to give developers a client library that:
- stays aligned with the API
- reflects real auth requirements
- exposes finance workflows clearly
- reduces integration drift over time
That is why OpenAPI matters.
For embedded accounting platforms, it is not just documentation. It is the foundation for reliable developer tooling.
Read Next
- For the broader platform view, read Embedded Accounting for your platform.
- For event-driven integrations, read Webhooks for Embedded Accounting Platforms.
- For scoped install flows, read OAuth Scopes and Permissions for Embedded Accounting Platforms.
Engineering notes from the team building Paprel's ledger core and API — ledger architecture, multi-tenancy, idempotency, and the patterns behind audit-grade accounting. Reflects how the system actually works and is updated as the product evolves.
Build in sandbox, launch with a production trial
Use sandbox for developer testing with no billing. When you are ready for real workflows, start production on a monthly plan with a 14-day free trial.