11 min read
primavera
erp
integrações
arquitectura
saas

Integrating Primavera with a modern web application

A practical guide to connecting Cegid Primavera to a modern web application, choosing API, SDK or SQL without exposing the ERP or creating technical debt.

Sala de reuniões luminosa com três pessoas a rever um mapa de integração sobre a mesa

TL;DR

  • The best integration with Primavera is almost never direct database access. For writes, use the official API or the SDK to respect tax rules, series, warehouses and ERP validations.
  • Treat Primavera as the system of record for customers, items, stock, orders and tax documents. The web application should have an operational copy, not try to replace accounting.
  • If the ERP is installed on the client’s network, do not expose it to the Internet. Use a local connector, message queue, VPN between networks or controlled tunnel with strong authentication.
  • The hard part is not calling the API. It is synchronisation, idempotency, conflicts, reprocessing, observability and understanding who owns each field.
  • Start with a small flow, for example customers and orders, measure real latencies and only then move on to stock, invoicing and warehouse movements.

Before the code, decide what integration you are actually building

“Integrating Primavera with a web application” can mean four very different things.

It could be an online shop that needs to send orders to the ERP. It could be a B2B portal where customers check invoices and balances. It could be an operational app that needs stock almost in real time. Or it could be an internal platform that only wants to read master data, such as customers, items and payment terms.

The architecture changes depending on the answer. If you only need a daily read of master data, batch synchronisation is enough. If you need to reserve stock at checkout, you have a different problem: concurrency, latency, failures and reconciliation. If you are going to issue tax documents, do not invent numbering or VAT rules outside Primavera. The ERP should remain the tax authority.

The first matrix I use in these integrations is simple:

  • Master data: customers, suppliers, items, families, prices, payment terms.
  • Operational data: orders, reservations, shipments, warehouse movements.
  • Tax data: invoices, credit notes, receipts, series, taxes.
  • Analytical data: aggregated sales, margins, balances, history.

Each group has a different tolerance for delay. Master data can accept 5 to 15 minutes. Stock may need 30 to 60 seconds, depending on the business. Tax documents require consistency and traceability. Analytics can run overnight.

The strong opinion here: do not start with “which endpoint exists?”. Start with “what is the source of truth?”. If you cannot answer that, you will end up with two systems correcting the same field and nobody trusting the data.

The four practical ways to integrate with Primavera

In Cegid Primavera ERP v10 and v11 installations, when available and properly configured, the Web API is usually the first option to assess. But there are scenarios where the SDK, SQL Server or files still make sense. The choice should not be religious.

1. Official Web API

It is the preferred option for a modern web application when functional coverage is sufficient.

Concrete advantages:

  • Respects the ERP’s application logic.
  • Avoids direct writes to internal tables.
  • Is easier to isolate behind an integration service.
  • Fits well with Node.js 22 LTS.NET 8, Python or any HTTP backend.

Limitations:

  • Coverage varies by version, licensing and configuration.
  • It can have high latency if the ERP is on a local network connected by VPN.
  • It does not always expose all the details that an operational integration needs.
  • Authentication and installation at the client can be harder than they seem in the demo environment.

Before designing the architecture, confirm the exact Primavera version, licensed modules, Web API availability and applicable documentation. Cegid Primavera’s public technical documentation should be the starting point: https://developers.primaverabss.com/

2. SDK or local component

The SDK makes sense when you need functions that the Web API does not cover or when the integration has to live very close to the ERP. It is common in scenarios where there is specific logic for documents, warehouses, batches, series or existing extensions.

Advantages:

  • Greater access to the ERP’s functional model.
  • Better for complex operations that depend on internal logic.
  • Can run inside the client’s network, without opening the ERP to the outside.

Limitations:

  • Greater dependency on Windows, local installation and specific versions.
  • More awkward deployment, especially across multiple clients.
  • Scales worse than a stateless API in the cloud.
  • Requires strong discipline in logs, updates and monitoring.

The typical architecture is a local connector installed alongside Primavera. That connector talks to the ERP via the SDK and communicates with the web application through a queue or secure API.

3. Direct SQL Server

Primavera typically runs on SQL Server. That tempts many people to connect the web application directly to the database. For writes, it is almost always a mistake.

Reading may be acceptable in limited cases: reports, analytics, controlled exports or data synchronisations that the API does not expose. Even then, use a read only account, your own views where possible, appropriate transactional isolation and never assume that the internal schema is a public contract.

