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.

Paprel Engineering Team

Evaluating this for a platform, firm, or fintech product? Explore our embedded accounting infrastructure overview

Engineers reviewing API documentation and client code during SDK planning

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:

  • page
  • page_size
  • currency
  • date_range
  • posted

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:

  • authorization
  • x-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:

  • 200
  • 400
  • 401
  • 412
  • 500

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:

  • authorization header required
  • x-data-signature header 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:

JSON
{
  "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:

JSON
{
  "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:

  1. Update the OpenAPI contract first.
  2. Review the contract diff before release.
  3. Regenerate the SDK from the updated spec.
  4. Run compatibility checks and examples.
  5. 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.

Explore the Paprel API documentation →
Posted by: Paprel Engineering Team · Engineering
Posted on:

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.

Evaluate Paprel

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.

API-First Delivery
Audit-Ready Controls
Sandbox And Guided Rollout