BlogAnton Ignashev

enova365 WebAPI: A Developer's Guide to the Soneta REST API

enova365 WebAPI: A Developer's Guide to the Soneta REST API

Why I'm Writing This

Most "enova365 integration" content online is a marketing page wearing a tutorial's clothes. This isn't one. I run a production agent that writes wholesale order drafts into enova365 through Soneta WebAPI — it's been live for months, it has its own exception queue, and I've personally hit every failure mode described further down at least once. This is the guide I wish existed when I started building it: what WebAPI actually is, what it costs, how authentication really works, how you query and write data, and where it breaks in practice.

If you've already read my walkthrough of a B2B portal integration with enova365, think of this as the developer-level companion. That article covers architecture — sync jobs, pricing, order flow. This one is closer to the metal: the module, the auth handshake, the controller model, and the specific mistakes that cost people a week.

Licence First: WebAPI Is a Paid Module, Not a Given

Confirm this before you open your IDE. Soneta WebAPI is a separate paid module on top of base enova365 — not bundled in, not automatically active just because the client runs enova365. It ships as a perpetual add-on or a monthly subscription, and your reseller activates it against the specific licence.

Call them and ask directly, in these terms: is the WebAPI module active on this licence, and which enova365 build is installed. The build matters because dynamic controller behaviour has genuinely changed across major versions — a query that works on one installation can behave differently on another that's a year or two behind. "We have enova365" is not an answer you can build a project timeline around. "We have enova365 2026.1 with WebAPI active" is.

If the module isn't active, get it added before development starts. It is, almost without exception, cheaper over a year than building and maintaining a file-export workaround instead — and the alternative to WebAPI is direct MS SQL access, which bypasses enova365's own business logic and creates its own class of problems (more on that below, in the drafts section).

REST vs the Legacy WebWCF (SOAP) Server

WebAPI ships as two server variants, and the choice is not really a choice for new work.

WebAPI Server (REST) is the current standard — JSON over HTTP/HTTPS, actively developed, documented with a generated Swagger UI so you can see exactly which controllers and methods exist on your specific installation before you write a single request. This is what every new integration should use.

WebWCF Server (SOAP) is the legacy variant, kept alive purely for backward compatibility with integrations built years ago, before REST became the default. If you're inheriting one — a portal or accounting tool someone else built on WebWCF five years back — migrating it to REST is worth planning, but it's not an emergency. If you're starting a greenfield integration in 2026 and someone suggests WebWCF, that's a decision made out of habit, not out of necessity. Don't.

Dynamic Controllers vs Static Controllers

This is where enova365's WebAPI earns its reputation as the most developer-friendly of the Polish ERPs.

Dynamic controllers are generated automatically from the enova365 data model. Soneta maps most standard objects — products, contractors (kontrahenci), documents, warehouses — to REST endpoints without a line of code on the enova side. For the large majority of use cases — reading a product catalogue, pulling contractor records, creating a sales order or a purchase invoice — dynamic controllers are all you'll touch. The generated Swagger documentation on your specific WebAPI server is the actual source of truth for what's available; it reflects your installation's exact configuration, including any add-ons.

Static controllers are custom code embedded directly in the WebAPI server, written when dynamic controllers can't cover the need — a multi-step business process, a calculation that has to run enova-side, a data shape that doesn't map cleanly to a standard object. Writing one means someone with .NET and enova365 SDK experience is building and deploying it as part of the WebAPI server itself, which is a heavier lift than calling an existing endpoint. For a standard read/write integration — and that includes most accounting-automation use cases — you will rarely need to write one. If you find yourself reaching for a static controller in the first week of a project, it's worth asking whether the dynamic model actually covers your case and you just haven't found the right endpoint yet.

Authentication: How the JWT Flow Actually Works

