Appearance
Connect to another system - connectors, secrets and Run integration
The real problem
Northwind wants every approved resignation to notify the payroll vendor, and the person building the screen is not a programmer. Pasting the vendor's address and API key into a button would put a secret in a page anyone can read, and every screen that needs the vendor would repeat it.
A connector keeps the address, the sign-in and the shape of the request in one place. A page button or a workflow step only says which connector to run and which values to send.
The idea in one minute
- A connector describes one outbound call: address, method, how to sign in, and a JSON body with
{{fields}}filled in at run time. - The credential is never inside the connector. It is stored encrypted for your tenant, and the connector refers to it as
secret:connector.<name>. - The catalog lists ready-made templates. Each is labelled honestly: Ready (verified by the platform's own tests), Untested (a starting template not yet run against the real service, so try it first) or Planned (not installable yet).
- A new connector drafted by the Studio assistant starts Off. A person adds the credential, tries it and switches it on.
- Run integration is the one way an application uses it: a page or form action, or a workflow node. It names the connector (or a flow) and maps values. It never sees an address or a key.
Designer path (Studio)
- Open Integrations > Connector Catalog. Read the status on each card.
- On Generic REST call, choose Use this. Enter the connector's name, the public https address and the token, then Save connector. The token is stored encrypted and is not shown again.
- In My connectors, choose Try. Fill the fields the request needs and Send. You see the real answer, for example
Worked (HTTP 200), or the vendor's own error in plain words. - On a form or page, add a step Run integration. Choose the connector from the list, then click a field chip such as
emailto send that form value. No address, no JSON. - In a workflow, add the node Integration: run a connector or flow and choose the same connector. Its result is available to later steps as
${context.<node key>.<field>}. - If the assistant drafted the connector, it shows Off (review first). Add the credential, Try it, then Switch on.
An internal address (localhost, 10.x, cloud metadata) is refused with a clear message. Only public https addresses work unless your platform operator allows private ones.
Developer path
Set up the connector from the command line. The value comes from stdin or a file, never from an argument, so it stays out of shell history:
bash
erp connector catalog
printf '%s' "$TOKEN" | erp connector secret set echoSave this as echo.json (baseUrl is the full address, so requestPath stays empty):
json
{
"domain": "integration",
"providerKey": "echo",
"name": "Echo",
"connectorKind": "HTTP",
"active": true,
"baseUrl": "https://httpbin.org/anything",
"requestPath": "",
"httpMethod": "POST",
"authType": "BEARER_TOKEN",
"authConfig": { "secretRef": "secret:connector.echo" },
"requestTemplate": { "data": "{{payload}}" }
}bash
erp connector validate echo.json
erp connector create echo.json
erp integration run connector echo --input '{"payload":"hello"}'Use it from a page or form (an action step, type: runIntegration):
json
{
"id": "notify-payroll",
"type": "runIntegration",
"name": "Notify payroll",
"config": {
"connectionRef": "self",
"kind": "connector",
"key": "echo",
"input": { "payload": "${form.employeeName}" }
},
"output": "notified"
}The response is then available as ${api.notified.<field>}. From a workflow, add a service task of type integration.run with the payload {"kind":"connector","key":"echo","input":{"payload":"${context.start.name}"}}.
From an application's own code, the same door: POST /api/v1/integration/run with {"kind":"connector","key":"echo","input":{...}} (or "kind":"flow" to queue a flow; you get an execution id back).
For an AI client, the MCP tool erp_connector_catalog lists the templates, and erp_validate_connector_definition checks a file.
Let another system call it (Published APIs)
To let an outside system run one connector or flow without a Studio login, publish it. Open Integrations > REST APIs > Published for other systems > Publish an API, choose what it runs and the calls allowed per minute. It starts switched off. Make a key for each calling system (shown once), then Switch on.
bash
curl -X POST "$BASE/api/v1/integration/published/notify-payroll" -H "X-Tenant-Id: $TENANT" -H "X-Api-Key: $KEY" -H "Content-Type: application/json" -d '{"employeeId":"E-1042"}'- The key can be sent as
X-Api-Keyor asAuthorization: Bearer <key>. Only a hash of the key is stored; a lost key cannot be recovered, only replaced. - A connector answers at once with the vendor's response. A flow is queued and returns an execution id.
- An unknown API, a switched-off API and a wrong or revoked key all get the same
401, so a caller learns nothing about what exists. Too many bad keys from one tenant get429. - Each API has its own calls-per-minute limit; beyond it the answer is
429withRetry-After. The body must be a JSON object up to 256 KB. - Runs are audited under the key's first characters (never the key) as
api-key:spk_xxxxxxxx. Revoke one key and the other systems keep working.
Ship it to another environment
Connectors and flows move as a bundle. It holds the definitions and only the names of the secrets they use, never the values.
bash
erp integration export --out integration-bundle.json # in the source environment
erp integration import integration-bundle.json # in the target: a preview, nothing changes
erp integration import integration-bundle.json --apply # import; new items arrive switched off
printf '%s' "$TOKEN" | erp connector secret set echo # add each credential the preview listedIn Studio the same is Integrations > Connector Catalog > Export / Import. After the import, add the credentials listed, Try each connector, then Switch on. A connector or flow that already exists keeps its on/off state.
A plugin can carry connectors too. In Plugin Studio, Integration > Connectors > New connector picks a catalog template and writes metadata/connector/<name>.json; from the command line, put that file in the plugin yourself and check it with erp connector validate. When the plugin is installed, in every tenant that gets it, the connector is created switched off and lists the credential it needs. Uninstalling the plugin leaves its connectors, because pages and flows may already use them.
How to verify
- Try in the catalog, or
erp integration run connector echo --input '{"payload":"hello"}'. A working connector returnsok: trueand the vendor's response. - Each run is written to the audit log as
integration.run(andintegration.run.failedwith the connector's name). Open Administration > Logging and look for theintegration.runentries. - A wrong credential comes back as the vendor's own refusal, for example
provider "echo" returned HTTP 401: .... An unknown name isno connector named "x", and a switched-off connector is reported as switched off. - Connection screens (Integrations > Connections) have Test, which makes one guarded request and reports connected, rejected or unreachable.
What is verified, and what is not: the catalog, secrets, Try and the run endpoint were exercised against a real public service. The page action and the workflow node are covered by automated tests, not yet by a full run through a published page or a running workflow. The Slack, Teams, SendGrid and Razorpay templates are untested against the real services.
Common mistakes
- Putting a key in the connector. Use
secretRef, never the key itself. A literal value would be stored in the connector and readable by anyone who can open it. - Adding a slash.
baseUrlplusrequestPathare joined as written. If the full address is inbaseUrl, leaverequestPathempty. - Trying a private address.
https://localhostor an internal host is refused by design. - Expecting a flow's result at once. A flow is queued. Read its execution in Integration Flows.
- Trusting an untested template. Try it and read the vendor's answer before switching it on.
