A connector is the adapter the integration hub uses to read from and write to one external system, and every connector is one of two kinds: a manifest connector — a reviewed JSON descriptor for a "JSON over HTTPS with standard auth" partner, interpreted by one shared engine — or a compiled connector, written in code for a transport or API that templated HTTP cannot express. Both kinds are dispatched the same way by flow steps, appear in the same connector catalog and get their connection form from that catalog, so an administrator configuring a connection cannot tell which kind they are using. This page is the developer and operator reference for how connectors behave; the per-partner settings of the shipped catalog connectors are on Catalog connectors, and the end-to-end setup is in Connect an external system.
Overview
| Compiled connector | Manifest connector | |
|---|---|---|
| Authored as | Code, by the platform team | A reviewed JSON descriptor shipped with the platform |
| Suits | Databases, message queues, file and object stores, browser automation, APIs that need token exchange, bulk or paging logic | A REST partner reachable with a static bearer token, basic auth or an API-key header |
| Interpreted by | Itself | One shared manifest interpreter |
| Shipped types | http.rest (HTTP REST), salesforce.rest, zoho.books, zoho.payroll, zoho.people, azure.servicebus, azure.blob, sftp, web.browser | hubspot.crm, zendesk.support, shopify.admin, cleartax.gsp |
The type (for example hubspot.crm) is the stable key a connection stores and a flow step dispatches on. Display name, description and documentation link come from the connector itself; when a connector supplies none, the catalog shows its type turned into words.
How xMatix handles it
Capabilities are read from the code
What the catalog says a connector can do is worked out from what the connector implements, never typed into a separate list:
| Capability | Who has it |
|---|---|
| Read and write | Every connector advertises both |
| Test Connection | Every shipped connector, including every manifest connector |
| Multi-page reads (pagination) | http.rest, the three Zoho connectors, azure.blob |
| Bulk write | salesforce.rest, web.browser |
| Binary streaming (attachments) | salesforce.rest, azure.blob |
| Schema discovery for field mapping | salesforce.rest, the three Zoho connectors |
Manifest connectors read one page per call, write one record per call and have no binary path. One caveat: read and write are always advertised, so a manifest that declares only one operation still shows both — calling the missing one fails the step with "does not declare a 'read' operation" (or 'write'). Every shipped manifest declares both.
How a connector step runs
A flow's connector-read or connector-write step names a connection (or a connector type). When it runs, the engine:
- Loads the connection. A connection that is not active fails the step ("references connection … which is inactive").
- Builds the step configuration by merging the connection's configuration with the step's own configuration, one level deep — a key set on the step wins over the same key on the connection.
- Scans the connection and step configuration for
${secret:name}references and fetches each from the integration app's secret store. If any reference cannot be found — or a stored value can no longer be decrypted — the step fails before any call goes out: "references secret(s) that could not be resolved … Re-enter the secret in the integration secrets store". - Hands the merged configuration, the step input, the resolved secrets, the trigger payload and (for an API-endpoint run) the inbound request to the connector.
Secrets are only fetched for steps that use a connection. The resolved values are handed to the connector for that call only; flows and connections keep the ${secret:…} reference, never the value.
Shared HTTP resilience
Manifest connectors and the HTTP-based compiled connectors each get their own HTTP client with the platform's resilience pipeline. The platform defaults are:
- Retries — up to 3 retries on transient failures (HTTP 5xx, 408, 429 and network errors), with exponential back-off from 1 second plus jitter; a partner's
Retry-Afterheader overrides the delay. Retries apply only to safe methods such as GET and HEAD. POST and PATCH writes are never retried, so a write is never duplicated by the platform. - Timeouts — 30 seconds per attempt and 100 seconds in total, including back-off.
- Circuit breaker — opens when half of at least 10 calls in a 30-second window fail with 5xx, 408, a network error or a timeout, and stays open for 15 seconds before probing again. HTTP 429 never opens it. The breaker is kept separately for each partner host and each connection, so one tenant's exhausted quota or one failing endpoint cannot block another connection.
The manifest contract
A manifest describes a REST partner declaratively: where it lives, how to authenticate, how to read, how to write, how to probe the connection, and which fields to ask the administrator for.
{
"manifestVersion": "1",
"type": "example.tickets",
"displayName": "Example Tickets",
"description": "Tickets over the Example v1 REST API.",
"docsUrl": "https://developer.example.com/tickets",
"baseUrl": "https://${config:subdomain}.example.com/api/v1",
"auth": { "scheme": "bearer", "token": "${config:apiToken}" },
"read": { "method": "GET", "path": "/tickets", "query": { "per_page": "${config:pageSize}" }, "itemsPath": "tickets" },
"write": { "method": "POST", "path": "/tickets", "body": { "ticket": "${input}" } },
"test": { "method": "GET", "path": "/tickets", "okBelow": 500 },
"inputs": [
{ "path": "subdomain", "label": "Subdomain", "kind": "text", "required": true },
{ "path": "apiToken", "label": "API token", "kind": "secretRef", "required": true },
{ "path": "pageSize", "label": "Page size", "kind": "number", "defaultValue": 100 }
]
}
Top-level fields
| Field | What it means | Notes |
|---|---|---|
manifestVersion | Version of the manifest format | Optional; defaults to "1" |
type | The connector type — the catalog key and what connections store | Required. Lower-case, dot-separated, stable for the life of the connector |
displayName | The name shown in the connector picker and catalog | Required |
description | One-line description shown in the catalog | Optional |
docsUrl | Link to the partner's API documentation | Optional |
baseUrl | Root URL every operation path is appended to | Required. Must start with https:// or http://; may contain ${config:…} tokens for per-tenant hosts (a subdomain or shop name) |
auth | How every request authenticates | Optional; see the auth table |
read | The read operation | At least one of read or write is required |
write | The write operation | At least one of read or write is required |
test | The Test Connection probe | Optional; without it, Test Connection sends a HEAD request to the base URL |
inputs | The configuration fields the connection form asks for | Optional; without it the connection form has no typed fields and falls back to a raw-JSON editor |
A manifest that breaks any of these rules — missing type, displayName or baseUrl, a base URL without an http(s) scheme, neither operation, an operation without a path, or an unknown auth scheme — is rejected when the platform loads it.
Auth schemes
scheme | Fields | What is sent |
|---|---|---|
none (default) | — | No credentials |
bearer | token | Authorization: Bearer <token>; the header is left out when the token resolves to empty |
basic | username, password | Authorization: Basic <base64 of username:password>; always sent |
apiKey | header, value | The named header with the value; left out when the value resolves to empty |
Every value is templated. The usual pattern is a token pointing at a secretRef input — "token": "${config:apiToken}" — where the administrator stores ${secret:partner-token} in that field. The nested secret reference resolves transparently.
Operation fields (read and write)
| Field | What it means | Notes |
|---|---|---|
method | HTTP method | Optional; defaults to GET for read and POST for write |
path | Path appended to the base URL | Required and templated. A path that resolves to a full http(s):// URL replaces the base URL |
headers | Header name → templated value | Headers are sent even when their value resolves to empty |
query | Query parameter → templated value | A parameter whose value resolves to empty is left out, so optional filters cost nothing |
itemsPath | Dotted path to the record collection in the response (read) | When it resolves, the flow receives just that value; otherwise it receives the { status, ok, body } envelope |
body | Request body template (write) | When omitted, the step input is sent as the body unchanged. Always sent as application/json |
Test probe fields (test)
| Field | What it means | Notes |
|---|---|---|
method | HTTP method of the probe | Optional; defaults to GET |
path | Path to probe | Required when test is present |
okBelow | Status codes below this count as success | Default 500. Every shipped manifest uses 500, so a 401 or 403 still shows as a successful test — read the status in the result |
Input fields (inputs[])
| Field | What it means | Notes |
|---|---|---|
path | The configuration key the value is saved under | Required; read back with ${config:<path>} |
label | The field label on the connection form | Required |
kind | The field type | text (default), number, boolean, select, secretRef, and the other connection-form kinds |
required | Whether the form insists on a value | Default false |
help, placeholder | Guidance shown with the field | Optional |
defaultValue | Initial value | Any JSON value |
span | Field width on the form grid | Optional |
options | { value, label } pairs for select | Values are what get stored |
A secretRef field renders as a text box with a Pick list of your app's secret names beside it (shown to app Admins, who can list secrets); it stores the ${secret:name} reference, never the value.
Template tokens
Tokens are written ${namespace:dotted.path}; leaving the path out (${input}) selects the whole value. Paths walk JSON objects only (not array positions), and a segment that does not match exactly falls back to a case-insensitive match, so ${input:id} finds a field named Id. A token that does not resolve becomes an empty string — it never fails the call by itself.
| Token | Resolves to | In a manifest connector |
|---|---|---|
${secret:name} | A secret from the integration app's secret store | Yes — but see the note below |
${config:a.b} | A value from the merged connection and step configuration; a ${secret:…} stored inside the value resolves too | Yes |
${input:a.b} | A value from the step's input record | Yes |
${trigger:a.b} | The payload of the trigger that started the run (for a record-event trigger: entity, op, id) | Yes |
${request:a.b} | The inbound request of an API-endpoint run (method, path, query.*, headers.*, body.*, contentType) | Yes; empty in every other kind of run |
${step:id.path} | An earlier step's output | No — resolves to empty; use the generic http.rest connector |
${transient:name} | A value supplied for one run only | No — resolves to empty |
Secrets must appear in configuration. The engine fetches only the secret references it finds in the connection or step configuration. A ${secret:name} written directly into a manifest resolves only when the same reference is also stored in the connection — which is why every shipped manifest pairs it with a secretRef input.
Whole-token values keep their type. In a body, a string whose entire value is one ${input…}, ${config…}, ${trigger…} or ${request…} token is replaced by the resolved JSON value with its type kept — "properties": "${input}" embeds the whole input object, and a number stays a number. Any other string has its tokens substituted as text, objects and arrays as compact JSON.
What the flow receives
- Read with a resolving
itemsPath— the selected value (normally an array of records). - Read without
itemsPath, or when it does not resolve, and every write — an envelope{ "status": <code>, "ok": <true for 2xx>, "body": <parsed JSON, or the raw text> }. A partner error therefore reaches the next step asok: falsewith the partner's response inbody; design the flow to check it.
Current limitations
The manifest engine reads one page per call (no pagination), writes one record per call (no bulk), supports only static bearer, basic and API-key auth (no token exchange), and sends JSON bodies only. A partner that needs paging, a token from an earlier step or a run-time credential can use the generic http.rest connector, which adds offset or cursor paging, a body template, ${step:…} and ${transient:…} tokens. Form-encoded, SOAP or other non-JSON APIs need a compiled connector — http.rest also sends JSON.
Procedure
Step 1 — Find out which connector a partner needs
Open Setup → Platform → Integrations, open your integration app, go to Connections and select New Connection. The connector-type picker lists every connector the platform ships, with its capabilities. If the partner is listed, use it. If not and it is a JSON-over-HTTPS API with header-based auth, use HTTP REST. Otherwise, ask xMatix for a connector.
Step 2 — Store the credential as a secret
On the app's Secrets tab select Add Secret, give it a reference name such as partner-token, and paste the value. The value is write-only from then on. See Credentials and rotation.
Step 3 — Fill in the connection form
Pick the connector type. A manifest connector shows the fields its inputs declare; required fields are marked. In each secret field choose or type the ${secret:partner-token} reference. Save.
Step 4 — Test the connection
Select Test Connection. The result shows the URL probed and its HTTP status ("Reached … (HTTP 200)" or "… returned HTTP 503"). With the shipped manifests a 401 or 403 still counts as reachable, so read the status: anything other than 2xx means the credential or permissions are not right yet. Follow a green test with a safe read in a real run — a flow preview does not call the partner.
Step 5 — Use it in a flow
Add a connector-read or connector-write step to a flow and choose the connection. Settings placed on the step override the same keys from the connection — for example, a different object type for this one step. Preview does not resolve tokens, so confirm tokens with a real run.
Example
A support team wants new tickets from an invented partner, "Example Tickets", pulled into xMatix every hour, and xMatix has shipped the example.tickets manifest shown above.
- The administrator adds a secret
example-tokenholding the partner's API token. - They create a connection of type Example Tickets with Subdomain
acme-support, API token${secret:example-token}and Page size 50. - Test Connection reports "Reached https://acme-support.example.com/api/v1/tickets (HTTP 200)".
- A scheduled flow's connector-read step uses the connection. At run time the engine finds
${secret:example-token}in the connection, fetches it, and the manifest sendsGET https://acme-support.example.com/api/v1/tickets?per_page=50withAuthorization: Bearer <token>. - The partner answers
{ "tickets": [ … ], "next_page": "…" }. BecauseitemsPathistickets, the next step receives just the 50 ticket records.next_pageis ignored — only the first page arrives, so the hourly schedule has to keep up with ticket volume.
Training
Practice exercise
In a sandbox, create an integration app with a secret and an HTTP REST connection to an endpoint your trainer gives you, then create a second connection of a catalog type (for example Zendesk Support) with a deliberately wrong token. Test both. Expected result: both tests report "Reached …", but the catalog connection shows a 401 or 403 status — showing that a green test proves reachability, not a valid credential. Now delete the secret the HTTP REST connection references and run a flow that uses it: the step fails before calling out, naming the missing secret.
Quick reference
- Manifest connector = reviewed JSON descriptor; compiled connector = code. Both look identical to administrators.
- Capabilities shown in the catalog come from code, not from settings.
- Step configuration overrides connection configuration key by key.
- Secrets are fetched only when referenced in the connection or step configuration.
- A missing secret fails the step before any call; Test Connection does not catch it.
- Test Connection with the shipped manifests passes on any status below 500.
- Manifest reads return one page; writes send one record; bodies are JSON.
${step:…}and${transient:…}do not work in manifest connectors — use HTTP REST.- POST and PATCH writes are never retried by the platform.
Permissions
Everything on this page sits behind the integration administration capability, which opens Setup → Platform → Integrations, plus a role on the specific integration app (granted on the app's Members tab to security profiles):
| App role | What it allows |
|---|---|
| Viewer | Read-only: list runs, errors, approvals |
| Operator | Replay runs, decide approvals, trigger flows |
| Connection Manager | Operator plus managing connections and secrets — including Test Connection |
| Admin | Full control, including app settings and membership |
A user with the capability but no role on an app can see the app list but is refused inside the app. Nobody in a tenant can add or edit a manifest; manifests ship with the platform.
Configuration
- Connections — Setup → Platform → Integrations → app → Connections: connector type and its form fields. Changing a connection affects every flow step that uses it on the next run.
- Secrets — the app's Secrets tab: write-only values referenced as
${secret:name}. Rotating a value changes nothing else. - Step overrides — keys set on a connector step's configuration win over the connection's keys for that step only.
- Connection active flag — an inactive connection fails every step that uses it.
- Resilience — retry, timeout and circuit-breaker values are platform settings, the same for all tenants; they are not configurable per connection.
Common problems
"Test Connection" is green but every run fails with 401
The shipped manifests count any status below 500 as reachable. Check the status in the test result; a 401 or 403 means the token, its scopes or the account are wrong. Store a corrected value on the Secrets tab — no flow edits are needed.
The step fails with "references secret(s) that could not be resolved"
A ${secret:…} reference in the connection or step has no stored value in this app, or the stored value can no longer be decrypted. Re-enter the secret on the app's Secrets tab under exactly the referenced name. Test Connection does not catch this — it substitutes an empty value.
The step fails with "references connection … which is inactive"
The connection was switched off. Reactivate it or point the step at another connection.
The read returns { status, ok, body } instead of records
The itemsPath did not resolve — usually because the partner returned an error (look at status and body), or because the records sit inside an array element, which paths cannot index.
A value I used in a header or URL comes out empty
The token's path did not resolve, or it is a ${step:…} or ${transient:…} token, which manifest connectors do not support. Check the spelling against the step input, or use the HTTP REST connector.
Only the first page of records arrives
Manifest reads fetch one page. Raise the page size within the partner's limit, schedule the flow often enough, or use HTTP REST with paging for a full pull.
Common questions
When should I use HTTP REST instead of asking for a manifest?
When you need the partner now and its API takes static headers. HTTP REST reads, writes, pages with offset or cursor strategies, can build a body from earlier steps and tests against any endpoint, but you write the URL, headers and request shape on every connection or step. A manifest earns its place by packaging the partner's specifics — auth, per-tenant host, where records sit in the response, and a typed form — so administrators configure "Zendesk" rather than "HTTP". The two use the same secret handling and resilience pipeline, so choosing HTTP REST costs convenience, not safety.
How are partner credentials protected?
Credentials live in the integration app's secret store, encrypted and write-only. Connections and flow steps hold only ${secret:name} references; the engine fetches the values for each call and never writes them back into configuration. A secret field on a connection form stores the reference, not the value. Because everything points at the reference, rotating a credential is a single update on the Secrets tab, and an exported configuration never contains a credential.
Can we write our own manifest?
No. Manifests are packaged with the platform and reviewed like code, because a manifest decides where the platform sends HTTP calls — the review is a security control. Tenants cannot add or change one. If a REST partner is missing, use the HTTP REST connector or ask xMatix to add the partner; a clean REST partner is usually a small manifest.
Why does Test Connection pass with a wrong token?
Its job is to prove the partner can be reached with your configuration. Every shipped manifest treats any status below 500 as a pass so that a 401 or 403 reaches you as a status code instead of an unexplained failure. Read the status in the result, and confirm the credential with a safe read before relying on the connection.
