xMatix
Sign in Request demo
xMatix
PRODUCTS
SalesField Sales & SFACRMRewardsClaimsInventoryProcurementWarehouse ManagementField ServiceServiceSupportTelephony & MessagingFinance & AccountingPayrollExpense ManagementCommercePortalsAnalytics & ReportingData StudioMobile AppSee all products →
PLATFORM
Platform overviewApp BuilderAutomationIntegrationsSecurity & GovernanceChange ManagementDevelopers
SENSE AI
Sense AI overviewSense AssistSense ControlSense VisionAI StudioTrust & governanceIn Claude & ChatGPTUse cases
SOLUTIONS
Auto DMSConsumer Goods DMSSales Force Automation (SFA) FMCG & DistributionManufacturing & Dealer NetworksAutomotive & DealershipsPharma & HealthcareConsumer DurablesAgri-InputsBuilding MaterialsService NetworksWarehousing & 3PLFinancial AccountingERP SoftwareIndia GST ComplianceUAE VAT & e-InvoicingSaudi ZATCA & VATAll solutions →
RESOURCES
Knowledge CenterDeveloper & CLIBlogGuidesWhat is xMatix?Company facts
COMPANY
AboutCareersPartnersEventsContactAuthorsLegal
Sign in Request demo
Home/Docs/Developer/Connector authoring
REFERENCE · Last reviewed

Connector authoring

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 connectorManifest connector
Authored asCode, by the platform teamA reviewed JSON descriptor shipped with the platform
SuitsDatabases, message queues, file and object stores, browser automation, APIs that need token exchange, bulk or paging logicA REST partner reachable with a static bearer token, basic auth or an API-key header
Interpreted byItselfOne shared manifest interpreter
Shipped typeshttp.rest (HTTP REST), salesforce.rest, zoho.books, zoho.payroll, zoho.people, azure.servicebus, azure.blob, sftp, web.browserhubspot.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:

CapabilityWho has it
Read and writeEvery connector advertises both
Test ConnectionEvery shipped connector, including every manifest connector
Multi-page reads (pagination)http.rest, the three Zoho connectors, azure.blob
Bulk writesalesforce.rest, web.browser
Binary streaming (attachments)salesforce.rest, azure.blob
Schema discovery for field mappingsalesforce.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:

  1. Loads the connection. A connection that is not active fails the step ("references connection … which is inactive").
  2. 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.
  3. 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".
  4. 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-After header 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

FieldWhat it meansNotes
manifestVersionVersion of the manifest formatOptional; defaults to "1"
typeThe connector type — the catalog key and what connections storeRequired. Lower-case, dot-separated, stable for the life of the connector
displayNameThe name shown in the connector picker and catalogRequired
descriptionOne-line description shown in the catalogOptional
docsUrlLink to the partner's API documentationOptional
baseUrlRoot URL every operation path is appended toRequired. Must start with https:// or http://; may contain ${config:…} tokens for per-tenant hosts (a subdomain or shop name)
authHow every request authenticatesOptional; see the auth table
readThe read operationAt least one of read or write is required
writeThe write operationAt least one of read or write is required
testThe Test Connection probeOptional; without it, Test Connection sends a HEAD request to the base URL
inputsThe configuration fields the connection form asks forOptional; 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

schemeFieldsWhat is sent
none (default)—No credentials
bearertokenAuthorization: Bearer <token>; the header is left out when the token resolves to empty
basicusername, passwordAuthorization: Basic <base64 of username:password>; always sent
apiKeyheader, valueThe 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)

FieldWhat it meansNotes
methodHTTP methodOptional; defaults to GET for read and POST for write
pathPath appended to the base URLRequired and templated. A path that resolves to a full http(s):// URL replaces the base URL
headersHeader name → templated valueHeaders are sent even when their value resolves to empty
queryQuery parameter → templated valueA parameter whose value resolves to empty is left out, so optional filters cost nothing
itemsPathDotted 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
bodyRequest body template (write)When omitted, the step input is sent as the body unchanged. Always sent as application/json

Test probe fields (test)

FieldWhat it meansNotes
methodHTTP method of the probeOptional; defaults to GET
pathPath to probeRequired when test is present
okBelowStatus codes below this count as successDefault 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[])

FieldWhat it meansNotes
pathThe configuration key the value is saved underRequired; read back with ${config:<path>}
labelThe field label on the connection formRequired
kindThe field typetext (default), number, boolean, select, secretRef, and the other connection-form kinds
requiredWhether the form insists on a valueDefault false
help, placeholderGuidance shown with the fieldOptional
defaultValueInitial valueAny JSON value
spanField width on the form gridOptional
options{ value, label } pairs for selectValues 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.

TokenResolves toIn a manifest connector
${secret:name}A secret from the integration app's secret storeYes — but see the note below
${config:a.b}A value from the merged connection and step configuration; a ${secret:…} stored inside the value resolves tooYes
${input:a.b}A value from the step's input recordYes
${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 outputNo — resolves to empty; use the generic http.rest connector
${transient:name}A value supplied for one run onlyNo — 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 as ok: false with the partner's response in body; 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.

  1. The administrator adds a secret example-token holding the partner's API token.
  2. They create a connection of type Example Tickets with Subdomain acme-support, API token ${secret:example-token} and Page size 50.
  3. Test Connection reports "Reached https://acme-support.example.com/api/v1/tickets (HTTP 200)".
  4. 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 sends GET https://acme-support.example.com/api/v1/tickets?per_page=50 with Authorization: Bearer <token>.
  5. The partner answers { "tickets": [ … ], "next_page": "…" }. Because itemsPath is tickets, the next step receives just the 50 ticket records. next_page is 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 roleWhat it allows
ViewerRead-only: list runs, errors, approvals
OperatorReplay runs, decide approvals, trigger flows
Connection ManagerOperator plus managing connections and secrets — including Test Connection
AdminFull 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.