WebAPI authenticates over JWT, and the flow is close to standard OAuth — nothing you need a special library for:

  1. Your integration sends credentials (an integration user, not a human operator's login) to the WebAPI authentication endpoint.
  2. enova365 validates them and returns a signed JWT.
  3. Every subsequent request carries that token in the request header.
  4. The token expires after a configured lifetime; your integration refreshes it before that happens, not after.

The shape of the request and response is simple — something like:

POST /token
{
  "login": "integration_user",
  "password": "***",
  "database": "TWOJAFIRMA"
}

The exact field names and endpoint path differ by version and are what the Swagger UI on your specific server will show you — don't trust a snippet from a blog post (including this one) over what your own installation's documentation says. What matters architecturally is this: build a single HTTP client wrapper that owns the token, refreshes it proactively on a timer running well inside the token's lifetime, and injects it into every outbound call. Never let an individual request discover the token expired and fail — that's how you get a 2 a.m. batch job silently dying halfway through a run.

Never put enova365 credentials in frontend or client-side code. Your integration's backend authenticates; nothing downstream of it should ever see the raw credentials, only the token your backend hands out internally.

Querying Data: Filters and Paging Without Reinventing SQL

Dynamic controllers accept standard REST-style query parameters for filtering, sorting, and paging — you're not writing SQL against enova365's database, you're passing parameters and letting the controller do the filtering server-side. The exact parameter names are version-specific and documented in your Swagger UI, but the pattern across every installation I've worked with is consistent: filter by field value, sort by a chosen field, request a page size and page number rather than pulling everything at once.

Use it. On a 10,000-SKU product catalogue, pulling the full set on every sync run versus requesting only records changed since your last successful run is not a minor optimisation — it's the difference between a sync that finishes in seconds and one that saturates your connection every time it runs. Most dynamic controllers expose a "modified since" style filter for exactly this reason; use it as the default, not the afterthought.

The same applies to nested data — line items on a document, for instance, are typically reachable through a related endpoint rather than embedded wholesale in every parent record response. Don't assume you'll get everything in one call; check what the specific controller returns before designing your data model around an assumption.

Writing Documents as Drafts (Bufor), Not Final Postings

This is the section worth reading twice if you're building anything that writes accounting or sales documents into enova365.

enova365 documents carry a status distinct from "doesn't exist yet" and "fully processed" — buffer status, bufor, the same state a human toggles manually inside the desktop application (there's a dedicated function to revert an approved document back to buffer, bound to Shift+F11, for exactly this reason: enova365 was built assuming documents pass through a reviewable, editable state before they're final). A document created via WebAPI can be written into that same buffer status — saved, visible, editable inside enova365, but not yet approved (zatwierdzony) and not yet contributing to stock movements, VAT registers, or downstream accounting.

That distinction is the whole design principle behind any integration that writes documents automatically. A dynamic controller creating a sales order or a purchase invoice (FZ) doesn't need to — and in almost every case, shouldn't — also call whatever separate action approves it. Write the document, leave it in buffer, and let a human review and approve it inside enova365 or through your own review interface that then triggers the approval step explicitly, as a second, deliberate call.

A minimal, illustrative payload for creating a document this way looks roughly like this — again, exact field names come from your Swagger UI, not from this post:

POST /Handel/ZamowieniaSprzedazy
{
  "Kontrahent": { "Id": 4821 },
  "Elementy": [
    { "Towar": { "Id": 1092 }, "Ilosc": 10, "Cena": 42.50 }
  ],
  "Bufor": true
}

Why this matters beyond "best practice": enova365's numbering sequences, stock reservation triggers, and VAT calculations are business logic that lives inside the application layer, not in the database. Writing directly to buffer through WebAPI still runs through that layer — enova365 assigns the document number, applies its own pricing and tax rules — while stopping short of the one step that has real financial and legal consequences: final approval. That's the step you want a person to own, every time, until you've earned enough trust in the automation to reconsider — and even then, I'd think hard before removing the human click entirely.

Harmonogram Zadań: Getting enova365 to Push, Not Just Answer

Everything above is you asking enova365 for something or handing it something. Harmonogram Zadań (Task Scheduler) is the other direction: it's enova365's built-in automation engine, built around triggers and actions, and it can be configured to fire an outbound HTTP notification when something happens inside the system — a document changes status, a new invoice appears, stock crosses a threshold.

This matters for integration design because it turns a polling architecture into an event-driven one. Instead of your integration asking "anything new?" every N minutes, enova365 tells you the moment something changes, and you fetch only the specific record that moved. It cuts unnecessary load noticeably, and it makes any downstream system — a portal, a reconciliation agent, a review dashboard — feel closer to real time.

The catch: not every enova365 installation has Harmonogram Zadań configured for outbound webhooks. It's available in the product, but whether it's set up on the specific installation you're integrating with is a question for the administrator or reseller, not an assumption to build around. Ask before you design the architecture, not after. And if you do use it, your side needs a publicly reachable HTTPS endpoint — a VPN-only setup needs extra routing work to receive it.

Where WebAPI Integrations Actually Break

In rough order of how often I've seen each one cost real time:

No network path to the WebAPI server. The single biggest source of calendar delay, and it has nothing to do with your code. Send a test request from your integration's actual environment to the WebAPI server before writing anything else. If it fails, everything downstream is theoretical until IT opens a port or sets up a VPN.

Licence module assumed active, not confirmed. "We have enova365" says nothing about WebAPI. Get written confirmation from the reseller, and get the exact build number while you're at it — dynamic controller behaviour is not perfectly stable across major versions.

Token refresh handled naively. A batch job that authenticates once at startup and never refreshes will start throwing 401s partway through a long-running sync, at whatever moment the token's lifetime runs out. Build refresh as a proactive, timed background task, not a reaction to failure.

Custom fields (pola dodatkowe) from installed add-ons. Dynamic controllers do expose them — but only if you know they exist and map them explicitly. Ask the enova365 administrator for a list of any industry-specific add-ons and their custom fields before you finalise your data model, not after your first production sync silently drops data nobody told you was there.

Reaching for a static controller too early. Custom server-side code is a real, valid tool — but it's also a maintenance commitment. Confirm a dynamic controller genuinely can't do the job before building and deploying one.

Writing document numbers from the integration side. enova365's numbering sequences are tied to its own internal state. Let it assign the number every time; never generate or suggest one externally, even for a draft.

Where This Leads: From Read/Write API to an Agent

Everything in this article — the auth flow, the controller model, writing documents to buffer instead of approving them automatically — is the exact plumbing an AI agent needs to book incoming invoices as reviewable drafts instead of a human retyping them. I've written up how that works end to end, from a KSeF invoice landing in your inbox to a draft sitting in enova365's buffer waiting for one click: Automated Posting Into enova365: How an AI Agent Writes Draft Documents via WebAPI.

If you're building this kind of integration — or want someone who's already hit these failure modes to look at your specific enova365 setup before you start — get in touch. The same WebAPI foundation described here is what powers the accounting AI agents I build: reading invoices from KSeF and email, writing draft postings into enova365, and leaving every approval to a human.

Let’s talk about your project

Free 30-minute consultation. We’ll figure out if and how I can help.

Book a Free 30-Minute Call

Select a date

August 2026
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Back to Blog

Related Posts

Comarch Optima API: a developer's guide to integrating Optima
Blog

Comarch Optima API: a developer's guide to integrating Optima

The question is usually whether Optima has an API. The answer is that it has five different things by that name, each with a different licence, a different owner, and a different phone number to call when it stops working.

Read more
Which AI agent to build first against enova365
Blog

Which AI agent to build first against enova365

The most valuable agent is almost always the wrong first build. Not because it cannot be built, but because its first honest output arrives in week ten, and nothing holds a room's attention that long. Four questions that screen the candidates, and one number that predicts whether the project lands.

Read more
The enova365 service account — what read-only actually means
Blog

The enova365 service account — what read-only actually means

The integration gets the Administrator account, because scoping the rights would take an afternoon and nobody has the afternoon. Then it turns out the strongest read-only boundary in enova365 is not the permission tree at all. It is the licence.

Read more