Appearance
REST APIs and GraphQL
This page covers two Explorer screens. REST APIs lists the HTTP APIs the tenant already has (a data API per entity, call addresses per flow, one door for connectors) and publishes key-protected addresses for outside systems. GraphQL manages GraphQL, SOAP and SFTP connections and calls them for testing. Readers are integration developers and administrators.
REST APIs
Where to find it
Studio Explorer > Workspace > Integrations > REST APIs. Page key api-catalog. Two tabs: What exists and Published for other systems.
What exists
The catalog is built from live records; there is nothing separate to maintain. Designing an entity, a flow or a connector is what publishes its API. A banner states that every call needs the X-Tenant-Id header (the tenant number is shown) and a signed-in session, and that the caller's permissions decide what is allowed.
| Kind | One row per | Method | Address | Note |
|---|---|---|---|---|
| Data | Active entity | GET POST PUT DELETE | /api/v1/entities/ENTITY/records | "Search, read, create, change and delete records. Permissions of the caller apply." |
| Flow | Flow | POST | /api/v1/integration/flows/CODE/execute | "Starts the flow for a signed-in caller; returns an execution id." |
| Flow | Flow, "(from another system)" | POST | /api/v1/integration/flows/webhooks/CODE | "Signed requests only." or "Open to anyone with the address. Protect it under Webhooks > Receiving." |
| Connector | Connector definition in the integration domain | POST | /api/v1/integration/run | Send {"kind":"connector","key":"KEY","input":{...} }. "Switched off." is appended for inactive connectors. |
Chips filter by kind (All, Data, Flows, Connectors) with counts. Each row has Copy address, which copies the address with the server base. If a source cannot be read the screen warns "Could not list data, flows, connectors. You may not have permission to see them."
Running a flow or connector from a page, a workflow or code
POST /api/v1/integration/run runs one connector now (the answer is returned) or queues one flow (an execution id is returned). The body is {"kind":"connector|flow","key":"...","input":{...} }; the header X-Idempotency-Key is honoured. Responses:
json
{ "kind": "flow", "key": "order-to-partner", "ok": true, "executionId": 412, "status": "QUEUED" }json
{ "kind": "connector", "key": "slack-alerts", "ok": true, "status": 200, "reference": null, "mappedStatus": null, "url": null, "response": { "ok": true } }Permission integration.run / execute. Limit 120 runs a minute per tenant ("too many integration runs in the last minute; try again shortly", 429). Errors: 400 "say what to run: kind (connector or flow) and key", 404 no flow named "X" or no connector named "X", 409 connector "X" is switched off, 422 when a flow cannot be queued, 502 with the provider's message when a connector call fails. Each run is audited.
Published for other systems
A published API lets an outside system run one connector or flow with a key, without a Studio login. It starts switched off.
Publish an API dialog
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Name | text | empty | Yes | The address name is derived: "Address ends with /published/SLUG". |
| Runs | select | none | Yes | A connector or a flow from a combined list. "A connector answers at once. A flow is queued and returns an execution id." |
| Calls allowed per minute | number | 60 | No | Per API. |
The slug is lower-case letters, digits and dashes, up to 63 characters. The grid shows API (name and what it runs), Address (POST BASE/api/v1/integration/published/SLUG), Keys (active count), Limit and Status.
Keys
Row action Keys lists each key with its name, short prefix (spk_...) and "last used TIME" or "never used", and Revoke. Make one key per calling system so one can be stopped without affecting the others. New key requires a name ("name the key after the system that will use it"); the key is shown once with a ready curl example:
bash
curl -X POST "https://erp.example.com/api/v1/integration/published/partner-orders" \
-H "X-Tenant-Id: 1" -H "X-Api-Key: spk_xxxxxxxx" \
-H "Content-Type: application/json" -d '{"orderNo":"A-1001"}'The key may be sent as X-Api-Key or as Authorization: Bearer KEY. The body must be a JSON object up to 256 KB.
Behaviour
| Rule | Value |
|---|---|
| Unknown API, switched-off API and wrong key | The same answer, 401 "missing or incorrect API key", so a caller learns nothing about what exists. |
| Rejected keys | After 30 rejected calls a minute per tenant, 429 "too many rejected calls; try again shortly". |
| Per-API rate | 429 with Retry-After: 60 and "this API allows N calls a minute". |
| Body | 400 "the body must be a JSON object"; 413 "the request body is larger than 256 KB". |
| Idempotency | The header X-Idempotency-Key. |
| Audit | Each run is audited under the key's short prefix, never the key. The key itself is stored hashed. |
| Switch off, delete | Switch off stops calls at once; deleting removes the API and its keys. |
Procedure: let a partner start a flow
- On Published for other systems select Publish an API. Name
Partner orders, Runsorder-to-partner (flow), 60 calls a minute. Select Publish. - Select Switch on.
- Select Keys, enter
Partner ACME, select New key and copy the key. - Give the partner the address and the key. They call it; the response is
{"kind":"flow","key":"order-to-partner","ok":true,"executionId":N,"status":"QUEUED"}. - Open the flow's history on Integration Flows to see the run, trigger type
API.
Permissions
integration.api: view (list), manage (publish, switch, delete, create and revoke keys). Calling a published API needs only the key. Without permission the screen shows the 403 message.
API
| Purpose | Request |
|---|---|
| List | GET /api/v1/integration/apis (each with slug, name, kind, targetKey, active, rateLimitPerMin, path, keys) |
| Publish | POST /api/v1/integration/apis with {"slug":"partner-orders","name":"Partner orders","kind":"flow","targetKey":"order-to-partner","rateLimitPerMin":60} |
| Switch | POST .../{slug}/active with {"active":true} |
| Delete | DELETE .../{slug} |
| Create key | POST .../{slug}/keys with {"name":"Partner ACME"} (returns key once) |
| Revoke key | DELETE /api/v1/integration/apis/keys/{keyId} |
| Call | POST /api/v1/integration/published/{slug} |
There is no erp command to manage published APIs.
Errors and troubleshooting
| Message | Cause |
|---|---|
| "the address name must be lower-case letters, digits and dashes" | Bad slug. |
| "an API runs a connector or a flow" | kind is neither. |
| "choose what the API runs" / "give the API a name" | |
| "there is already an API called X" (409) | Slug taken. |
| "no API X" (404) | |
| "name the key after the system that will use it" | Empty key name. |
| "no active key N" (404) | Key already revoked. |
GraphQL
The Explorer node opens the Connectors screen on its Integration tab. It manages connections of type GraphQL, SOAP and SFTP (REST connections are managed on Connections, where the same records also appear) and has a test console for each row. The other tabs of the same screen are described under External Connectors.
Where to find it
Studio Explorer > Workspace > Integrations > GraphQL. Page key graphql-connections (the Connectors screen, tab Integration).
New Integration Connection dialog
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Connection Code | text | empty | Yes | Disabled when editing. |
| Type | select | GRAPHQL | Yes | GRAPHQL, SOAP or SFTP. Disabled when editing. |
| Name | text | empty | Yes | |
| Base URL | text | empty | Yes | The endpoint. For SFTP sftp://host:22. |
| Auth Type | select | NONE | Yes (not SFTP) | NONE, API_KEY, BASIC, BEARER, OAUTH2_CLIENT_CREDENTIALS. |
| Secret | password | empty | When auth needs one | "Leave blank to keep the current one" when editing. |
| Username | text | empty | SFTP | Saved in the connection's settings. SFTP always signs in with a password here. |
For richer set-up (key sign-in, host key pinning, OAuth fields) use the Connections screen.
Test console (expand a row)
| Type | Inputs | Result |
|---|---|---|
| GRAPHQL | Query (default { __typename }), Variables (JSON, default {}), Execute | JSON data on success; Failed: ERRORS when the errors array is non-empty or the transport failed. A GraphQL answer with errors is a failure even on HTTP 200. |
| SOAP | SOAPAction, Body XML (default <Body/>), Call | The response body XML, or Fault CODE: MESSAGE for a SOAP 1.1 fault, including faults on a non-2xx status. |
| SFTP | Remote Directory (default /), List Files, Health Check | A file table (name, size, directory) and a Healthy or Unreachable chip. |
API
| Purpose | Request |
|---|---|
| GraphQL | POST /api/v1/integrations/connections/{code}/graphql with {"query":"...","variables":{} } |
| SOAP | POST .../{code}/soap with {"soapAction":"...","bodyXml":"..."} |
| SFTP list | GET .../{code}/sftp/files?remoteDirectory=/ |
| SFTP download | GET .../{code}/sftp/download?remotePath=... returns contentBase64 |
| SFTP upload | POST .../{code}/sftp/upload with {"remotePath":"...","contentBase64":"..."} |
| SFTP delete | DELETE .../{code}/sftp?remotePath=... |
| SFTP health | GET .../{code}/sftp/health |
Note the path prefix /api/v1/integrations/ (plural) for these direct calls, against /api/v1/integration/ for everything else. Permission resource integration: execute for every call except SFTP health, which needs view. A connection of the wrong type is refused with 422 connection "X" is connection_type TYPE, not EXPECTED; an unknown code returns 404 no connection "X". Direct calls are audited (integration.graphql.executed, integration.soap.executed, integration.sftp.uploaded, integration.sftp.deleted).
Flows reach SFTP through the sftp.* actions on an SFTP connection, and databases through db.query and db.write. GraphQL and SOAP connections are not called by a flow step in this release; a flow that needs one makes a REST step to the direct-call endpoint above, or calls the service as an ordinary REST connection.
bash
curl -X POST https://erp.example.com/api/v1/integrations/connections/crm-graphql/graphql \
-H "X-Tenant-Id: 1" -H "X-Actor: alice" -H "Content-Type: application/json" \
-d '{"query":"query($id: ID!) { customer(id: $id) { name } }","variables":{"id":"42"}}'The response is {"success":true,"data":{...},"errors":[],"rawErrorMessage":null}.
Related
Connections, Flows, Connectors, API designer, Connect to another system.
