For the complete documentation index, see llms.txt. This page is also available as Markdown.

App Backends

How an app registers a backend and takes over a role in the ERP.

Most apps only read and write ERP data. The apps in this space do something more: they take over a role in the ERP. To do that, an app registers a backend — a record in the ERP that says "for this domain, I am responsible".

Every domain in this space works the same way. Learn it once here.

The pattern

┌───────────┐   1. install: register backend   ┌───────────┐ 
│  Your App │ ──────────────────────────────►  │ VARIO ERP │ 
│           │                                   │           │ 
│           │ ◄──────────────────────────────   │           │ 
└───────────┘   2. ERP calls back / notifies    └───────────┘
1

On install

A migration creates a backend record carrying your app identifier.

2

From then on

The ERP routes work in that domain to you — either by calling a URL you registered, or by firing a webhook.

Two things make the record yours:

Field
Value
Why

appId

your appIdentifier

The ERP knows which app owns this backend, and you can find it again

type / backendType

APP

Distinguishes an app-provided backend from a built-in one

What each domain registers

Domain
Record
Endpoint

Sales channel backend + sales channels

POST /community/{version}/erp/sales-channels/backend

Shipping

Carrier type

POST /community/{version}/vds/carrier-type

Banking

Bank backend

POST /erp/bank/backend

Financial Accounting

Finance backend

POST /community/{version}/erp/finance/backend

POS Payment Methods

POS payment backend

POST /community/{version}/erp/pos/payment/backend

The framework provides migration helpers for sales channel, bank and finance backends. Carrier types and POS payment backends are created with a plain API call.

The naming is not uniform. Most domains have something literally called a backend; shipping does not — there the carrier type (Versendertyp) plays that role, carrying the app identifier and the callback URLs. There is no "carrier backend".

How the ERP reaches you

This is the part that surprises people: for several domains the ERP calls into your app, synchronously. You register those URLs on the backend record itself.

Domain
URL fields on the record
Called when

Shipping

createShipmentSyncUrl, createLabelSyncUrl

A shipment is created / a label is requested

Banking

appTransactionUrl, appPaymentUrl, appStatusUrl

Transactions are fetched / a payment is sent / status is polled

What you register vs. what the customer creates

A frequent misunderstanding. Your app registers the technical infrastructure. The customer creates their own business objects on top of it:

You create (on install)
The customer creates (in the ERP)

Carrier type ("DHL App")

Carriers and shipping methods that use it

Bank backend ("PayPal")

Their banks, which select your backend

POS payment backend

The payment methods that point at it, and their assignment to registers

Sales channel backend ("Shopware 6")

Usually created by your app — one channel per store

So a shipping app never creates a carrier, and a banking app usually never creates a bank — it makes itself selectable. Don't create customer master data on install; the customer owns names, IBANs and BICs.

Migrations

Backends are created in a migration that runs on install. Two things you must understand:

Migrations run once, ever. Each step is recorded by name. Editing an existing step does nothing on tenants where it already ran — you must add a new, differently named step.

Use always(key, callback) instead of setMigration for steps that must re-run on every install — webhook registration is the usual case.

Sandbox vs. production

There is no platform-level sandbox flag. Two approaches are used:

  • A second backend record whose label is suffixed (Sandbox) — the shipping apps do this, and detect the mode from the label.

  • A configuration value the user toggles — PayPal does this.

Finding your backend again

You rarely keep the id. Query it back by your own app identifier — e.g. via VQL:

The framework's findSalesChannelBackend() does exactly this.

Checklist

  • Manifest declares the permissions your domain needs

  • Migration registers the backend with your appId and type APP

  • Callback URLs point at your public host — and a later migration can refresh them

  • Webhooks registered with always(), not setMigration()

  • Uninstall deactivates (never deletes) customer objects, children first

  • Sandbox mode explicit, with string-safe boolean checks

  • App log checked after install — failures are silent

Last updated

Was this helpful?