Advantages:

  • Very fast for reads.
  • Useful for large volumes, for example 10 GB of sales history.
  • Enables specific queries for reports.

Limitations:

  • The schema may change with updates.
  • Direct writes ignore ERP validations.
  • Poorly written queries can block operations.
  • Makes vendor support harder.

If you go down this route, consult Microsoft’s documentation on SQL Server Change Tracking or CDC. For SQL Server 2019 and 2022, both can help, but they have different operational costs: https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-tracking-sql-server

4. Files, CSV, XML or SAF-T

There are still file based integrations that work well. They are not pretty, but they are predictable. For nightly imports, accounting exports or legacy systems, it may be the lowest risk option.

Advantages:

  • Simple to audit.
  • Easy to reprocess.
  • Good for daily batches.

Limitations:

  • Not suitable for interactive experiences.
  • Error validation is usually poor.
  • Creates delays and manual reconciliation.

RPA should be the last resort. If the integration depends on “clicking” in Primavera like a human, prepare for failures during updates, expired sessions and unexpected windows.

The architecture I prefer most for this type of integration has three pieces: web application, integration service and Primavera connector.

The web application should never know Primavera details. It should not know series, internal tables, specific endpoint names or ERP credentials. It should talk to an integration service through its own contracts: create order, synchronise customer, check invoice status.

The integration service sits in the cloud, alongside the application. It can be Node.js 22 LTS.NET 8 or another stack with good observability. It stores synchronisation state in PostgreSQL 16 or an equivalent database. It manages queues, reprocessing, idempotency and mappings.

The Primavera connector sits where the ERP is. If Primavera is on the client’s network, the connector should be there too. It communicates outwards through HTTPS, a managed queue or authenticated connection. This avoids opening inbound ports to the ERP.

A simple mental model:

  • Browser or mobile app calls your web application.
  • The web application records the intention locally, for example “order created”.
  • A job sends that intention to the integration service.
  • The integration service calls the Primavera connector.
  • The connector executes on the Web API or SDK.
  • The result comes back with ERP identifiers and final status.

This seems heavier than “calling Primavera directly”, but it pays for itself quickly when there are failures. And there will be failures: VPN down, licence occupied, timeout, item not found, customer blocked, wrong series, insufficient stock.

For synchronous operations, set clear budgets. In a web application, I would try to keep p95 below 800 ms for common operations. A call to Primavera through a local network, VPN and API can easily exceed 2 seconds at p95. For checkout or order creation, I prefer to accept the operation locally and process it in the background, showing “under validation” when the business allows it.

Synchronisation, idempotency and source of truth

The most underestimated part is idempotency. If your app sends the same order twice because of a timeout, Primavera should not end up with two documents.

Create a stable external key. It can be web_order_id, customer_id or integration_request_id. That key should travel to Primavera whenever there is a proper field, technical note or extension table. If there is no clean place to store it, keep a mapping table in the integration service.

A minimal model in PostgreSQL 16 could be this:

create table primavera_sync_map (
  id bigserial primary key,
  entity_type text not null,
  external_id text not null,
  primavera_id text not null,
  primavera_company text not null,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  unique (entity_type, external_id, primavera_company)
);

create table primavera_sync_cursor (
  source_name text primary key,
  cursor_value text not null,
  updated_at timestamptz not null default now()
);

This model does not solve everything, but it prevents an entire category of problems: silent duplication. It also allows events to be reprocessed without fear.

For Primavera to web synchronisation, you have three main strategies:

  • Polling by change date: simple, sufficient for many cases. Use overlapping windows, for example always going back 2 minutes, to compensate for clocks and long transactions.
  • Change Tracking or CDC in SQL Server: better for volume and precision, but increases coupling to the database.
  • Events through an ERP extension: best when available, because it brings the integration closer to real business events.

Watch the clock. Dates without timezone are a classic trap. If the web application stores UTC and the ERP works in local time, daylight saving time transitions can create gaps or duplicates. Store cursors by monotonic identifier where possible. When that is not possible, use overlapping windows and deduplication.

A simple job should have this logical form, not necessarily this exact code:

async function syncCustomers() {
  const cursor = await loadCursor("primavera_customers");
  const changed = await primavera.listCustomersChangedSince(cursor);

  for (const customer of changed) {
    await upsertCustomerFromPrimavera(customer);
    await saveMapping("customer", customer.code, customer.primaveraId);
  }

  const nextCursor = calculateSafeCursor(changed, cursor);
  await saveCursor("primavera_customers", nextCursor);
}

