Chapter 1 of 12
Choose the integration direction
Start with the direction of travel. The transport, credential and failure model follow from this choice.
| You need to | Use |
|---|---|
| Create or update business records | The Data REST API for a single record, bulk API for batches, or file import for operator-led loads. |
| Start a workflow from your code | The Automation client API with an API key scoped to the workflow. |
| Start a workflow when another service emits an event | The external system’s signed inbound HTTPS endpoint. |
| Call another service during a workflow | Choose an available External System and activity, connect the account to use and map workflow data. Register and define operations when adding a custom system. |
| Receive changes from Data or Automation | An outbound webhook subscription delivered to HTTPS, Amazon SQS, Amazon SNS or Kafka. |
Chapter 2 of 12
Create and scope credentials
Use one credential per integration and grant only the record types, workflows and request budget that integration needs.
| Caller | Credential |
|---|---|
| A signed-in person | Their browser session and product permissions; do not create an API key. |
| Your backend calling Data | A Data API key scoped to the required record types, with its own per-minute and per-hour limits. |
| Your backend starting Automation | An Automation API key scoped to the workflows it may start or inspect. |
| A third party pushing an event | That registered external system’s inbound HMAC secret. |
| SynaptaGrid calling your HTTPS receiver | The outbound subscription secret used by your receiver to verify X-Signature-256. |
- Copy a newly issued secret immediately and store it in your secret manager, never in source or browser code.
- Use separate keys for development, staging and production so a test integration cannot reach production records or runs.
- Send X-API-Key and X-App-Instance-Guid on Data and Automation Client-tier calls. Copy the environment base URL and instance GUID from the product integration screen; do not infer either from another environment.
- Data keys support read/write grants, optional source-IP ranges, expiry, and per-minute/per-hour limits. Automation keys support start/read grants per workflow, optional source-IP ranges, and expiry.
- Record an owner and expiry date. Data rate limits report X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 also supplies Retry-After. X-RateLimit-Reset and Retry-After are both a number of seconds to wait, not a timestamp, so add them to the current time rather than reading them as one.
- Data API-key callers see published schemas, not a working draft that is still being modeled.
Chapter 3 of 12
Send records into Data
Publish the record type first, then use its generated REST surface. The published schema is the contract your integration writes against.
- 01
Publish the record type
Resolve breaking-change and migration warnings before treating the new version as an integration contract.
- 02
Mint a narrow key
Limit it to the record types the source owns and set request limits appropriate to its traffic.
- 03
Read the generated schema
Use the schema and generated API reference for exact field names, types, required values and the record-type URL.
- 04
Choose single or bulk writes
Use the flat record endpoint for one record and the flat bulk endpoint for batches. A bulk request still counts every row against quota.
- 05
Persist the response identifiers
Keep the record GUID and source correlation identifier so later updates and support investigations address the same record.
POST /v1/egav/client/entity/{record_type}/attribute-set/{schema}/v{version}/flat/
X-API-Key: <data-api-key>
X-App-Instance-Guid: <data-app-instance-guid>
Content-Type: application/json
{
"external_id": "crm-87421",
"status": "received"
}{
"data": {
"id": 42,
"guid": "<stable-record-guid>",
"external_id": "crm-87421",
"status": "received"
},
"success": true,
"status": "success"
}- Use the record GUID as the durable external identifier. Single-record reads accept either the numeric id or GUID.
- List responses add meta.total, meta.page, meta.per_page and meta.total_pages. Keep per_page between 1 and 100.
- If the schema is live-on-save, the write is immediately readable. If controlled publishing is enabled, call POST .../flat/{id}/publish before Client-tier reads can see the new working state.
- The generated Data write surface does not currently expose a request-level idempotency key. Make a source identifier such as external_id unique and reconcile an uncertain outcome before creating again.
Chapter 4 of 12
Start Automation from an external system
Use the client API when your application is deliberately starting a known workflow. Use a signed inbound source when another system is publishing an event.
| Path | Duplicate protection |
|---|---|
| Client API | Send a stable idempotency_key in the JSON body. Replaying it is a no-op replay and the response marks idempotent_replay=true. |
| Signed inbound event | Send a stable event id in the event body. Re-delivery of that event id does not create a second run. |
POST /v1/automation/client/workflows/{workflow_code}/start
X-API-Key: <automation-api-key>
X-App-Instance-Guid: <automation-app-instance-guid>
Content-Type: application/json
{
"workflow_id": "order-87421",
"idempotency_key": "start:order-87421:v1",
"subject": {"type": "entity", "source_app_code": "egav", "source_app_instance_guid": "<data-app-instance-guid>", "entity_type": "order", "guid": "<record-guid>"},
"input": {"order_id": "87421"},
"metadata": {"source": "commerce-api"}
}| Client operation | Contract |
|---|---|
| POST /v1/automation/client/workflows/{workflow_code}/start | Requires a start grant. Returns workflow_code, workflow_id, run_id, started_at, idempotent_replay and backend. |
| GET /v1/automation/client/executions/{guid} | Requires a read grant for that execution’s workflow. Use the execution guid returned by status data; the start response’s run_id is the executor correlation value. Returns 404 outside the key’s instance or grant so callers cannot probe names. |
| GET /v1/automation/client/executions/?workflow_code={code}&status={status}&limit=50 | Lists up to 100 recent runs. A per-workflow key must send workflow_code; only a wildcard read grant may omit it. |
- 01
Register the source
Create an external system, mark it as an event source and copy its generated inbound secret.
- 02
Bind the workflow
Choose the external source and event type, add filters, validate the workflow, publish it and arm the trigger.
- 03
Serialize once
Create the final UTF-8 JSON bytes. Compute the HMAC over those exact raw bytes; do not parse and reformat after signing.
- 04
Post to the displayed inbound URL
POST /v1/automation/public/webhooks/{app_instance_guid}/{source_code}/inbound with X-Signature-256: sha256=<hex>. This HMAC is the credential; do not send a bearer token.
- 05
Keep the returned run identity
Store the workflow and run identifiers beside your source event id for status checks and support.
raw = UTF8(JSON body)
digest = HMAC_SHA256(inbound_secret, raw).hex()
X-Signature-256: sha256=<digest>{
"event_id": "commerce:event:87421",
"event_type": "order.ready",
"data": {"order_id": "87421", "total": 125.50}
}Chapter 5 of 12
Copy-ready integration examples
Replace the angle-bracket values with the coordinates and secrets shown in your product integration screen. Keep every secret on the server side.
# Create a working record
curl --request POST "<base-url>/v1/egav/client/entity/order/attribute-set/default/v1/flat/" \
--header "X-API-Key: <data-api-key>" \
--header "X-App-Instance-Guid: <data-app-instance-guid>" \
--header "Content-Type: application/json" \
--data '{"external_id":"crm-87421","status":"received","amount":125.50}'
# Reconcile by source id; per_page cannot exceed 100
curl --get "<base-url>/v1/egav/client/entity/order/attribute-set/default/v1/flat/" \
--header "X-API-Key: <data-api-key>" \
--header "X-App-Instance-Guid: <data-app-instance-guid>" \
--data-urlencode "filters[external_id]=crm-87421" \
--data-urlencode "page=1" \
--data-urlencode "per_page=10"
# Only for a schema configured for controlled publishing
curl --request POST "<base-url>/v1/egav/client/entity/order/attribute-set/default/v1/flat/<record-guid>/publish" \
--header "X-API-Key: <data-api-key>" \
--header "X-App-Instance-Guid: <data-app-instance-guid>"curl --request POST "<base-url>/v1/automation/client/workflows/order_fulfilment/start" \
--header "X-API-Key: <automation-api-key>" \
--header "X-App-Instance-Guid: <automation-app-instance-guid>" \
--header "Content-Type: application/json" \
--data '{
"workflow_id":"order-87421",
"idempotency_key":"start:order-87421:v1",
"subject":{"type":"entity","source_app_code":"egav","source_app_instance_guid":"<data-app-instance-guid>","entity_type":"order","guid":"<record-guid>"},
"input":{"order_id":"87421"},
"metadata":{"source":"commerce-api"}
}'
# Find the execution and retain its guid for direct status reads
curl --get "<base-url>/v1/automation/client/executions/" \
--header "X-API-Key: <automation-api-key>" \
--header "X-App-Instance-Guid: <automation-app-instance-guid>" \
--data-urlencode "workflow_code=order_fulfilment" \
--data-urlencode "limit=50"
curl "<base-url>/v1/automation/client/executions/<execution-guid>" \
--header "X-API-Key: <automation-api-key>" \
--header "X-App-Instance-Guid: <automation-app-instance-guid>"{
"workflow_code": "order_fulfilment",
"workflow_id": "order-87421",
"run_id": "<executor-run-id>",
"started_at": "2026-08-03T12:00:00Z",
"idempotent_replay": false,
"backend": "state_machine"
}
// Repeating the same JSON idempotency_key returns the same logical start
// with idempotent_replay set to true. It does not create another run.import { createHmac } from 'node:crypto';
const secret = process.env.AUTOMATION_INBOUND_SECRET;
if (!secret) throw new Error('AUTOMATION_INBOUND_SECRET is required');
const event = {
event_id: 'commerce:event:87421',
event_type: 'order.ready',
data: { order_id: '87421', total: 125.50 },
};
const rawBody = Buffer.from(JSON.stringify(event), 'utf8');
const digest = createHmac('sha256', secret).update(rawBody).digest('hex');
const response = await fetch(
'<base-url>/v1/automation/public/webhooks/<app-instance-guid>/<source-code>/inbound',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Signature-256': `sha256=${digest}`,
},
body: rawBody,
},
);
if (!response.ok) throw new Error(`Inbound event failed: ${response.status}`);
console.info(await response.json()); // deduplicated, matched_binding_count, started_run_idsimport { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody must be captured before any JSON body parser changes it.
function verifyWebhook(rawBody, signatureHeader, secret) {
const suppliedHex = signatureHeader?.replace(/^sha256=/, '') ?? '';
const expected = Buffer.from(createHmac('sha256', secret).update(rawBody).digest('hex'), 'hex');
const supplied = Buffer.from(suppliedHex, 'hex');
return supplied.length === expected.length && timingSafeEqual(supplied, expected);
}
if (!verifyWebhook(rawBody, request.headers['x-signature-256'], webhookSecret)) {
return response.status(401).end();
}
const cloudEvent = JSON.parse(rawBody.toString('utf8'));
// Allowlist cloudEvent.source and cloudEvent.type before processing cloudEvent.data.BEGIN;
INSERT INTO processed_events (event_id, event_type, received_at)
VALUES (:cloud_event_id, :cloud_event_type, CURRENT_TIMESTAMP)
ON CONFLICT (event_id) DO NOTHING;
-- Apply the business change only when the INSERT added one row.
-- A duplicate should make no change and still return HTTP 2xx.
COMMIT;if (response.status === 429) {
const retryAfterSeconds = Number(response.headers.get('Retry-After') ?? '1');
await waitWithJitter(retryAfterSeconds * 1000);
// Retry with the same Automation idempotency_key or inbound event_id.
} else if (response.status >= 500) {
await backoffWithJitter();
// Reconcile a Data create before repeating it; Data has no request idempotency key.
} else if (!response.ok) {
throw await contractOrPermissionError(response); // Correct 4xx; do not retry unchanged.
}Chapter 6 of 12
Turn an external API into workflow steps
Select a supplied activity or define a custom API operation, then map it into a workflow step.
- 01
Choose the system
Use an available supplied External System. For a custom API, register its base URL, authentication, retry policy, throttling and concurrency limits.
- 02
Select operations
Managed systems supply protected activities and entity definitions. For a custom system, fetch or upload an API description and import only useful operations.
- 03
Define a custom operation
If your custom service has no usable description, provide the method, path, typed input and output, and whether the response is synchronous.
- 04
Choose the account
Select the named private account connection for the activity and review its permission check before running.
- 05
Map inputs
Map from the trigger, an earlier step output, a signal, a fixed value, a template or a computed value.
- 06
Map outputs and arm
Map useful response values back to later steps or records. Arming compiles and validates the resolved mappings.
Chapter 7 of 12
Choose an account for each activity
Accounts belong inside External Systems. The system defines the activity; the selected account supplies its private authentication.
- 01
Connect inside the system
Open the External System configuration and its connection settings. Use New connection, set Connection name and Authentication, then authorize the account or supply the credentials required by that option. OAuth uses service consent; API keys, bearer credentials and username/password use their declared fields.
- 02
Bind the exact account
A system can have multiple private accounts. In the workflow activity, use Choose your account connection to select the intended named account. Accounts are scoped to their owner and workspace. Workflow access records the owner approval needed for scheduled or event-driven use.
| Authentication option | What to prepare |
|---|---|
| OAuth | Choose an available Authentication option and complete the provider consent. An administrator must enable the connector registration first. Signing in to SynaptaGrid does not grant the connector access to your provider account. |
| Jira Cloud API token | For an administrator-approved API-token connection, enter the approved Atlassian account email as Username and its API token as Password. Do not enter the Atlassian account password. OAuth is a separate option that needs enabled administrator registration. |
| HubSpot service key or private app token | For bearer authentication, enter the approved scoped token in Access token. Choose read permissions for the contacts, companies and deals your workflow uses; add the corresponding write permissions only for write activities. These tokens are not renewed by OAuth refresh. |
For Jira and HubSpot, run a controlled read with the intended named connection and check the provider-side result before enabling create or update activities. A supplied catalog entry or saved connection does not prove provider access.
Requested permissions describe the Authentication option: they do not confirm what your account has granted. Compare them with Required permission identifiers for the activity. Every required group must be satisfied; a group can offer alternative permissions. Read the account check message and use Check permissions again after a change. Automation checks again when the activity runs.
| What the permission check tells you | What to do |
|---|---|
| The account has the required permissions | Use the selected account. The execution check still applies when the action runs. |
| Reconnect can supply the required permissions | Reconnect requests the same authentication option and its configured permissions. For different permissions, use another option or account. |
| The selected option cannot supply the permissions | Choose another authentication option or connect another account. Reconnecting the same option does not add arbitrary permissions. |
| The account, activity or connector setup is unavailable | Follow the displayed reason. An operator may need to enable or repair the connector setup before you can authorize it. |
| Permissions have not been checked | For manual credentials, service permissions are checked when the activity runs. If the check itself failed, retry it before running; the saved account selection stays in place. |
Verify local and production behavior separately with a controlled account and a useful activity. Check the selected account, mapped data and provider-side result, then prove denied access and the applicable refresh, reconnect and alert behavior. A catalog entry, successful login or saved connection alone does not prove an activity works.
Chapter 8 of 12
Receive outbound webhooks
Data emits record changes; Automation emits run, step, task and external-call events. Subscribe only to the events your consumer handles.
| Publisher | Typical events |
|---|---|
| Data | entity.created, entity.updated, entity.deleted, entity.version_promoted and file.uploaded. |
| Automation | automation.workflow.started/completed/failed; automation.task.created/assigned/completed/signed; automation.step.completed/failed; and automation.external_call.completed. |
| CloudEvents 1.0 field | How to use it |
|---|---|
| specversion | Always 1.0 for supported product events. |
| id | Stable delivery identity. Put this in a unique processed-events store to deduplicate. |
| type | Exact event name used by subscription filters and handler dispatch. |
| source | Publisher identity. Allowlist the source values your consumer expects. |
| subject | The affected business resource when supplied. |
| time | Publisher timestamp; do not use it as a uniqueness key. |
| data | Event-specific payload. Treat additive fields as backward-compatible. |
- HTTPS receivers get the CloudEvents 1.0 JSON body and the managed X-Signature-256 header.
- Data also sends X-EGAV-Event, X-EGAV-Event-Id, X-EGAV-Delivery and X-EGAV-Subject. Automation uses the corresponding X-Automation-Event, X-Automation-Event-Id, X-Automation-Delivery and X-Automation-Subject headers.
- Amazon SQS is useful for buffering, Amazon SNS for fan-out, and Kafka for an existing event stream.
- Create different subscriptions for consumers with different ownership, event filters, credentials or recovery needs.
- Use the test-delivery action before enabling business processing; a successful DNS lookup is not proof your handler accepts and verifies the event.
Chapter 9 of 12
Verify, deduplicate and recover delivery
A safe receiver authenticates the raw request before parsing it and makes processing idempotent before returning success.
1. Read the raw request bytes
2. Compute HMAC-SHA256(secret, raw bytes)
3. Constant-time compare "sha256=<hex>" with X-Signature-256
4. Parse the CloudEvents 1.0 JSON
5. Reject an unexpected source or event type
6. Insert event id into a unique processed-events store
7. Apply the business change once
8. Return 2xx only after durable acceptance- The default is four total attempts: one immediate attempt, then retries after 10, 60 and 300 seconds. The default per-attempt timeout is 10 seconds.
- A subscription can set 1–10 total attempts, a 1–120 second timeout and 1–10 backoff delays; each delay must be between 1 second and 24 hours.
- Return a non-2xx response for a transient failure so delivery can retry; do not return success before the event is durably queued or committed.
- Delivery is at least once. A duplicate event is normal and should return success after your unique event-id check finds the prior result.
- Inspect each attempt in the delivery log. Failed deliveries back off and eventually dead-letter when their attempt budget is exhausted.
- Fix the receiver first, then retry one delivery or use bulk redrive. Redrive does not replace receiver-side idempotency.
Chapter 10 of 12
Handle responses, limits and caller retries
Classify a response before retrying. A contract or permission problem will not become healthy through repetition.
| Status | Meaning and caller action |
|---|---|
| 400 | Malformed JSON, query or signature input. Correct the request; do not retry unchanged. |
| 401 | Missing or invalid API key or inbound signature. Load the current secret and rebuild the request. |
| 403 | The key is valid but its instance, grant, source IP or entitlement does not allow this operation. |
| 404 | The resource is unknown or deliberately hidden outside the key grant. A controlled-publishing Data record also returns 404 before its first promotion. |
| 409 | The request conflicts with current lifecycle state. Read the resource and decide whether the desired result already exists. |
| 422 | The request violates the published contract. Data returns field-level validation details; fix those fields before retrying. |
| 429 | A Data key exceeded its quota. Honor Retry-After and the X-RateLimit-* headers, then retry with jitter. |
| 5xx or network failure | Treat as transient, back off with jitter and reconcile before repeating a non-idempotent Data write. |
- Retry Automation starts with the same JSON idempotency_key and signed inbound sends with the same event_id.
- Data writes have no request-level idempotency key. Use a unique source external_id and query or reconcile after an uncertain response before creating again.
- Automation execution status values are pending, running, completed, failed, cancelled, timeout and skipped.
Chapter 11 of 12
Rotate secrets without downtime
Plan API-key and webhook-secret rotation separately because their overlap behavior is different.
- 01
Create a second API key
Mint a separately named key with the same minimum grants. Do not rotate the existing key yet.
- 02
Deploy and prove the new value
Change the secret-manager reference, restart or redeploy the consumer, and make a controlled request.
- 03
Retire the old API key
Revoke it only after logs show that no caller still presents it.
- 04
Treat rotate as an atomic replacement
Rotation invalidates the old secret immediately for Data keys, Automation keys, inbound source secrets and outbound webhook signing secrets.
- 05
Coordinate inbound HMAC rotation
Pause sends or coordinate an atomic sender cutover because a request signed with the previous source secret will be rejected.
- 06
Separate outbound subscriptions when overlap is needed
Use a temporary second subscription and let the receiver accept both subscription secrets. Expect duplicate business events during the overlap and deduplicate by CloudEvents id, then remove the old subscription.
Chapter 12 of 12
Troubleshoot the complete path
Follow one correlation chain from the source request through the record, event, workflow run and outbound delivery.
| Symptom | Check first |
|---|---|
| 401 or 403 on an API call | The correct environment, current key, X-App-Instance-Guid, workflow or record-type grant, source-IP rule and entitlement. |
| 422 from Data | Payload field names and types against the published schema, not the current draft. |
| Signed inbound event rejected | The raw bytes used for HMAC, sha256= prefix, current source secret, source code and application-instance URL. |
| Event accepted but no workflow starts | The workflow is published and active, its trigger is armed, event type matches and filters evaluate true. |
| External action is slow or failing | System health, authentication, throttle state, concurrency limit, timeout and retry policy. |
| Account needs different permissions | The activity permission check and Authentication option. Reconnect only when that option offers the required permissions; otherwise choose another option or account. |
| Account needs attention but no alert arrives | Account health, notification preferences and delivery status. Use a positive notification test before concluding that repeated alerts were suppressed. |
| Outbound delivery repeats | Your processed-event unique key; do not diagnose a retry as a second source event without comparing event ids. |
| Outbound delivery dead-letters | Attempt details and receiver logs, then test and redrive only after the receiver is healthy. |
Continue
Continue with the product guides
Data and Automation are sold separately and work independently. Use both when a workflow should read or change a versioned business record.