Guides
Connecting your workflows to external systems
Connect your workflows to any external system — from connected integrations to internal tools — with the right method, credentials, and guardrails in place.
Atomicwork workflows can call any external system's API — whether it's provisioning a user in Okta, posting a message to Slack, creating a Jira ticket, or pushing data to a system you built in-house. This guide covers everything you need to know about making outbound API calls from your workflows: which method to use, how authentication is handled, where credentials are stored, and what to do when things go wrong.
Choosing the right method
Atomicwork gives you two ways to call an external API from a workflow. The right choice depends on whether the app is already connected through the integrations page.
Option 1: Call API from a code script
Use when: The app is connected through the integrations page (Settings > App store).
Call API is the simplest way to hit an external API. You write a code script inside an Execute Code action and call a typed SDK method for the connected app:
const result = await API.datadog.datadogCallApi({
method: "GET",
endpoint: "/api/v1/monitor?page=0&page_size=25",
});The method name follows the app: API.datadog.datadogCallApi, API.azure_ad.azureAddUserToGroup, and so on. Type Workflow. or API. in the code editor and press Cmd+I to see the available functions and autocomplete them. You can also use the Workflow.* namespace — Workflow.datadogCallApi(...) resolves to the same function.
Call API handles authentication, token refresh, and destination safety automatically. You never see a token, you don't manage credentials, and you can't accidentally send a request to the wrong host. The trade-off is that it only works with apps that are connected through the integrations page and have Call API enabled.
[!NOTE] Call API does not appear as a separate action in the workflow builder's action picker. To use it, add an Execute Code action and call the SDK method from your script. Type
Workflow.in the code editor and press Cmd+I (or Ctrl+I) to browse available functions.
Call API parameters
| Field | Required | Notes |
|---|---|---|
method | Yes | GET, POST, PUT, DELETE, or PATCH. |
endpoint | One of endpoint or url | Path plus query string (e.g. /api/v1/monitor). The base URL comes from the connection, so you don't hard-code it. |
url | One of endpoint or url | Full URL (e.g. https://atomicwork.okta.com/api/v1/users). Takes precedence over endpoint if both are set. |
headers | No | Merged into the request. |
body | No | Request payload. |
Each integration accepts both endpoint and url. Use endpoint to pass just the path (e.g. /api/v1/users) — Atomicwork fills in the base URL from the connection. Use url when you need to specify the full address (e.g. https://atomicwork.okta.com/api/v1/users). We'd recommend endpoint where possible — it avoids hard-coding the base URL, so the call stays correct if your connection's hostname changes.
Both endpoint and url go through destination safety validation. The difference is only in how the target address is built — not whether it's checked.
What Atomicwork handles automatically
-
Authentication. The connection's credentials are resolved server-side and applied to the outgoing request. Your script never sees a token, and an auth header you set yourself cannot override the one Atomicwork injects.
-
Token refresh. For OAuth-based connections, expired tokens are refreshed automatically before the call goes out. You don't need to handle token lifecycle in your code.
-
Destination safety. Calls are restricted to the hosts that belong to the connected app. For apps with a per-tenant address — Okta, Workday, ServiceNow — calls are further restricted to your own instance. A request to any other host is rejected with a
403.
Supported apps
Call API is enabled per app, not universally. Most major integrations have it — including Okta, Jira, Slack, Microsoft Graph, GitHub, Workday, ServiceNow, Cloudflare, Datadog, Rippling, Google Workspace, Azure AD, Notion, Linear, and Grafana — but the list grows as new integrations are added. If the app you need doesn't have a Call API method, use the HTTP request approach below.
Option 2: Make an HTTP request with a saved credential
Use when: The app isn't available on the integrations page, or you need to call a system that doesn't have Call API enabled.
The Make an HTTP request action is a standalone workflow action (not a code script) that sends an HTTP request to any URL you specify. You handle authentication by picking a saved credential from the credential store, or by entering credentials directly.
This approach gives you full control — you choose the URL, the method, the headers, the body, and the credentials. There's no automatic token refresh, so you manage that yourself. If you set allowed hosts on a saved credential, Atomicwork enforces that restriction server-side at execution — giving you a guardrail similar to Call API's destination safety, but one you configure per credential rather than getting automatically.
To add one to a workflow:
-
In the workflow builder, click Add action and select Make an HTTP request.
-
Enter the URL of the external system. Include the subdomain if there is one (e.g.
https://mycompany.bamboohr.com/api/...). -
Choose the HTTP method:
GETto read data,POSTto create,PUTorPATCHto update,DELETEto remove. -
Choose credentials — pick a saved credential from the credential store, or enter a username/password or API key directly. We'd recommend using saved credentials so your teammates don't have to re-enter them for the same systems.
-
Add any required headers and the request body (JSON format).
We'd recommend building and testing your request in a tool like Postman before adding it as a workflow action.
Choosing between them
| Call API (from code) | Make an HTTP request | |
|---|---|---|
| Best for | Apps connected through the integrations page | Systems not available as an integration |
| Authentication | Automatic — uses the connection's credentials | Manual — pick a saved credential or enter auth details |
| Token refresh | Automatic | You manage it |
| Destination safety | Built in — both endpoint and url are validated against the app's registered hosts | You control the URL. Saved credentials with allowed-host restrictions are enforced server-side at execution. |
| Where to use it | Inside an Execute Code action | As a standalone workflow action |
| Credential management | None needed | Save credentials in the credential store |
Managing credentials
Credentials are stored and managed in two separate places in Atomicwork, depending on direction — outbound (Atomicwork calling other systems) or inbound (other systems calling Atomicwork).
The credential store (outbound)
The credential store holds shared, organization-level credentials for outbound calls. Find it at Settings > Organization > Security > Credential store.
Click Add a credential and choose one of three authentication types:
| Type | When to use |
|---|---|
| API key | The receiving app issues a key or token. For bearer-style authentication, use this type — set the header name (e.g. Authorization) as the key, and the full token value (e.g. Bearer sk-xxx) as the value. There is no separate bearer type. |
| Username and password | The receiving app uses basic auth. |
| No authentication | The endpoint accepts unauthenticated requests. |
Once saved, pick the credential by name when configuring an HTTP request action. The secret is resolved server-side and injected into the outbound call — it never appears in your workflow definition.
Credential best practices:
-
Never inline secrets. Don't put a token directly in a workflow body, a code script, or source control. Always use a credential reference.
-
Use descriptive names. Name credentials so teammates can immediately tell what app they're for (e.g. "BambooHR API key - Production").
-
Set allowed hosts. We'd recommend restricting each credential to the hosts it should be used with (e.g.
github.comor*.salesforce.com). This prevents a credential saved for one system from being accidentally used against another. -
Reads are masked. The credential store returns
********in place of stored values. Only organization-level credential administrators can reveal the actual secret. -
Rotation is simple. Since integrations only hold a reference to the credential, rotating a secret means updating the credential in the store — not hunting down every place it was used.
Public API tokens (inbound)
Public API tokens authenticate calls made into Atomicwork's own API — not calls going out. Manage yours at Settings > My account > Credential store (the page title reads Public API token).
Every request to the Atomicwork API must include your token in the X-Api-Key header:
X-Api-Key: aw_xxxxxxxxxxxxTokens are workspace-scoped — a token created in one workspace cannot access another. They're tied to your individual account and stop working when your account is deactivated or your permissions change.
[!NOTE] Both the outbound credential store and the personal API token screen are labelled Credential store in the sidebar. The outbound store is under Organization > Security — that's the one for workflow integrations. The personal one is under My account — that's for your own API access.
Rate limits
Rate limits are applied per tenant and shared across every channel — Portal, API, Email, Slack, Teams, workflows, and journeys all draw from the same budget. They are not per user and not per API key.
| Operation | Per minute | Per 10 minutes |
|---|---|---|
| Read a request | 2,000 | 10,000 |
| Create a request | 50 | 500 |
| Update a request | 2,000 | 10,000 |
| Concurrent updates to the same request | 30 in any 30-second window |
When you hit a limit
The API returns HTTP 429. The back-off interval is included in the response two ways — use whichever is easier for your integration:
- A
Retry-Afterresponse header, in seconds. variables[0]in the JSON body, the same number.
{
"message": "Rate limit exceeded. Retry after N seconds",
"message_code": "RATE_LIMIT_ERROR",
"variables": [N]
}Wait the full interval before retrying. A call rejected by the 10-minute window may already have counted against the 1-minute window, so an immediate retry can be rejected again.
Bulk migrations
If you're running a one-time data migration and need higher throughput, limits can be raised temporarily for your tenant. Contact your Atomicwork representative with the peak rate you need and how long you need it, and we'll stage the increase ahead of your run.
Example: End-to-end incident response
Here's a complete example that ties everything together. Say a workflow triggers when a security incident is created, and you need to mute noisy alerts in Datadog, clear the compromised user's active sessions in Okta, and log the incident to an internal status page that isn't connected through Atomicwork.
This example shows all three integration patterns: Call API for an app with no built-in actions (Datadog), Call API for an app that has built-in actions but you need an endpoint beyond them (Okta), and an HTTP request for a system that isn't on the integrations page.
Step 1: Mute the Datadog monitor (Call API — no built-in actions)
Datadog is connected through the integrations page but has no built-in workflow actions, so Call API is how you reach it:
// Mute alerts for the affected monitor during the incident
await API.datadog.datadogCallApi({
method: "POST",
endpoint: `/api/v1/monitor/${input.monitorId}/mute`,
body: {
end: input.maintenanceEndTimestamp,
scope: input.hostScope,
},
});
return { monitorMuted: true };No credentials to manage — Atomicwork uses the Datadog connection's credentials automatically.
Step 2: Clear all active Okta sessions (Call API — beyond built-in actions)
Okta has built-in workflow actions for common operations like assigning groups, but clearing a user's active sessions isn't one of them. Call API lets you hit any Okta endpoint, including the ones the built-in actions don't cover:
// Force sign-out: clear all active sessions for the compromised user
await API.Okta.oktaCallApi({
method: "DELETE",
endpoint: `/api/v1/users/${input.oktaUserId}/sessions`,
});
return { sessionCleared: true, userId: input.oktaUserId };Same automatic authentication and destination safety as above — the call is restricted to your Okta tenant's instance URL.
Step 3: Update the internal status page (HTTP request)
The internal status page isn't on the integrations page, so use a Make an HTTP request action with a saved credential from the credential store:
- Add a Make an HTTP request action after the code steps.
- Set the URL to
https://status.internal.company.com/api/incidents. - Choose
POSTas the method. - Pick the saved "Status Page API key" credential.
- Set the body to include the incident details from the previous steps (using data pills).
Troubleshoot common issues
Call API issues
| Error | Why it happens | What to do |
|---|---|---|
| 403 Forbidden | The destination safety check rejected the request. The endpoint doesn't match the connected app's registered hosts. | Verify the endpoint belongs to the app's host. For per-tenant apps like Okta, confirm it matches your instance URL — calling dev-12345.okta.com when your connection is for company.okta.com will be rejected. |
| 401 or 403 despite a working connection | The integration connection has expired or been revoked, or the connection's OAuth scopes don't include the permissions this endpoint requires. | Go to Settings > App store, find the app, and reconnect it. Check the external app's API docs for the scopes or permissions the endpoint requires — you may need to reauthorize with additional scopes. |
| Method not found in the code editor | The app doesn't have Call API enabled. | Type Workflow. and press Cmd+I to check. If the function isn't listed, use Make an HTTP request with a saved credential instead. |
HTTP request issues
| Error | Why it happens | What to do |
|---|---|---|
| 401 Unauthorized | The saved credential has expired, been revoked, or doesn't have the permissions the endpoint requires. | Go to Settings > Organization > Security > Credential store, find the credential, and update it with a fresh key. Check the external system's docs for the required scopes or permissions. |
| Connection timeout | The external system is unreachable, or the URL is incorrect. | Verify the URL and confirm the system is online. If it requires IP allowlisting, contact Atomicwork support for the list of outbound IPs. |
| Wrong data format | The external system expects a non-JSON format (XML, form-encoded). | Use an Execute Code action instead of Make an HTTP request — you'll have more control over the request format. |
Rate limit issues
| Error | Why it happens | What to do |
|---|---|---|
| 429 Too Many Requests | Your tenant has hit the platform's per-tenant rate limits, which are shared across all channels (API, workflows, Portal, Slack, Teams, etc.). | Stagger your operations or contact your Atomicwork representative about temporarily raising limits for a migration. |
Learn more
-
Use Call API actions in workflows — detailed reference for Call API parameters, supported apps, and SDK patterns
-
HTTP request actions — step-by-step for adding HTTP request actions to workflows
-
Managing credentials — the credential store, public API tokens, and how to manage them
-
Code actions — setting up Execute Code actions, testing, and using AI Assist
-
API reference: Introduction — base URL, authentication, and error handling for the Atomicwork API