The most important function here is calculateSafeCursor. If you advance the cursor to “now” instead of to the last processed record with a safety margin, you will lose changes in production.

Security and operation in production

Do not expose Primavera’s Web API directly to the Internet with a long password and hope. That is asking for trouble.

The acceptable minimum:

  • TLS on all connections.
  • Authentication with a technical client, with minimum permissions.
  • Secrets stored in a vault, for example Azure Key Vault, AWS Secrets Manager or HashiCorp Vault.
  • Logs without NIF, tokens, IBAN, full addresses or unnecessary personal data.
  • IP allowlist when it makes sense.
  • Credential rotation with a documented process.
  • Separation by company, environment and tenant.

If you use OAuth 2.0, read the relevant specification at https://www.rfc-editor.org/rfc/rfc6749 and validate the flow supported by the installation. Many older enterprise integrations still use patterns that would now be avoided in a public app. Compensate with network isolation, short expiry and reduced permissions.

Also define operational limits. An ERP is not a public API designed for 300 RPS. In many scenarios, 2 to 10 requests per second is already more than enough. For synchronisation, prefer batches of 100 to 500 records, with pauses and retry with backoff. Timeouts of 10 to 30 seconds are reasonable for heavy operations, but they should not block HTTP requests from end users.

Observability is not optional. Record each integration request with:

  • Operation identifier.
  • Business entity.
  • Primavera company.
  • Status, attempt and normalised error.
  • Latency.
  • Identifier returned by the ERP.

Use RFC 9110 as a reference for HTTP semantics when designing your internal API: https://www.rfc-editor.org/rfc/rfc9110

The error message “failed to create document” is not enough. You need to know whether it failed because of timeout, tax validation, blocked customer, missing item or network outage.

Implementation plan that avoids expensive surprises

I would implement it in phases.

First, inventory. Exact Primavera version, modules, companies, databases, test environment, Web API available, SDK required, internal owners and operating hours. Without this, you are guessing.

Second, data map. List mandatory and optional fields. Define equivalences: web customer to Primavera customer, SKU to item, address to entity, payment method to payment term, VAT rate to tax regime.

Third, decide authority by field. Can the customer email be edited on the web? Does the tax address always come from the ERP? Is the price calculated by the app or by Primavera? If two people can edit the same field in different systems, you need a conflict rule.

Fourth, create a test environment with data similar to real data. Perfect data does not test integrations. You need blocked customers, items without stock, invalid NIF, incomplete addresses, closed series and voided documents.

Fifth, implement a small end to end flow. For example, create customer and send order. Only then add invoicing, stock and receipts.

Sixth, create administrative reprocessing. Someone in operations should be able to see failures and resend a corrected integration, without asking a developer to run scripts.

Seventh, measure. p50, p95 and p99 latency. Error rate. Average time to synchronisation. Number of retries. Operations blocked by validation.

Eighth, document decisions. Not in a pretty PDF that nobody reads. In a living technical document, linked to the repository, with contracts, fields, payload examples and business rules.

Common pitfalls in production

The first pitfall is writing directly to Primavera tables. It may work in a small test and fail when series, taxes, warehouses, permissions, version changes or accounting closures come into play. For operational and tax writes, avoid it.

The second is assuming that stock is a simple number. Stock can depend on warehouse, location, batch, reservation, pending orders and commercial rules. If the web shows “5 units” and the warehouse works with reservations, you will sell what you do not have.

The third is ignoring voided or rectified documents. Naive integrations only synchronise creations. Then credit notes, voids and manual adjustments appear in the ERP, and the web application continues to show debt or incorrectly closed orders.

The fourth is not handling multiple companies. Many Primavera installations have several companies. The same customer code can exist in more than one. Your mapping key should include company, not just identifier.

The fifth is not separating technical errors from business errors. Timeout should go to automatic retry. “Customer blocked” should not repeat 100 times. It should go to a queue for human intervention.

The sixth is forgetting upgrades. An update to Primavera, SQL Server or the connector can change behaviour. Before updating production, run a short set of integration tests: create customer, create order, check document, void test flow, synchronise change.

Conclusion

Integrating Primavera with a modern web application is mainly a problem of architecture and operation, not endpoints. Choose API or SDK for writes, use SQL only very carefully for reads, and design from the start for failures, retries and reconciliation. If you are facing a similar problem, book a call at https://impact-origin.com/agendamento.

Impact OriginEnjoyed this article?At Impact Origin we help founders and teams build and scale custom software, from a startup MVP to the next step. If you have a project in mind, let's talk.