Pro App Web Requests

Web requests let a Pro app talk to external services — a courier API, a payment provider, a partner system — without ever holding the credentials or even knowing the address it calls.

You define the request once, in the backend. The running app calls it by name and passes a few parameters. Everything else — the address, the headers, the body, the credentials — stays on the server.

How it works

App  →  "call acme.getOrder with orderId = SO-1042"
              ↓ (backend adds address, headers, credentials)
        https://api.acme.com/v2/orders/SO-1042
              ↓
App  ←  the response

The app cannot change where the call goes. Parameters can only fill in the places you allowed, so a request can never be pointed at a different service.

Enabling web requests

  1. Open the app in the App Builder.
  2. Switch to the Backend tab.
  3. Select Web Requests from the left menu.
  4. Turn on the section.

Web requests require a Pro app. Only users with Design access can define or change them; anyone who can run the app can call an enabled request.

Defining a request

Click Add request and fill in:

Press Test to run the request from the backend and see the response with all credentials redacted.

Authentication

Credentials always come from secrets — you reference the secret by name, never by value.

Option What it does
None The service needs no credentials.
Bearer token from a secret Sends a bearer token taken from a secret.
Basic auth from secrets Sends a user name and password taken from two secrets.
OAuth2 client credentials The backend logs in with a client id and secret, gets an access token, and uses it.

With OAuth2 client credentials the backend handles the whole login for you: it fetches the token, keeps it until shortly before it expires, reuses it for every call, and renews it automatically. Tokens are kept separately for each set of credentials, so two requests with different credentials never share a token.

Using it in an app

Just describe what the app should do — the App Builder wires the call in for you:

When the user picks an order, fetch it from Acme and show the delivery status.
Add a button that pushes the selected document to the partner system.
Which web requests can this app call?

The app receives the status code and the response content. If the request is disabled, a parameter is missing, a secret has no value, or the external service fails, the app gets a clear message explaining what went wrong.

What the app gets back

A call always returns a small wrapper around the answer — the status of the call plus the content:

{ status: 200, data: <the service's answer> }

The answer itself is always under data. For an ERP.net list that means the rows are result.data.value. If anything goes wrong, the call fails with a readable message instead of returning an error object, so app code wraps it in a try/catch.

try {
  const res = await operator.requests.call('catalog.products', { top: 60 });
  const payload = res.data ?? res;          // tolerant unwrapping
  const rows = Array.isArray(payload.value) ? payload.value : [];
} catch (err) {
  showError(err.message);
}

The Test button in the backend shows the same content: what appears under data there is exactly what the running app receives.

The App Builder can create, change, test, mark public and delete these requests for you — you only need to enter the credential values yourself under Secrets.

Public requests (for public pages)

A visitor of a public page is not signed in, so the app cannot use that visitor's ERP.net connection, backend tables, stored files or secret values. The supported way to show server data on a public page is a request marked Public.

A public request:

This also covers ERP.net: point the request at the ERP.net Domain API address, give it a service login stored in secrets, and the public page can show the data without anyone signing in.

Example — a public product catalog:

Address:  https://<instance>/api/domain/odata/General_Products_Products?$filter=Active eq true and ShowInCatalog eq true&$top={{param.top}}
Auth:     OAuth2 client credentials (client id and secret from Secrets)
Public:   yes

Keep public requests as narrow as possible: bake the filters into the address and expose only harmless parameters such as paging or a search term. Anyone with the link can call a public request.

Safety limits