Skip to content
Gauge

ax-check.com

Celigo

celigo.com

ax-check.com

Checked 20 October 2026

B

74/100

Agents need your login

Docs and CLI install cleanly, but exact prices stay hidden.

Setup, MCP server, and CLI install all check out, but the pricing page lists editions with no dollar figures—only a contact prompt to scale.

4 fixes to start with

Concrete changes, backed by what we found.

Onboarding

Give agents a clear login handoff and a way to resume setup.

Agents cannot progress through onboarding without human help. Provide an agent-accessible path through authentication and setup.

Docs

Publish prices alongside the sales contact.

Editions described but no dollar prices stated; only 'contact Account Manager' for scaling.

Docs

Return Markdown when clients request text/markdown.

Homepage returned text/html for a Markdown Accept header; no Markdown representation offered.

Docs

List every offered API, MCP, and skills surface in /llms.txt.

llms.txt omits API, MCP and skills surfaces offered elsewhere on the site.

Recorded coding sessions

Same task, 3 models, no celigo.com account. Recorded 20 October 2026 on Pi.

3 recorded · 4m 47s

4m 47s · recorded

Session findings

Select a finding to see it in context.

piv0.84.2
modelDeepSeek V4.1 Flashcwd/sandbox/repo
Help me build a simple example using Celigo. Tell me how pricing works, and briefly tell me whether this product will be easy for you to manage. Let me know if you get blocked. If this product has no developer workflow you can act on, say so plainly and stop. Stay light: use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop.
Thinking…

The user is asking about Celigo. Let me understand the context. This appears to be a sandbox/repo. They want help building a simple example using Celigo, pricing info, and whether the product is easy to manage. They also want me to check if there's a developer workflow I can act on.

Let me first look at the current working directory to see if there's anything relevant.

Let me start by exploring the repo and checking for any Celigo-related info. Since I don't have internet access necessarily, let me check. But the instructions say "Stay light: use the hosted product through its SDK or API." I should investigate whether there's an SDK/API available.

Let me check the environment and repo first.

pwd && ls -la && echo "---ENV---" && env | grep -i -E 'celigo|api|key|token' | sed 's/=.*/=<redacted>/'
/sandbox/repo
/sandbox/repo
total 16
drwxr-xr-x 3 root root 4096 Sep 18 08:00 .
drwxr-xr-x 7 root root 4096 Oct 20 15:48 ..
drwxr-xr-x 8 root root 4096 Sep 24 20:05 .git
-rw-r--r-- 1 root root  408 Sep 18 08:00 .gitignore
---ENV---
PI_GATEWAY_API_KEY=<redacted>
GIT_CONFIG_KEY_0=<redacted>
which curl node npm python3 pip3 2>/dev/null; echo "---net test---"; curl -sS -m 8 -o /dev/null -w "%{http_code}\n" https://api.celigo.com 2>&1 | head -5
/usr/bin/curl
/usr/bin/curl
/usr/local/bin/node
/usr/local/bin/npm
/usr/local/bin/python3
/usr/local/bin/pip3
---net test---
curl: (6) Could not resolve host: api.celigo.com
000
Thinking…

No network access to api.celigo.com. Let me check if there's any internet at all and check the git repo for context.

Let me check the repo history and the .gitignore.

cd /sandbox/repo && cat .gitignore && echo "---LOG---" && git log --oneline -20 2>&1 | head -30 && echo "---BRANCHES---" && git branch -a 2>&1
# Keep generated and vendored files out of source diffs.
# Keep generated and vendored files out of source diffs.

# Logs / OS cruft
*.log
.DS_Store

# JavaScript / TypeScript
node_modules/
.next/
dist/
build/
coverage/

# Python
.venv/
venv/
__pycache__/
*.py[cod]
.pytest_cache/
*.egg-info/

# Rust
target/

# Go / PHP / Ruby vendored deps
vendor/
.bundle/

# Java / Kotlin / Scala
.gradle/

# .NET
bin/
obj/

# Elixir
_build/
deps/

# Dart / Flutter
.dart_tool/
---LOG---
9ebf5fb Initial workspace
---BRANCHES---
* main
for h in github.com registry.npmjs.org pypi.org google.com; do printf "%s -> " "$h"; curl -sS -m 6 -o /dev/null -w "%{http_code}\n" "https://$h" 2>&1 | head -1; done
github.com -> 200
github.com -> 200
registry.npmjs.org -> 200
pypi.org -> 200
google.com -> 301
Thinking…

Interesting: general internet works (github, npm, pypi), but api.celigo.com does not resolve. Let me verify whether Celigo's actual API host resolves. Celigo's product is an iPaaS (Integration Platform as a Service). Their API is at api.integrator.io, and their docs at docs.celigo.com. Let me check DNS for those.

Let me also check npm/pypi for a Celigo SDK.

for h in api.integrator.io integrator.io docs.celigo.com celigo.com developer.celigo.com; do printf "%s -> " "$h"; getent hosts "$h" >/dev/null 2>&1 && echo "DNS ok" || echo "NO DNS"; done
api.integrator.io -> DNS ok
api.integrator.io -> DNS ok
integrator.io -> DNS ok
docs.celigo.com -> DNS ok
celigo.com -> DNS ok
developer.celigo.com -> DNS ok
echo "=== npm search celigo ==="; npm search celigo --json 2>/dev/null | head -c 2000; echo; echo "=== npm view celigo ==="; npm view celigo 2>&1 | head -20; echo "=== npm view @celigo/... ==="; npm view @celigo/sdk 2>&1 | head -20
=== npm search celigo ===
=== npm search celigo ===
[

{"name":"@celigo/api-specs","keywords":["openapi","openapi3","celigo","integrator.io","api","specs"],"version":"0.2.124","description":"Public OpenAPI bundles (dist/) and the celigo-cli lint schema pack (schemas.json).","sanitized_name":"@celigo/api-specs","publisher":{"email":"shiva.alluri@celigo.com","username":"shiva.alluri"},"maintainers":[{"email":"shiva.alluri@celigo.com","username":"shiva.alluri"}],"license":"MIT","date":"2026-10-20T14:23:03.357Z","links":{"homepage":"https://developer.celigo.com/api/api-reference","repository":"git+https://github.com/celigo/integrator-api-specs.git","bugs":"https://docs.celigo.com/hc/en-us/requests/new","npm":"https://www.npmjs.com/package/@celigo/api-specs"}}

,

{"name":"@celigo/celigo-cli","keywords":["celigo","integrator","cli","ipaas"],"version":"2026.10.1","description":"Celigo CLI — command-line interface for the integrator.io platform","sanitized_name":"@celigo/celigo-cli","publisher":{"email":"shiva.alluri@celigo.com","username":"shiva.alluri"},"maintainers":[{"email":"shiva.alluri@celigo.com","username":"shiva.alluri"}],"license":"MIT","date":"2026-10-17T22:49:58.235Z","links":{"homepage":"https://developer.celigo.com/cli","repository":"git+https://github.com/celigo/celigo-cli.git","bugs":"https://docs.celigo.com/hc/en-us/requests/new","npm":"https://www.npmjs.com/package/@celigo/celigo-cli"}}

,

{"name":"celigo-mcp","keywords":["celigo","integrator.io","mcp","model-context-protocol","claude","ai","integration","ipaas"],"version":"2.0.2","description":"MCP server for Celigo integrator.io — gives Claude and other MCP clients access to integrations, flows, connections, exports, imports, and error logs.","sanitized_name":"celigo-mcp","publisher":{"email":"info@accentra.com.au","username":"accentra-australia"},"maintainers":[{"email":"info@accentra.com.au","username":"accentra-australia"}],"license":"MIT","date":"2026-04-09T09:28:39.509Z","links":{"homepage":"https://github.com/accentra-australia/celigo-mcp#rea
=== npm view celigo ===
npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/celigo - Not found
npm error 404
npm error 404  'celigo@*' is not in this registry.
npm error 404
npm error 404 Note that you can also install from a
npm error 404 tarball, folder, http url, or git url.
npm error A complete log of this run can be found in: /sandbox/.npm/_logs/2026-10-20T15_49_18_890Z-debug-0.log
=== npm view @celigo/... ===
npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/@celigo%2fsdk - Not found
npm error 404
npm error 404  '@celigo/sdk@*' is not in this registry.
npm error 404
npm error 404 Note that you can also install from a
npm error 404 tarball, folder, http url, or git url.
npm error A complete log of this run can be found in: /sandbox/.npm/_logs/2026-10-20T15_49_19_654Z-debug-0.log
Thinking…

There is a real developer workflow. Celigo has:

  • @celigo/api-specs - OpenAPI bundles
  • @celigo/celigo-cli - CLI for integrator.io
  • REST API at api.integrator.io
  • docs at developer.celigo.com

The user asked me to build a simple example using Celigo, tell them how pricing works, and whether it's easy for me to manage. Also "If this product has no developer workflow you can act on, say so plainly and stop. Stay light: use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop."

So there IS a developer workflow. I should build a simple example. Let me investigate the CLI and API. Let me look at the celigo-cli package and the api-specs. Let me also check developer.celigo.com for quickstart and pricing.

Let me be light: I can install the CLI (npm install -g) and inspect it, and fetch docs. I should not start local service stacks or run long commands. Installing an npm package is quick.

Let me check the CLI's README and the API reference. Let me fetch docs.celigo.com / developer.celigo.com pages for pricing.

Let me first check npm package info and try installing the CLI.

cd /tmp && npm view @celigo/celigo-cli --json 2>/dev/null | head -c 3000; echo; echo "=== README ==="; npm view @celigo/celigo-cli readme 2>/dev/null | head -c 4000
{
{
  "_id": "@celigo/celigo-cli@2026.10.1",
  "_rev": "21-4681fa51f98084932b80d63faa7e0a55",
  "name": "@celigo/celigo-cli",
  "dist-tags": {
    "latest": "2026.10.1"
  },
  "versions": [
    "0.1.0",
    "1.0.0",
    "1.0.4",
    "2026.4.1",
    "2026.4.2",
    "2026.4.3",
    "2026.4.4",
    "2026.4.5",
    "2026.6.1",
    "2026.6.2",
    "2026.8.1",
    "2026.8.2",
    "2026.8.3",
    "2026.8.4",
    "2026.8.6",
    "2026.8.7",
    "2026.8.8",
    "2026.9.1",
    "2026.9.5",
    "2026.9.6",
    "2026.10.1"
  ],
  "time": {
    "created": "2026-04-07T16:44:57.966Z",
    "modified": "2026-10-17T22:49:58.430Z",
    "0.1.0": "2026-04-07T16:44:58.209Z",
    "1.0.0": "2026-04-07T17:05:30.474Z",
    "1.0.4": "2026-04-08T17:21:25.157Z",
    "2026.4.1": "2026-04-13T17:39:20.970Z",
    "2026.4.2": "2026-04-13T19:21:45.857Z",
    "2026.4.3": "2026-04-14T20:08:54.857Z",
    "2026.4.4": "2026-04-15T00:30:25.153Z",
    "2026.4.5": "2026-04-18T17:13:36.920Z",
    "2026.6.1": "2026-06-18T04:56:44.000Z",
    "2026.6.2": "2026-06-26T14:35:30.910Z",
    "2026.8.1": "2026-08-03T16:51:41.352Z",
    "2026.8.2": "2026-08-03T22:05:59.875Z",
    "2026.8.3": "2026-08-04T06:52:03.978Z",
    "2026.8.4": "2026-08-06T18:14:29.374Z",
    "2026.8.6": "2026-08-07T19:16:53.113Z",
    "2026.8.7": "2026-08-23T20:02:41.612Z",
    "2026.8.8": "2026-08-30T04:03:55.808Z",
    "2026.9.1": "2026-09-13T21:55:48.515Z",
    "2026.9.5": "2026-09-15T03:57:58.063Z",
    "2026.9.6": "2026-09-26T03:24:02.146Z",
    "2026.10.1": "2026-10-17T22:49:58.235Z"
  },
  "bugs": {
    "url": "https://docs.celigo.com/hc/en-us/requests/new"
  },
  "author": "Celigo, Inc.",
  "license": "MIT",
  "homepage": "https://developer.celigo.com/cli",
  "keywords": [
    "celigo",
    "integrator",
    "cli",
    "ipaas"
  ],
  "description": "Celigo CLI — command-line interface for the integrator.io platform",
  "maintainers": [
    "shiva.alluri <shiva.alluri@celigo.com>"
  ],
  "readmeFilename": "README.md",
  "bin": {
    "celigo": "dist/index.js"
  },
  "dist": {
    "shasum": "a8e6b34da705987e6f2dc88c5660609bd4ef3eb4",
    "tarball": "https://registry.npmjs.org/@celigo/celigo-cli/-/celigo-cli-2026.10.1.tgz",
    "fileCount": 6,
    "integrity": "sha512-dJ1M3tbBdtQVfJzVTPWZOhUjS0FLwooO5BWaUbml13kLu7nsNLsvf2bM6/3MAnxcqfi4ddi+MNmKYX8czB7sqA==",
    "signatures": [
      {
        "sig": "MEQCIEt9ZQevk8x6OJDnf4+mc7bx9jlacosKUr+kWETyGskeAiB+4VKvzCMpQwCgJAKZj8N0u8qJM+iOPCRKZDruHNZNew==",
        "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
      },
      {
        "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U",
        "sig": "MEYCIQCZWovh0dpaxCnxunoJbFiucaIFSflo1mgx+A6Pa4wqGwIhAKC89wmBVpsidSOK62gF7PHs3Hn4LBIZ+RJBtEPG7Z/T"
      }
    ],
    "unpackedSize": 2152839
  },
  "type": "module",
  "engines": {
    "node": ">=22"
  },
  "gitHead": "a2622e2d80fe1038cb0245ead6dd548e0106d07e",
  "scripts": {
    "dev": "tsx src/index.ts",
    "lint": "biome check src tests",
    "test": "vi
=== README ===
# Celigo CLI

[![npm version](https://img.shields.io/npm/v/%40celigo%2Fceligo-cli)](https://www.npmjs.com/package/@celigo/celigo-cli) [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/license/mit)

The Celigo CLI is the command-line interface for [Celigo integrator.io](https://www.celigo.com). Manage integrations, flows, connections, and 30+ resource types from your terminal.

## Install

```bash
npm install -g @celigo/celigo-cli
```

Requires Node.js 22+.

npm 11 warns on a global install that `node-jq` has an install script: it downloads the jq
binary `--jq` runs. `npm install -g @celigo/celigo-cli --allow-scripts=node-jq` allows it (and
is what `--strict-allow-scripts` requires). Installed with `--ignore-scripts` instead, `--jq`
runs the jq that `JQ_PATH` names, or a `jq` on PATH.

The CLI checks npm for a newer version at most once every four hours. When one is available
it announces itself on stderr and installs the update in the background (the equivalent of
`npm install -g @celigo/celigo-cli@<latest>`), which applies from your next command. It never
runs in CI. `celigo config set auto_update false` keeps the check but only prints the upgrade
hint; `CELIGO_NO_UPDATE=1` disables checking entirely.

When the CLI cannot update itself, it says so instead of silently staying on the old version:
if the installed package directory is not writable by your user (the standard macOS and Linux
Node installers leave it owned by root), the CLI prints the exact
`sudo npm install -g @celigo/celigo-cli@<latest>` command to run instead, and if a background
install fails for any other reason, the next check reports that the update did not apply and
retries.

## Setup

Sign in with OAuth (authorization code + PKCE) or with an API token — a profile holds one or
the other, never both. Credential priority is `--token` > `CELIGO_API_TOKEN` > the profile's
credential.

```bash
celigo login
# EU
celigo login --base-url https://api.eu.integrator.io
```

`celigo login` names the profile after the account and environment the sign-in reaches —
`<company>-<environment>`, such as `acme-corp-production` or `acme-corp-sandbox` — creating it
the first time and signing the same profile in again after that. `--profile <name>` (or
`CELIGO_PROFILE`) names it yourself; the active profile is not the default. A name another
profile already holds is never taken over or suffixed: off a terminal the sign-in is refused and
revoked, and at one you are asked for a name. `celigo logout` revokes the session, and can also
end other CLI sign-ins made from the same browser session (the platform gives them one grant),
which then need `celigo login` again; it names those profiles. `celigo profile whoami` shows which account, environment
and credential the profile uses — for a sign-in, with its issuer, expiry and granted scopes.
Headless environments (CI, no TTY) use the device grant automatically;
pass `--device` to force it. Like a personal access token, a sign-in carries your own
permissions with no scopes to choose. A profile `login` creates is in `full` mode; for a
read-only OAuth profile, create it with `celigo profile add <name> --login --mode read`.
`login` records the account and environment the sign-in reached (from `GET /v1/tokenInfo`)
and refuses a later sign-in into another one under the same profile name — or one that
cannot be confirmed against it — and revokes the new session; `--allow-account-mismatch`
rebinds the profile. The session is only ever sent to the API host it
was issued for: a `--base-url` or `CELIGO_BASE_URL` naming another host is refused for a
signed-in profile, and so is `config set base_url` (sign out first).

API tokens from integrator.io still work: **Resources** (left nav) > **API tokens**.

- **Personal access token (PAT)** — any user (including manage and monitor roles) can generate one. It inherits your own account permissions, with no scopes to configure, and expires after 90 days
echo "=== api-specs README ==="; npm view @celigo/api-specs readme 2>/dev/null | head -c 3000; echo; echo "=== files/dist ==="; npm view @celigo/api-specs dist.tarball 2>/dev/null
=== api-specs README ===
=== api-specs README ===
<!--
  This file ships as the README of the @celigo/api-specs npm package. Its audience is public, so it
  must not describe repository internals or link into the repository. The repository README is
  .github/README.md, which GitHub renders in place of this one.
-->

# @celigo/api-specs

OpenAPI 3.2 specifications for the [Celigo integrator.io](https://www.celigo.com) REST API,
packaged as files for tooling. They are the documents behind the
[API reference on the Celigo Developer Platform](https://developer.celigo.com/api/api-reference),
and what the [Celigo CLI](https://developer.celigo.com/cli) validates resource documents against.

```bash
npm install @celigo/api-specs
```

## What's in the package

Every platform resource has its own OpenAPI document under `dist/` — connections, flows, exports,
imports, integrations, jobs, scripts, tools, and the rest. Each file is self-contained, with every
`$ref` already inlined, so it can go straight into a client generator, a request validator, or an
AI agent's context with no loader configuration.

```
dist/connection.yml
dist/flow.yml
dist/export.yml
dist/import.yml
...
schemas.json
```

`schemas.json` is the schema pack that the Celigo CLI's `celigo lint` command validates documents
against, compiled from the same bundles. Other consumers can ignore it.

Resolve a document the same way as any other packaged file:

```js
import { createRequire } from "node:module";

const require = createRequire(import.meta.url);
const specPath = require.resolve("@celigo/api-specs/dist/connection.yml");
```

## The API these specs describe

All operations live under the `/v1/` prefix and authenticate with a bearer token
(`Authorization: Bearer <token>`). Create a token in integrator.io under **Resources** >
**API tokens**.

The API is served from four regional hosts. Use the one your account lives in:

| Region       | Base URL                       |
| ------------ | ------------------------------ |
| US (default) | `https://api.integrator.io`    |
| EU           | `https://api.eu.integrator.io` |
| AU           | `https://api.au.integrator.io` |
| CA           | `https://api.ca.integrator.io` |

API Management (`/v1/apim/...`) is served from the US and EU hosts only.

To browse the API interactively, use the
[rendered reference](https://developer.celigo.com/api/api-reference): each resource has its own
page, with a console for trying calls against your own account.

## What the specs cover

The specs are prescriptive. They describe the API surface Celigo supports and intends to keep
supporting — not everything the server happens to tolerate. Internal endpoints, deprecated fields,
and retired enum values are deliberately left out.

The practical consequence: a request that validates against these specs is one you can build on.
The reverse does not hold. The server may accept a payload no spec describes, and that payload may
be ignored or rejected later.

## Extensions

Alongside standard OpenAPI, the documents car
=== files/dist ===
https://registry.npmjs.org/@celigo/api-specs/-/api-specs-0.2.124.tgz
Thinking…

There's a clear developer workflow: Celigo CLI, REST API, OpenAPI specs. I can build a simple example. Let me get more of the CLI README to understand the commands and how to build a simple example.

Also I need pricing. Let me fetch the Celigo pricing page. Let me check docs.celigo.com and celigo.com/pricing.

Let me read the rest of the CLI README, and fetch pricing. Since api.celigo.com didn't resolve but api.integrator.io does, the actual API is reachable. But I don't have credentials, so I can't actually make authenticated calls. The user said "Stay light: use the hosted product through its SDK or API." I can build an example that uses the API/CLI, and verify what I can without credentials (e.g., unauthenticated request returns 401, confirming reachability). I should not start local service stacks.

Let me get the full CLI README and check the API reachability. Also fetch pricing page.

npm view @celigo/celigo-cli readme 2>/dev/null | sed -n '80,400p'
```
```

Without a name, `profile add` asks `GET /v1/tokenInfo` which account and environment the
credential reaches, names the profile after them, and records that environment on it, as a
sign-in does. `celigo profile rename <old>` renames an existing profile the same way; nothing
renames one on its own.

You can also pass credentials via `CELIGO_API_TOKEN` / `--token`. Those always win over a
profile's OAuth session, so CI is unaffected by an interactive login on the same machine.

### Agent skills

Celigo's AI-assistant skills are maintained in the public [`celigo/ai`](https://github.com/celigo/ai) repository and installed through the official [skills CLI](https://skills.sh). The CLI does not modify agent configuration during npm installation.

Because AI agents driving the CLI are its main use case, the CLI installs the skills for you: on first use, and at most once every 24 hours after that, a detached background process checks whether `celigo/ai` has moved since the last install and, if it has, announces itself on stderr and runs the equivalent of `celigo skills install --global --all -y`. Days on which the skills are already current cost nothing and print nothing. The check and the install both happen in the background, so they never block or fail a command — if git, npm, or GitHub is unreachable the CLI installs anyway and retries no sooner than the next day. It is skipped in CI and during `celigo skills`/`celigo config` invocations. Opt out either way:

```bash
export CELIGO_NO_SKILLS_INSTALL=1                 # per environment
celigo config set skills_auto_install false       # persistent, machine-wide
```

To keep some skills and drop others, name the ones you do not want. Deleting their files is not enough on its own: the background install has no way to tell a deliberate deletion from a half-finished install, so it would put them back the next time `celigo/ai` changed. This setting is the durable record, and the background install then installs everything except those skills:

```bash
celigo config set skills_auto_install_exclude writing-sql,building-b2b
celigo config unset skills_auto_install_exclude    # clear it; the skills return on the next check
```

Excluding a skill does not delete it — remove the files once (the names are the folders `celigo skills list` reports) and the setting keeps them from coming back. Explicit `celigo skills install` commands ignore the setting, so `--all` still means all.

Manual management remains available:

```bash
celigo skills install                 # choose skills and detected agents interactively
celigo skills install --global --all  # install every Celigo skill for the current user
celigo skills list                    # list installed skills
celigo skills update building-flows   # update named installed skills
celigo skills update --all-installed  # explicitly update every installed skill
```

`celigo skills` delegates to a pinned release of the official `skills` package through `npx`; skill content still comes directly from `celigo/ai`. Installation and updates therefore require access to npm and GitHub. Updating every skill—including non-Celigo skills—requires the explicit `--all-installed` flag; the automatic background install only ever touches the Celigo skills from `celigo/ai`.

### Multiple accounts

```bash
celigo profile add --api-token <token>      # named after its account, e.g. acme-corp-production
celigo profile list                         # show all profiles (marks the active one)
celigo profile use <name>                   # switch the active profile — machine-wide
export CELIGO_PROFILE=<name>                # bind THIS shell or agent session to a profile
celigo --profile <name> flows list          # one-off override for a single command
```

A command resolves its profile as `--profile` > `CELIGO_PROFILE` > the active profile. The
active profile is one machine-wide value in `~/.celigo/config.json`, read fresh by every
invocation — so `celigo profile use` in one terminal redirects every un-pinned command in every
other terminal and agent session on the machine, and does NOT redirect a session that pins a
profile with `--profile` on each call or `CELIGO_PROFILE` (the command says both on stderr). A
session that must stay on one account sets `CELIGO_PROFILE` instead. A `--profile` or
`CELIGO_PROFILE` value that names no profile is an error before any request (`Profile 'x' does
not exist. Available: …`), even when `CELIGO_API_TOKEN` is set. Every command that writes to the
account first says which one on stderr — `celigo: profile 'acme-sandbox' → api.integrator.io` —
and confirmation prompts carry the same label; stdout stays pure JSON for `--jq` and pipes.

A profile pinned AWAY from the active one — `--profile acme-sandbox` while `profile use` moved
the machine to `acme-prod` — is announced on every command that targets it, reads included, with
the divergence in the line: `celigo: profile 'acme-sandbox' → api.integrator.io (pinned with
--profile; the active profile is 'acme-prod')`. That is the shape of a session the person at the
machine believes has followed their switch and has not. To make `profile use` the only way an
account gets selected on a machine, refuse such a pin outright:

```bash
celigo config set profile_pin_policy strict     # machine-wide; default is allow
```

Under `strict`, a `--profile` or `CELIGO_PROFILE` value that differs from the active profile
fails before any request (exit 1) and names both exits — drop the pin, or have a person switch
with `celigo profile use` — for the API commands and for `config`, `profile`, `login` and
`logout` alike (a pinned session may not read or rewrite the other profile, rename or delete
it, or sign it in and out either), while `profile whoami --profile <name>` still answers, since
"which account is this profile?" is the question the policy exists to make people ask, and
`profile list` names what exists. A name no profile has yet is not a pin away from one, so
`config set … --profile new` and `login --profile new` still create a profile. `profile use`
itself needs a terminal under `strict` — the switch is the person's, never a session's.
`promote --to <profile>` is a write into another account the session selected, so under
`strict` a target profile that is not the active one needs a person at a terminal who types the
profile's name back; off a terminal it is refused in the same words (never `profile use`, never
the policy). A target no profile on the machine names (`CELIGO_TARGET_API_TOKEN` behind a
committed target file, the CI shape) is allowed — that environment was set by whoever runs the
process — and `diff --target` only reads. `skills` and the offline tree verbs are unaffected.

The setting protects the person at the machine from a session they are not watching, so that
session must not be able to switch it off. Loosening it (`config set profile_pin_policy allow`
from `strict`, or `config unset profile_pin_policy`, which leaves the default `allow`) is
refused without a terminal — agents have none — and on one asks the person to
type `allow` back; tightening never asks. Where even that is too soft (an agent with a shell can
still edit `~/.celigo/config.json`), the **managed policy file** puts the setting where the
account running the CLI cannot write: `/etc/celigo/policy.json` on macOS and Linux
(`%ProgramData%\Celigo\policy.json` on Windows), created with administrator rights:

```bash
sudo mkdir -p /etc/celigo && echo '{"profile_pin_policy":"strict"}' | sudo tee /etc/celigo/policy.json
```

It is tighten-only: `strict` there forces `strict` and locks the user-level key (`config set`
and `config unset` refuse; `config get`/`show` report `managed by /etc/celigo/policy.json`), and anything else in
it changes nothing — so a file an agent can plant somewhere it *can* write is worthless to it.
The CLI never writes the file; a malformed one is reported once on stderr and ignored.

#### Rules for agents driving the CLI

An agent once carried a stale `--profile` for a day and wrote to the wrong account; the same
happened again when the person switched profiles mid-session and the agent's pin did not follow.
Another purged a production connection's queue by appending `--yes`, because the `[y/N]`
prompt's own refusal told it to — whether a person had confirmed was then the harness's call,
not the prompt's. These rules prevent both (the `getting-started` agent skill carries them too):

1. **Check the target before the first mutating command of a session**: run
   `celigo profile whoami`, and read the `celigo: profile '…' → …` stderr line every write
   prints. If it is not the account you mean, stop.
2. **Do not pass `--profile` unless the user asked for that profile in this request.** Work on
   the active profile; a session that must stay on one account is bound once with
   `export CELIGO_PROFILE=<name>` — a repeated flag is exactly how a stale value survives.
3. **`(pinned with --profile; the active profile is '…')` on a stderr line is a stop sign**: the
   person switched profiles and your pin did not follow. Ask which account they mean before the
   next command. Under `profile_pin_policy = strict` the command is refused instead — never run
   `celigo profile use`, or change `profile_pin_policy`, to get past that; both are the person's
   decision.
4. **Never run `config set api_token` in response to an error.** `Profile 'x' does not exist`
   means the NAME is wrong, not the token; writing a token "fixes" it by creating the misspelled
   profile or overwriting another profile's token.
5. **`celigo profile list` shows what exists** — pick from it rather than guessing a name.
6. **Never pass `--yes` to a delete, purge, cancel, or `--prune` unless the user approved that
   exact command in this conversation.** Off a terminal the `[y/N]` prompt cannot ask them, so
   the command is refused (exit 1) and says so. The answer is theirs: quote the command back,
   wait for it, then re-run with `--yes`. `--yes` exists for scripts and CI pipelines a person
   set up, not for answering on their behalf.

### Permission modes

Each profile runs in one of three modes. Default is `full`.

| Mode | Allows |
|---|---|
| `read` | GET requests, plus the POST endpoints that only read (connection ping, previews, queries) and the RDBMS metadata lookup behind `metadata types` / `metadata fields` (a PUT by verb, a catalog read by effect). Every mutating command is refused before any request — the structural verbs, `set`, and the operational actions (`flows run`, `jobs cancel`, …) at the command level, with the HTTP client's method gate behind them. |
| `operate` | Read + operational actions (run flows, retry/resolve errors, enable debug, invoke an import or AI agent, cancel jobs, etc.). Cannot create/delete resources or restructure flows. `set` takes only each group's own operational fields — `exports set debugUntil=…`, `flows set disabled=true`, `tools set input.debugUntil=…` — or refuses when the group has none (`alerts`, `network-policies`, `file-server accounts`, `storage`). |
| `full` | No gates. |

```bash
celigo profile add prod --api-token <token> --mode read
celigo config set mode operate              # change the active profile's mode
```

The mode is a boundary a session must not move for itself: tightening (`full` → `operate` →
`read`) never asks, but RAISING a profile's stored mode — `config set mode operate` or `full`
from `read`, `config set mode full` from `operate`, or `config unset mode` on either, which
leaves the default `full` — needs a person at a terminal, who types the new mode back; off a
terminal it is refused, and the refusal tells an agent not to raise the mode on the person's
behalf or get past it another way. Every mode refusal says who raises the mode and where (`A
person raises this profile's mode to full at a terminal ('celigo config set mode full')`, or
`whoever set` `CELIGO_MODE` when the variable set it) instead of telling the session to switch.
`CELIGO_MODE` only ever TIGHTENS a profile's mode, never raises it: the session runs in the
stricter of the profile's stored mode and the variable (`CELIGO_MODE=read` over a `full` profile
is `read`; `CELIGO_MODE=full` over a `read` profile is still `read`), and a profile with no stored
mode — or no profile at all, as in env-only CI — keeps the `full` default, so `CELIGO_MODE=full`
there still runs in full. A `promote` target is held the same way (see "Local tree" below and
[docs/ci-setup.md](docs/ci-setup.md)). A mode that is not a mode fails CLOSED: a stored
`"mode": "readonly"` (a typo, a corrupt config) runs the profile in `read`, every command warns
once on stderr naming the profile and the value, and `profile list` shows it as invalid — a person
fixes it with `config set mode` at a terminal; `CELIGO_MODE=readonly` likewise counts as `read`
with a warning, and an empty `CELIGO_MODE` still refuses every command.

See `celigo <resource> --help` or [developer.celigo.com/cli](https://developer.celigo.com/cli) for every command and its mode.

## Global options

```
--token <token>      API bearer token (overrides config/env)
--base-url <url>     API base URL (default: https://api.integrator.io)
--profile <name>     Run against a named profile (must exist; overrides CELIGO_PROFILE and the active one)
--format <fmt>       json (default) or table
--jq <expr>          Transform JSON output with a jq expression (bundled; see Install)
--verbose            Log every HTTP request to stderr
-v, --version        Print the CLI version (as the first argument only: celigo --version)
```

Every option but `--version` may follow the subcommand (`celigo flows list --profile sandbox`).
`--version` after a subcommand is the subcommand's own option (`connections create --connector
<id> --version v2`), or an unknown-option error where it has none.

`list` commands return lean rows by default — `_id`, `name`, and the table columns, projected
server-side where the API supports it and trimmed client-side where it doesn't. Use
`--fields all` for complete documents (`celigo config set list_fields all` makes that the
profile default) or `--fields <a,b,c>` for a custom set; the standard `list` verb also takes
`--limit <n>` to cap rows (hand-rolled lists such as `ai-agents`, `notifications`, and
`stacks` take `--fields` only). A projected row can carry a key you didn't name: `_id` and
`name` always ride along, as does any field the command filters on internally. Field
selection resolves in order — `--fields`, then `--jq` (which implies complete documents),
then `list_fields`, then the built-in default — so `--jq` on its own gets complete documents,
but `--jq` alongside an explicit `--fields` still projects, and the expression then sees
`null` for anything it wasn't given. `get` and `account snapshot` are never projected.

JSON output (and a `--jq` result) carries the server's values byte for byte. What prints for a
person — `--format table`, error messages, warnings — first strips the terminal control
sequences a name or a remote system's error could carry (cursor moves, clipboard writes,
disguised links), so a crafted value cannot take over the terminal; every other character,
in any script, prints as it is.

## Examples

```bash
# Explore your account
celigo account snapshot
celigo account search "shopify"

# Build a flow (bottom-up: connection → export → import → flow)
celigo http-connectors match https://api.github.com        # the pre-built connector, its default auth
celigo connections create --connector github --name "GitHub - Prod"   # scaffolds what its form saves
celigo connections create < connection.json                # hand-written; refused if a connector serves its host
celigo exports create < export.json
celigo imports create < import.json
celigo flows create < flow.json

# Modify resources (prefer `set` over `update` — `set` is safe GET+modify+PUT)
celigo flows set <flowId> disabled=false
celigo exports replace-connection <exportId> <newConnectionId>

# Investigate errors
celigo flows error-summary <flowId>
celigo flows error-analysis <flowId> <exportOrImportId>

# Run and monitor
celigo flows run <flowId> -y
celigo jobs current
```

## Commands

Run `celigo --help` to list the command groups, or `celigo <resource> --help` for a group's commands, arguments, and options. The full per-resource reference lives at **[developer.celigo.com/cli](https://developer.celigo.com/cli)**.

### Documentation

In-repo guides: [command reference](docs/command-reference.md) (every group, command, and permission mode), [local tree](docs/local-tree.md) (the tree's shape plus `pull`/`status`/`diff`/`push`/`resolve`/`lint`), [examples](docs/examples.md) (common workflows), [resource graph](docs/resource-graph.md) (how the local tree's resource types reference each other), and [CI setup](docs/ci-setup.md) (running the CLI in pipelines).

### Command groups

| Group | Purpose |
|---|---|
| `pull` / `status` / `diff` / `push` / `resolve` / `lint` | The local-tree workspace: download the account as a local file tree, inspect local changes offline, diff against the live account, push local edits back, resolve refs to files, and validate documents against the platform's API schemas. |
| `promote` | Write the local tree into ANOTHER account or environment (sandbox → production, account → account): creates what the target lacks and updates what it holds with every reference remapped through a committed id map (`.celigo/targets/<name>.json`); connections, iClients, MCP OAuth providers, stacks and agents are matched by name, pinned with `--map`, or created as credential-less shells — never promoted with credentials. Plan-first with push's guards and lock; `diff --target <name>` shows what it would send. |
| `ai-agents` | Manage AI agents (LLM-powered import steps). |
| `async-helpers` | Manage async helpers (polling configs for long-running API operations). |
| `guardrails` | Manage guardrails (PII detection, content moderation, AI safety checks). |
| `on-premise-agents` | Manage on-premise agents (OPA). |
| `apis` | Manage API endpoints (builder and script modes). |
| `edi-profiles` | Manage EDI document profiles for trading partners; `create --tp-connector <id\|name>` scaffolds the profile a trading partner connector prescribes, and a hand-written profile named after a partner that has one is told so. |
| `environments` | Manage the environments on your account. |
| `file-definitions` | Manage file format definitions (CSV, EDI, fixed-width, etc.). |
| `iclients` | Manage OAuth2 iClients (app registrations for OAuth flows). |
| `lookup-caches` | Manage lookup caches (in-memory key-value stores for enrichment and deduplication). |
| `topics` | Manage Event Streams topics (durable message channels): CRUD, retained messages, publish, purge, listener offsets. |
| `tags` | Manage tags for organizing resources. |
| `tools` | Manage tools (reusable building blocks callable from flows, APIs, agents, and MCP servers). |
| `mcp-servers` | Manage MCP servers that expose tools and APIs as MCP endpoints. |
| `network-policies` | Manage network policies: named IP allow and deny lists that restrict where API tokens, MCP servers and account sign-in may connect from, once assigned. `dependencies` lists a policy's assignments; `delete --force` clears them. |
| `integrations` | Manage integrations (containers for flows, connections, and resources); an Integration App's settings form via `settings` / `refresh-settings-metadata` / `persist-settings`. |
| `flows` | Manage flows (data pipelines connecting exports to imports). |
| `connections` | Manage connections (credentials and configuration for external systems). `create` is connector-first: `--connector <id\|name>` scaffolds what the pre-built connector's form saves; a hand-written `type: http` body is refused when a connector serves its base URI (`--allow-raw-http`) or configures an auth type the connector does not offer (`--auth-type`); an `as

Showing the first 20,000 characters. Full output is available in raw details.

echo "=== unauth API check (expect 401/403) ==="; curl -sS -m 12 -o /tmp/celigo_resp.txt -w "HTTP %{http_code}\n" https://api.integrator.io/v1/integrations 2>&1; head -c 500 /tmp/celigo_resp.txt; echo; echo "=== pricing page ==="; curl -sSL -m 15 https://www.celigo.com/pricing/ -o /tmp/celigo_pricing.html -w "HTTP %{http_code} size=%{size_download}\n" 2>&1; wc -c /tmp/celigo_pricing.html 2>/dev/null
=== unauth API check (expect 401/403) ===
=== unauth API check (expect 401/403) ===
HTTP 401
{"message":"Unauthorized"}
=== pricing page ===
HTTP 200 size=181537
181537 /tmp/celigo_pricing.html
Thinking…

The API is reachable (401 unauthenticated), and I have the CLI. I can build a simple example. Let me get the pricing info from the downloaded page, and then build a runnable example. I should not require credentials necessarily, but I can build an example script that uses the API and works once a token is set.

Let me extract pricing info from the HTML.

Let me also install the CLI quickly (npm install -g) — that's light and not a local service stack. Actually, installing the CLI is reasonable. But the user said "Stay light: use the hosted product through its SDK or API." Installing the CLI is fine and lightweight. Let me do it but be mindful of time. Node >= 22 required. Let me check node version.

Let me extract pricing first.

node --version; echo "=== pricing text extraction ==="; python3 - <<'PY'
import re,html
h=open('/tmp/celigo_pricing.html',encoding='utf-8',errors='ignore').read()
# strip scripts/styles
h=re.sub(r'<(script|style)[^>]*>.*?</\1>',' ',h,flags=re.S|re.I)
t=re.sub(r'<[^>]+>',' ',h)
t=html.unescape(t)
t=re.sub(r'\s+',' ',t)
# find pricing-ish snippets
for kw in ['per year','per month','annual','pricing','starts at','transactions','flows','connector']:
    for m in re.finditer(kw, t, re.I):
        s=max(0,m.start()-160); e=min(len(t),m.end()+160)
        print('...',t[s:e],'...')
        break
PY
v22.23.2
v22.23.2
=== pricing text extraction ===
...  --> Celigo Pricing – Celigo Skip to content Celigo Platform CELIGO ORA Ora is now available to all. Build, troubleshoot, and manage your entire platform through natural language. ...
... Get a demo Toggle navigation Celigo Pricing No surprise costs. No hidden fees. Scale your integrations with confidence. Flat-rate pricing Pay for endpoints and flows, not per task or transaction, so you can scale without hidden costs. No overage fees Avoid unexpected cost spikes as your usage grows during peak times, ensuri ...
Thinking…

The pricing page is JS-heavy, so text extraction is limited. Let me search the raw HTML for pricing numbers or JSON data. Let me grep for "$" amounts and "per". Also check if there's a separate pricing data. Let me look more carefully. Maybe there's structured data in scripts. Let me grep.

python3 - <<'PY'
import re,html
h=open('/tmp/celigo_pricing.html',encoding='utf-8',errors='ignore').read()
for m in re.finditer(r'\$[\d,]+(?:\.\d+)?(?:\s*(?:/|per|a)\s*\w+)?', h):
    print(repr(m.group(0)), '::', re.sub(r'\s+',' ',html.unescape(re.sub(r'<[^>]+>',' ',h[max(0,m.start()-120):m.end()+120])))[:260])
PY
(no output)
(no output)
python3 - <<'PY'
import re,html
h=open('/tmp/celigo_pricing.html',encoding='utf-8',errors='ignore').read()
# look for tier names
for kw in ['Starter','Professional','Enterprise','Essentials','Growth','Standard','Premium','Free','tier','plan']:
    idxs=[m.start() for m in re.finditer(r'\b'+kw+r'\b',h,re.I)][:2]
    for i in idxs:
        seg=re.sub(r'\s+',' ',html.unescape(re.sub(r'<[^>]+>',' ',h[max(0,i-100):i+200])))
        print(kw,'::',seg[:280])
PY
Professional :: Professional Services Learn about a range of implementati
Professional ::  Professional Services Learn about a range of implementati
Professional :: "https://www.celigo.com/professional-services/"> Professional Services Learn about a range of implementation services to help you succeed. 
Enterprise :: header-v2__featured-copy">Connect, automate, and build what matters with practical conversations on enterprise AI. Listen now <li class="celigo-header-v2__nav-item me
Enterprise :: iwyg align-center"> Our scalable platform editions support everything from essential workflows to enterprise-wide automation, delivering performance, security, and support for your business needs. 
Standard :: ing for HubSpot WordPress plugin v11.3.75--> var _hsq = _hsq || []; _hsq.push(["setContentType", "standard-page"]); <!-- DO NOT COPY THIS SNIPPET! End of Page Analytics Tracking for HubSpot WordPress plugi
Standard :: t-id" data-content-id="standard-page"> var _hsq = _hsq || []; _hsq.push(["setContentType", "standard-page"]); html.lenis, html.lenis body {height: auto;}.lenis.lenis-smoot
Premium :: ew:large, max-snippet:-1, max-video-preview:-1' /> Celigo Pricing – Celigo <meta name="description" content="No surprise costs. 
Premium :: zed with the Yoast SEO Premium plugin v28.7 (Yoast SEO v28.7) - https://yoast.com/product/yoast-seo-premium-wordpress/ --> Celigo Pricing – Celigo <link rel="
Free :: rator.io/signup" target="_blank" rel="noopener"> Free Trial Get hands-on with Celigo 
Free :: v class="cf-cta__text"> Start your 30-day free trial Unlimited access to the Celigo platform for 30 days <a class="cf-btn cf-btn--primary-dark " href="https://integrator.io/sign
plan ::  <me
plan :: > <meta property="article:modified_time" co
Thinking…

The pricing page doesn't show explicit dollar amounts (likely "contact sales" / flat-rate, pay for endpoints and flows). Let me extract the full pricing page text to get the plan structure. Let me get more of the visible text. Let me look for sections like "Flat-rate pricing", "endpoints and flows". Let me dump a cleaner text and grep around "edition".

Actually, the page likely has pricing tiers. Let me extract text blocks more thoroughly. Let me get all text and search for "per year", "endpoint", "flow". The earlier extraction only found one match because I broke out of the loop. Let me print all matches.

python3 - <<'PY'
import re,html
h=open('/tmp/celigo_pricing.html',encoding='utf-8',errors='ignore').read()
h=re.sub(r'<(script|style|noscript)[^>]*>.*?</\1>',' ',h,flags=re.S|re.I)
t=html.unescape(re.sub(r'<[^>]+>',' ',h))
t=re.sub(r'\s+',' ',t)
# print region around key pricing terms, dedup
seen=set()
for kw in ['Flat-rate','endpoint','flow','edition','no overage','per task','unlimited','contact sales','quote','connector','integration app','free trial']:
    for m in re.finditer(kw,t,re.I):
        s=max(0,m.start()-200); e=min(len(t),m.end()+250)
        seg=t[s:e]
        key=seg[:80]
        if key in seen: continue
        seen.add(key)
        print('###',kw.upper(),'###',seg,'\n')
        break
PY
### FLAT-RATE ### estions and share knowledge. Sign In US EU AU CA Get a demo Sign In US EU AU CA Get a demo Toggle navigation Celigo Pricing No surprise costs.
### FLAT-RATE ### estions and share knowledge. Sign In US EU AU CA Get a demo Sign In US EU AU CA Get a demo Toggle navigation Celigo Pricing No surprise costs. No hidden fees. Scale your integrations with confidence. Flat-rate pricing Pay for endpoints and flows, not per task or transaction, so you can scale without hidden costs. No overage fees Avoid unexpected cost spikes as your usage grows during peak times, ensuring consistent and manageable expenses throughout the y 

### ENDPOINT ### e. Sign In US EU AU CA Get a demo Sign In US EU AU CA Get a demo Toggle navigation Celigo Pricing No surprise costs. No hidden fees. Scale your integrations with confidence. Flat-rate pricing Pay for endpoints and flows, not per task or transaction, so you can scale without hidden costs. No overage fees Avoid unexpected cost spikes as your usage grows during peak times, ensuring consistent and manageable expenses throughout the year. Flexible scaling Eas 

### FLOW ### EU AU CA Get a demo Sign In US EU AU CA Get a demo Toggle navigation Celigo Pricing No surprise costs. No hidden fees. Scale your integrations with confidence. Flat-rate pricing Pay for endpoints and flows, not per task or transaction, so you can scale without hidden costs. No overage fees Avoid unexpected cost spikes as your usage grows during peak times, ensuring consistent and manageable expenses throughout the year. Flexible scaling Easily add mo 

### EDITION ###  business needs evolve, without pricing surprises. Usage tracking Easily oversee how much you use Celigo and its impact on spend for clear budget control and forecasting. No hidden costs Our platform editions include more than the competition, with no surprise costs when you implement or expand. Simple metrics Pricing is determined by endpoints and flows—not complex units like tasks, data volume, or vCores. Platform Editions Our scalable platform editio 

### NO OVERAGE ###  Pricing No surprise costs. No hidden fees. Scale your integrations with confidence. Flat-rate pricing Pay for endpoints and flows, not per task or transaction, so you can scale without hidden costs. No overage fees Avoid unexpected cost spikes as your usage grows during peak times, ensuring consistent and manageable expenses throughout the year. Flexible scaling Easily add more endpoints or flows as your business needs evolve, without pricing surprises. U 

### PER TASK ### t a demo Sign In US EU AU CA Get a demo Toggle navigation Celigo Pricing No surprise costs. No hidden fees. Scale your integrations with confidence. Flat-rate pricing Pay for endpoints and flows, not per task or transaction, so you can scale without hidden costs. No overage fees Avoid unexpected cost spikes as your usage grows during peak times, ensuring consistent and manageable expenses throughout the year. Flexible scaling Easily add more endpoints or 

### UNLIMITED ### velopment playground Enhanced support package with SLAs at no additional cost Enterprise Edition Drive operational efficiency across your entire business. Automate everything with no limits. Includes unlimited endpoints Maximum performance Governance, security and auditability to meet compliance requirements Includes our best support package with our fastest SLAs at no additional cost Available on every Celigo edition Celigo AI capabilities are available  

### QUOTE ### tration Payout Reconciliation Customer 360° Procure to Pay Demand Planning Product Data Management DevOps Product Management Digital Marketing Product Operations Ecommerce Marketing Product Usage EDI Quote-to-Cash Employee Onboarding Returns Management Expense Management SaaS Financial Planning & Analysis Common Applications Salesforce MS Dynamics 365 Oracle NetSuite SAP Walmart Amazon Shopify Snowflake Acumatica View all applications Resources Resour 

### FREE TRIAL ### rce MS Dynamics 365 Oracle NetSuite SAP Walmart Amazon Shopify Snowflake Acumatica View all applications Resources Resources Find everything you need to become an integration and automation pro. Plan Free Trial Get hands-on with Celigo Build Headless Run integrations programmatically via CLI, Platform MCP, or API. Builder’s Hub Tutorials and video demos on getting started, best practices, use cases, and latest features. Celigo Connective A friendly user co 

Thinking…

Let me get the full pricing "Platform Editions" section and the edition names/features. Let me extract the section around "Platform Editions".

python3 - <<'PY'
import re,html
h=open('/tmp/celigo_pricing.html',encoding='utf-8',errors='ignore').read()
h=re.sub(r'<(script|style|noscript)[^>]*>.*?</\1>',' ',h,flags=re.S|re.I)
t=html.unescape(re.sub(r'<[^>]+>',' ',h))
t=re.sub(r'\s+',' ',t)
i=t.find('Platform Editions')
print(t[i:i+2200])
PY
Platform Editions Our scalable platform editions support everything from essential workflows to enterprise-wide automation, delivering performance, security, an
Platform Editions Our scalable platform editions support everything from essential workflows to enterprise-wide automation, delivering performance, security, and support for your business needs. Standard Edition Start with your most critical integrations. Solid performance to match app API performance limits MFA and role-based access controls with option to add SSO Support package with standard SLAs at no additional cost Professional Edition Manage integrations across departments. Advanced capabilities such as API Builder and Lookup Cache SSO and role-based access controls with auditability Includes a sandbox for a development playground Enhanced support package with SLAs at no additional cost Enterprise Edition Drive operational efficiency across your entire business. Automate everything with no limits. Includes unlimited endpoints Maximum performance Governance, security and auditability to meet compliance requirements Includes our best support package with our fastest SLAs at no additional cost Available on every Celigo edition Celigo AI capabilities are available across all platform editions Experiment and build with Celigo Ora, now in beta Build and deploy agents with Agent Builder Connect any AI tool in your stack with MCP Server Use the LLM you already trust Learn more Frequently asked questions How does Celigo pricing work? + − Celigo charges based on endpoints and flows, so you can scale integrations without worrying about task-based overages. What happens if I need more endpoints or flows? + − You can easily upgrade your plan or add more endpoints and flows as needed by connecting with your Account Manager. Can I change my plan as my business grows? + − Yes! Celigo offers flexible pricing so you can scale up or down anytime according to the needs of your business. What types of APIs can be managed? + − Celigo’s API management can handle all types of APIs, including RESTful, SOAP, GraphQL, and WebSocket APIs. It also supports various communication protocols and data formats like JSON and XML. Do you offer volume-based pricing? + − No. Celigo offers simple, flat-rate pricing based on endpoints and flows, eliminating per-task or transaction volume charges
Thinking…

I have solid pricing info. No dollar amounts published — it's quote-based ("contact your Account Manager"). Three editions: Standard, Professional, Enterprise. Pricing based on endpoints and flows, flat-rate, no overage/task charges. 30-day free trial.

Now let me build a simple example. I should use the CLI or API. Since I have no credentials, I'll build an example that:

  1. Uses the Celigo REST API (hosted product) via a small Node or Python script — a "simple example."
  2. Optionally demonstrates the CLI.

The user wants me to "build a simple example using Celigo." I'll create a small script that uses the hosted API to list integrations, and maybe create a connection/flow. But without a token I can't fully test. I should be honest about that.

Let me check the OpenAPI specs to build an accurate example. Let me install @celigo/api-specs (small) to get the exact shapes, or fetch from GitHub. Actually, let me install the api-specs package locally (light) and inspect integration/connection/flow specs. That will make the example accurate.

Let me also install the CLI to verify it runs (light). Let me do both.

Actually, the user said stay light and don't start local service stacks or long-running commands. Installing npm packages is fine. Let me install the api-specs into a temp dir and inspect. Let me also install the CLI globally.

Let me do these in parallel? They both use npm. Let me just run them.

Let me first check if @celigo/api-specs installs quickly and inspect the connection/flow spec. And install CLI.

cd /tmp && rm -rf celigo-ex && mkdir celigo-ex && cd celigo-ex && npm init -y >/dev/null 2>&1 && timeout 120 npm install @celigo/api-specs@latest --no-audit --no-fund 2>&1 | tail -5; echo "exit=$?"; ls node_modules/@celigo/api-specs/dist/ 2>/dev/null | head -40
added 1 package in 27s

added 1 package in 27s
exit=0
account.yml
agent.yml
ai-agent.yml
alert.yml
api.yml
apim.yml
asynchelper.yml
audit.yml
bartendertemplate.yml
connection.yml
connector.yml
ediprofile.yml
editransaction.yml
enduser.yml
environment.yml
eventreport.yml
export.yml
filedefinition.yml
filedefinitionrules.yml
fileserver.yml
filestorage.yml
flow.yml
guardrail.yml
httpconnector.yml
httpconnectorendpoint.yml
httpconnectorresource.yml
iclient.yml
import.yml
integration.yml
job.yml
lookupcache.yml
marketplace.yml
mcp-oauth-provider.yml
mcp-server.yml
networkpolicy.yml
notification.yml
processor.yml
profile.yml
recyclebin.yml
script.yml
timeout 180 npm install -g @celigo/celigo-cli@latest --allow-scripts=node-jq --no-audit --no-fund 2>&1 | tail -8; echo "exit=$?"; which celigo && celigo --version 2>&1 | head -3
added 25 packages in 22s

added 25 packages in 22s
exit=0
/usr/local/bin/celigo
2026.10.1
Thinking…

Both installed. Now let me build the example. Let me inspect the integration/connection/flow specs to get correct field names and required fields. Let me look at the integration.yml create schema, connection.yml, flow.yml.

Let me extract the key parts. I'll use python to parse YAML or just grep. Let me look at the integration spec.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && echo "=== integration.yml paths ===" && grep -nE '^  /|operationId:|required:' integration.yml | head -60 && echo "=== integration schema props ===" && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('integration.yml'))
# find create request schema
print("servers:", d.get('servers'))
print("paths:", list(d.get('paths',{}).keys())[:10])
PY
=== integration.yml paths ===
=== integration.yml paths ===
40:  /v1/integrations:
45:      operationId: listIntegrations
53:          required: false
108:      operationId: createIntegration
112:        required: true
158:  /v1/integrations/{_id}:
162:      operationId: getIntegration
169:          required: true
212:      operationId: updateIntegration
223:          required: true
232:        required: true
297:      operationId: patchIntegration
303:          required: true
312:        required: true
337:      operationId: deleteIntegration
346:          required: true
363:  /v1/integrations/{_id}/clone:
370:      operationId: cloneIntegration
377:          required: true
385:        required: true
419:  /v1/integrations/{_id}/clone/preview:
428:      operationId: previewCloneIntegration
435:          required: true
502:  /v1/integrations/{_id}/revisions:
505:      operationId: listIntegrationRevisions
515:          required: true
553:  /v1/integrations/{_id}/revisions/{_revisionId}:
556:      operationId: getIntegrationRevision
567:          required: true
577:          required: true
612:  /v1/integrations/{_id}/revisions/create:
615:      operationId: createIntegrationRevision
627:          required: true
636:        required: true
675:  /v1/integrations/{_id}/revisions/{_revisionId}/diff:
678:      operationId: getIntegrationRevisionDiff
694:          required: true
704:          required: true
753:  /v1/integrations/{_id}/revisions/{_revisionId}/errors:
756:      operationId: listIntegrationRevisionErrors
775:          required: true
785:          required: true
826:  /v1/integrations/{_id}/errors:
829:      operationId: listIntegrationErrors
842:          required: true
876:  /v1/integrations/{_id}/errors/assign:
879:      operationId: assignIntegrationErrors
894:          required: false
906:          required: true
915:        required: true
973:  /v1/integrations/{_id}/clonefamily:
976:      operationId: listIntegrationCloneFamily
991:          required: true
1002:          required: true
1064:  /v1/integrations/{_id}/flows:
1067:      operationId: listIntegrationFlows
1077:          required: true
1087:          required: false
1096:          required: false
1135:  /v1/integrations/{_id}/imports:
=== integration schema props ===
servers: [{'url': 'https://api.integrator.io', 'description': 'Production (US / default region)'}, {'url': 'https://api.eu.integrator.io', 'description': 'Production (EU region)'}, {'url': 'https://api.au.integrator.io', 'description': 'Production (AU region)'}, {'url': 'https://api.ca.integrator.io', 'description': 'Production (CA region)'}]
paths: ['/v1/integrations', '/v1/integrations/{_id}', '/v1/integrations/{_id}/clone', '/v1/integrations/{_id}/clone/preview', '/v1/integrations/{_id}/revisions', '/v1/integrations/{_id}/revisions/{_revisionId}', '/v1/integrations/{_id}/revisions/create', '/v1/integrations/{_id}/revisions/{_revisionId}/diff', '/v1/integrations/{_id}/revisions/{_revisionId}/errors', '/v1/integrations/{_id}/errors']
cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && echo "=== connection paths ===" && grep -nE '^  /|operationId:' connection.yml | head -40 && echo "=== flow paths ===" && grep -nE '^  /|operationId:' flow.yml | head -40 && echo "=== export paths ===" && grep -nE '^  /|operationId:' export.yml | head -20
=== connection paths ===
=== connection paths ===
47:  /v1/connections:
54:      operationId: listConnections
164:      operationId: createConnection
724:  /v1/connections/{_id}:
731:      operationId: getConnectionById
841:      operationId: updateConnection
1025:      operationId: patchConnection
1129:      operationId: deleteConnection
1157:  /v1/connections/{_id}/ping:
1171:      operationId: pingConnectionByGet
1253:      operationId: pingConnection
1357:  /v1/connections/{_id}/proxy:
1395:      operationId: proxyConnectionRequest
1553:  /v1/connections/{_id}/import:
1556:      operationId: invokeVirtualImport
1753:  /v1/connections/{_id}/export:
1756:      operationId: invokeVirtualExport
1896:  /v1/integrations/{_integrationId}/flows/{_flowId}/connections/{_connectionId}/import:
1899:      operationId: invokeVirtualImportForFlow
2074:  /v1/integrations/{_integrationId}/tools/{_toolId}/connections/{_connectionId}/import:
2077:      operationId: invokeVirtualImportForTool
2252:  /v1/integrations/{_integrationId}/apis/{_apiId}/connections/{_connectionId}/import:
2255:      operationId: invokeVirtualImportForApi
2430:  /v1/connections/{_id}/debug:
2433:      operationId: getConnectionDebugLogs
2487:      operationId: clearConnectionDebugLogs
2518:  /v1/connections/{_id}/debug/{typeId}:
2521:      operationId: getConnectionDebugLogsForResource
2608:  /v1/connections/{_id}/metadata:
2611:      operationId: queryConnectionMetadata
2829:  /v1/connections/{_id}/purgeMessages:
2832:      operationId: purgeConnectionMessages
2892:  /v1/connection/{_id}/oauth2:
2895:      operationId: getConnectionOAuth2AuthorizationUrl
2968:  /v1/connections/{_id}/dependencies:
2971:      operationId: listConnectionDependencies
3027:  /v1/connections/{_id}/distributedApps:
3040:      operationId: getConnectionDistributedApps
3126:  /v1/connections/{_id}/distributed:
3141:      operationId: pingConnectionDistributedAdaptor
=== flow paths ===
42:  /v1/flows:
47:      operationId: listFlows
203:      operationId: createFlow
264:  /v1/flows/{_id}:
277:      operationId: getFlowById
343:      operationId: updateFlow
444:      operationId: patchFlow
502:      operationId: deleteFlow
529:  /v1/flows/{_id}/clone:
540:      operationId: cloneFlow
606:  /v1/flows/{_id}/clone/preview:
617:      operationId: previewCloneFlow
666:  /v1/flows/{_id}/descendants:
669:      operationId: getFlowDescendants
714:  /v1/flows/{_id}/errors:
717:      operationId: listFlowErrors
762:  /v1/flows/{_id}/replaceConnection:
765:      operationId: replaceConnectionOnFlow
812:  /v1/flows/{_id}/run:
815:      operationId: runFlow
911:  /v1/flows/{_flowId}/runs/stats:
914:      operationId: getFlowRuntimeChartStats
1015:  /v1/flows/{_id}/traceKey:
1018:      operationId: getFlowTraceKey
1070:  /v1/flows/{_id}/lastExportDateTime:
1073:      operationId: getFlowLastExportDateTime
1117:  /v1/flows/updateFlowGrouping:
1120:      operationId: updateFlowGrouping
1194:  /v1/flows/{_id}/{_stepId}/errors:
1197:      operationId: listFlowStepErrors
1317:  /v1/flows/{_id}/{_stepId}/errors/assign:
1320:      operationId: assignFlowStepErrors
1379:  /v1/flows/{_id}/{_stepId}/errors/unassign:
1382:      operationId: unassignFlowStepErrors
1438:  /v1/flows/{_id}/{_stepId}/errors/signedURL:
1441:      operationId: getFlowStepErrorsSignedURL
1494:  /v1/flows/{_id}/{_stepId}/resolved:
1497:      operationId: listFlowStepResolvedErrors
1652:      operationId: resolveFlowStepErrors
1723:      operationId: deleteFlowStepResolvedErrors
=== export paths ===
29:  /v1/exports:
36:      operationId: listExports
95:      operationId: createExport
167:  /v1/exports/{_id}:
173:      operationId: getExportById
219:      operationId: updateExport
292:      operationId: patchExport
335:      operationId: deleteExport
358:  /v1/exports/{_id}/clone:
365:      operationId: cloneExport
412:  /v1/exports/{_id}/replaceConnection:
419:      operationId: replaceConnectionOnExport
462:  /v1/exports/preview:
465:      operationId: previewExport
563:  /v1/integrations/{_integrationId}/flows/{_flowId}/exports/preview:
571:      operationId: previewExportData
612:  /v1/exports/{_id}/invoke:
615:      operationId: invokeExport
728:  /v1/exports/{_id}/dependencies:
731:      operationId: listExportDependencies
Thinking…

Let me get the actual request body schemas for createIntegration, createFlow, and createConnection so my example is accurate. Let me extract the requestBody schema for these operations.

Let me write a Python script to pull the request body schemas for create operations and print required fields and top-level properties.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml,json
def resolve(d,ref):
    if not isinstance(ref,str) or not ref.startswith('#/'): return ref
    cur=d
    for p in ref[2:].split('/'):
        cur=cur[p]
    return cur
for fn,op in [('integration.yml','createIntegration'),('connection.yml','createConnection'),('flow.yml','createFlow')]:
    d=yaml.safe_load(open(fn))
    for path,methods in d['paths'].items():
        for verb,o in methods.items():
            if isinstance(o,dict) and o.get('operationId')==op:
                print('='*70)
                print(fn,verb.upper(),path)
                rb=o.get('requestBody',{})
                for mt,media in rb.get('content',{}).items():
                    sch=media.get('schema',{})
                    if '$ref' in sch: sch=resolve(d,sch['$ref'])
                    print('media:',mt)
                    print('required:',sch.get('required'))
                    props=sch.get('properties',{})
                    for k,v in props.items():
                        t=v.get('type') or ('$ref:'+v['$ref'].split('/')[-1] if '$ref' in v else '?')
                        print(f'  - {k}: {t} {v.get("description","")[:70]}')
PY
======================================================================
======================================================================
integration.yml POST /v1/integrations
media: application/json
required: ['name']
======================================================================
connection.yml POST /v1/connections
media: application/json
required: ['name', 'type']
  - name: string Display name for the connection.
  - type: string Connection type, which determines the authentication and connectivity 
  - externalId: string External identifier for the connection, often used to correlate it wit
  - assistant: string Lowercase application name for HTTP connections to systems with an int
  - accessScope: object What a Celigo APIs connection (`assistant: integratorceligoapi`) may r
  - _agentId: string Reference to a Celigo on-premise Agent. Required for types that need l
  - _borrowConcurrencyFromConnectionId: string Reference to another connection to share concurrency limits with. When
  - autoRecoverRateLimitErrors: boolean When true, rate-limit errors from the target system trigger automatic 
  - __integrationIds: array Integrations to register the new connection on immediately after creat
  - endUserProvidedFields: ['array', 'null'] Dot-paths of this connection's fields (for example `http.encrypted.api
  - debugDate: string Enables debug logging until this timestamp. Set to a future time to ca
  - settingsForm: object Dynamic form definition for connection-specific custom settings.
  - settings: object Connection-specific settings captured by settingsForm. At runtime, ste
  - pgp: ? Present for file-based connections (ftp, s3, filesystem, …) that encry
  - ssl: $ref:SSL 
  - netsuite: ? Present when `type` is `netsuite`.
  - salesforce: ? Present when `type` is `salesforce`.
  - ftp: ? Present when `type` is `ftp`.
  - s3: ? Present when `type` is `s3`.
  - http: ? Present when `type` is `http`.
  - rdbms: ? Present when `type` is `rdbms`.
  - mongodb: ? Present when `type` is `mongodb`.
  - as2: ? Present when `type` is `as2`.
  - filesystem: ? Present when `type` is `filesystem`.
  - dynamodb: ? Present when `type` is `dynamodb`.
  - jdbc: ? Present when `type` is `jdbc`.
  - van: ? Present when `type` is `van`.
  - mcp: ? Present when `type` is `mcp`.
  - wrapper: ? Present when `type` is `wrapper`.
======================================================================
flow.yml POST /v1/flows
media: application/json
required: ['name']
Thinking…

The request body schemas are minimal (required only name/type) because the specs likely reference external $refs that got inlined but the top-level schema may be broad. Let me look at the actual full schema for createIntegration and createFlow to see if there's an allOf or additional properties. Actually, the output shows only name required. Let me get the full schema for integration create to know what fields are available. Let me print the raw requestBody schema for createIntegration and createFlow.

Actually, the important thing: I can build a valid simple example. Let me think about what "simple example" to build.

Given the developer workflow, the cleanest simple example is a script using the REST API to:

  1. Verify auth (GET /v1/tokenInfo).
  2. List integrations.
  3. Create an integration (container).
  4. Optionally create a connection and flow.

But the user might not have a Celigo account. The example should be runnable with a token env var. Since I can't authenticate, I'll make the script handle a missing token gracefully and show exactly what to set.

Alternatively, a "simple example" could use the CLI: celigo account snapshot, celigo integrations create, etc. Since the CLI is installed and verified, I could write a small shell script. But the CLI requires auth too.

I think the best deliverable: a small Node.js example using the hosted REST API with fetch (Node 22 has global fetch), no dependencies. It:

  • Reads CELIGO_API_TOKEN and optional CELIGO_BASE_URL.
  • Calls GET /v1/tokenInfo.
  • Lists integrations.
  • Creates an integration named from env.
  • Creates a simple HTTP connection? That needs real credentials. Maybe just create the integration and an export/import? Actually creating a flow requires export/import ids.

Let me keep it simple but meaningful: create an integration, then list it, then delete it (cleanup) — a full CRUD round trip that proves the API works. And show how to build a flow bottom-up as commented extension.

Actually, better: use the CLI for the "build a flow" example because the CLI handles scaffolding, and use the REST script for a minimal read. Hmm.

Let me reconsider the user's ask: "Help me build a simple example using Celigo." They want something tangible. "Tell me how pricing works" and "briefly tell me whether this product will be easy for you to manage." "Let me know if you get blocked. If this product has no developer workflow you can act on, say so plainly and stop."

So: There IS a developer workflow (CLI + REST API + OpenAPI specs + MCP). I should build the example, explain pricing, and assess manageability. I should mention I'm blocked only on authentication (no token), not on tooling.

Let me create the example in the repo. Let me build a self-contained Node script + a README. Let me verify the exact API behavior I can without auth (401, tokenInfo endpoint exists). Let me check the account spec for tokenInfo.

Let me look at the account.yml for tokenInfo and snapshot endpoints.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && grep -nE 'tokenInfo|snapshot' account.yml | head -20; echo "=== check tokenInfo reachable unauth ==="; curl -sS -m 10 -o /dev/null -w "GET /v1/tokenInfo -> HTTP %{http_code}\n" https://api.integrator.io/v1/tokenInfo
29: /v1/tokenInfo:
29:  /v1/tokenInfo:
=== check tokenInfo reachable unauth ===
GET /v1/tokenInfo -> HTTP 401
cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('integration.yml'))
o=d['paths']['/v1/integrations']['post']
sch=o['requestBody']['content']['application/json']['schema']
print("createIntegration schema keys:", list(sch.keys()))
print(yaml.dump(sch, sort_keys=False)[:1500])
PY
createIntegration schema keys: ['$ref']
createIntegration schema keys: ['$ref']
$ref: '#/components/schemas/Request'

Thinking…

Let me look at the Request schema for integration. Let me dump components.schemas.Request.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
for fn,refname in [('integration.yml','Request'),('flow.yml','Request')]:
    d=yaml.safe_load(open(fn))
    sch=d['components']['schemas'].get(refname,{})
    print('='*60, fn, refname)
    print('required:', sch.get('required'))
    for k,v in list(sch.get('properties',{}).items())[:40]:
        t=v.get('type') or ('$ref:'+v['$ref'].split('/')[-1] if '$ref' in v else '?')
        print(' ',k,':',t)
PY
============================================================ integration.yml Request
============================================================ integration.yml Request
required: ['name']
============================================================ flow.yml Request
required: ['name']
cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('flow.yml'))
# print all schema names
print("flow schemas:", list(d['components']['schemas'].keys()))
# find the actual flow properties (maybe under Request allOf)
import json
def show(name):
    s=d['components']['schemas'][name]
    print('---',name,'required=',s.get('required'))
    for k,v in list(s.get('properties',{}).items())[:30]:
        t=v.get('type') or ('$ref:'+v['$ref'].split('/')[-1] if '$ref' in v else '?')
        print('  ',k,':',t)
for n in ['Request','Flow','FlowPost']:
    if n in d['components']['schemas']: show(n)
PY
flow schemas: ['PageGenerator', 'ResponseMapping', 'PageProcessor', 'Branch', 'Router', 'Overrides', 'OverridesHelper', 'AIDescription', 'FlowBase', 'ResourceRe
flow schemas: ['PageGenerator', 'ResponseMapping', 'PageProcessor', 'Branch', 'Router', 'Overrides', 'OverridesHelper', 'AIDescription', 'FlowBase', 'ResourceResponse', 'Flow', 'Error', 'Request', 'JsonPatchOperation', 'JsonPatchRequest', 'CloneRequest', 'CloneResponse', 'ClonePreviewResponse', 'FlowDescendantsResponse', 'FlowErrorsResponse', 'FlowReplaceConnectionRequest', 'FlowRunRequest', 'FlowRunResponse', 'FlowRunsStatsRequest', 'FlowRunsStatsResponse', 'FlowTraceKeyResponse', 'LastExportDateTimeResponse', 'UpdateFlowGroupingRequest', 'FlowStepError', 'FlowStepErrorsResponse', 'FlowStepErrorsAssignRequest', 'FlowStepAffectedErrorsResponse', 'FlowStepErrorsUnassignRequest', 'FlowStepErrorsUnassignResponse', 'FlowStepSignedURLResponse', 'FlowStepResolvedResponse', 'FlowStepResolveRequest', 'FlowStepResolvedDeleteRequest', 'FlowStepRetryRequest', 'JobFileRef', 'JobLogRef', 'JobErrorFileRef', 'Job', 'FlowStepRetryExponentialRequest', 'FlowStepRetryData', 'FlowStepRequestResponse', 'FlowStepRequestsListResponse', 'FlowStepRequestsDeleteRequest', 'FlowStepRequestsDeleteResponse', 'FlowStepTagsRequest', 'FlowStepTagsResponse', 'FlowJobsSearchResponse', 'ExecutionLogEntry', 'ExecutionLogsResponse', 'ExecutionLogMetadataRequest', 'ExecutionLogStep', 'ExecutionLogMetadataResponse', 'ExecutionLogDataRequest', 'ExecutionLogDataResponse', 'FlowJobLogEntry', 'FlowJobLogChildrenResponse', 'ErrorsFilterMetadataResponse', 'PageProcessorsPreviewRequest', 'ExportPreviewResponse', 'DependencyEntry', 'DependencyResponse']
--- Request required= ['name']
--- Flow required= ['_id', 'name', 'disabled', 'logging', 'createdAt', 'lastModified']
Thinking…

Let me look at FlowBase properties to know the flow structure (pageGenerators etc.). Let me dump FlowBase.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('flow.yml'))
s=d['components']['schemas']['FlowBase']
print('FlowBase required=',s.get('required'))
for k,v in s.get('properties',{}).items():
    t=v.get('type') or ('$ref:'+v['$ref'].split('/')[-1] if '$ref' in v else '?')
    desc=(v.get('description') or '')[:80]
    print(' ',k,':',t,'-',desc)
print()
print('PageGenerator required=',d['components']['schemas']['PageGenerator'].get('required'))
for k,v in d['components']['schemas']['PageGenerator'].get('properties',{}).items():
    t=v.get('type') or ('$ref:'+v['$ref'].split('/')[-1] if '$ref' in v else '?')
    print(' ',k,':',t)
PY
FlowBase required= None
FlowBase required= None
  name : string - Display name for the flow.
  description : string - Free-text description of the flow's purpose.
  _integrationId : ['string', 'null'] - Integration this flow belongs to. Omitting it (or sending `null`) on
create no l
  schedule : ['string', 'null'] - Celigo 6-field cron expression: `? minute hour day-of-month month day-of-week`.

  timezone : ['string', 'null'] - IANA timezone for the schedule (e.g. `America/New_York`). Defaults to UTC.
  disabled : boolean - When true, scheduled executions are suspended and the flow cannot be triggered.

  pageGenerators : array - Data sources (exports) that produce pages of records for the flow. Mutually excl
  pageProcessors : array - Sequential processing steps (imports, lookups, routers). Mutually exclusive with
  routers : array - Routers that direct records into branches. Mutually exclusive with top-level
`pa
  _exportId : string - Source export of a simple (single source, single destination) flow — the legacy

  _importId : string - Destination import of a simple (single source, single destination) flow — the le
  _runNextFlowIds : ['array', 'null'] - Flow IDs to start when a run of this flow completes — the flow's "Next integrati
  _runNextExportIds : array - Specific exports in other flows to trigger after completion.
  externalId : ['string', 'null'] - External identifier for correlating the flow with a record in another system.
  wizardState : string - Tracks how far the user has progressed through the flow setup wizard in the UI.
  settings : object - Custom key-value settings for this flow. At runtime the flow's steps read them
u
  runPageGeneratorsInParallel : boolean - When true, all page generators start simultaneously instead of sequentially.
  autoResolveMatchingTraceKeys : boolean - When true, a new error for a record whose trace key already has open errors on t
  isAbstract : boolean - Marks this as an abstract (multi-instance) flow — a reusable template that canno
  _abstractFlowId : string - Abstract flow this instance inherits from. Immutable once set. The instance inhe
  overrides : $ref:Overrides - 
  overridesHelper : $ref:OverridesHelper - 
  _flowGroupingId : ['string', 'null'] - Flow grouping for organizing related flows in the UI. References an entry in the
  _keepDeltaBehindFlowId : string - Coordinates delta timing so this flow's checkpoint stays behind the referenced f
  _keepDeltaBehindExportId : string - Like `_keepDeltaBehindFlowId` but targets a specific export within a flow.
  aiDescription : $ref:AIDescription - 
  aliases : array - Named aliases that map to specific resources within the flow.
  draft : boolean - When true, this flow is a draft that auto-deletes when its expiry passes
(`draft
  preSave : object - Pre-save hook that runs a script before persisting flow changes.
  settingsForm : object - Form definition for collecting flow-level settings from users in the UI.

PageGenerator required= None
  _exportId : string
  schedule : string
  skipRetries : boolean
  setupInProgress : boolean
  _keepDeltaBehindFlowId : string
  _keepDeltaBehindExportId : string
  __startDateHelper : string
cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && echo "=== integrations list query params ===" && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('integration.yml'))
o=d['paths']['/v1/integrations']['get']
for p in o.get('parameters',[]):
    print(p.get('name'),'-',p.get('in'),'-',(p.get('description') or '')[:60])
PY
echo "=== connection http example schema ==="; python3 - <<'PY'
import yaml
d=yaml.safe_load(open('connection.yml'))
s=d['components']['schemas']
print('schemas:', [k for k in s if 'ttp' in k or k in ('Request','HTTP','Http')][:20])
for name in s:
    if name.lower()=='http':
        print('HTTP required=',s[name].get('required'))
        for k,v in s[name].get('properties',{}).items():
            print('  ',k,':',v.get('type') or v.get('$ref'))
PY
=== integrations list query params ===
=== integrations list query params ===
None - None - 
None - None - 
limit - query - Maximum number of integrations to return per page. When more
=== connection http example schema ===
schemas: ['HTTP', 'Request']
HTTP required= ['baseURI', 'mediaType']
   mediaType : string
   successMediaType : string
   errorMediaType : string
   baseURI : string
   disableStrictSSL : boolean
   concurrencyLevel : integer
   targetConcurrencyLevel : integer
   retryHeader : string
   formType : string
   type : string
   clientCertificates : object
   ping : object
   auth : object
   rateLimit : object
   headers : array
   encrypted : ['object', 'string']
   encryptedFields : array
   unencrypted : object
   unencryptedFields : array
   _iClientId : string
   _httpConnectorId : string
   _httpConnectorApiId : string
   _httpConnectorVersionId : string
   isRest : boolean
   useNewAuthFailSchema : boolean
Thinking…

I now have enough to build a correct example. Let me build a self-contained Node script that:

  1. Reads CELIGO_API_TOKEN (required) and CELIGO_BASE_URL (default US).
  2. GET /v1/tokenInfo to confirm identity/region.
  3. Lists integrations (GET /v1/integrations?limit=10).
  4. Creates an integration (POST /v1/integrations with {name}).
  5. Gets it back.
  6. Cleans up by deleting it (with --keep flag to skip).

Also demonstrate building a flow bottom-up? That requires real external connection creds. I could create a minimal HTTP connection to a public API (e.g., https://api.github.com) with no auth, then an export and import... but the import would need a destination. Too much. Keep it to the integration CRUD + mention the CLI flow-building commands.

Actually, a nice "simple example" that's fully self-contained and doesn't need external systems: use the API to create an integration and a flow shell? A flow with no steps may not be valid. Better to keep the CRUD example and add commented guidance.

Alternatively, I can make the example create an integration, then an HTTP connection to a public API with auth: {type: "none"}, ping it, and delete it. That's a genuinely useful end-to-end test that touches the hosted product and doesn't require third-party credentials. Let me check the HTTP auth schema for "none". Let me check the connection HTTP auth object and ping endpoint.

Actually, let me keep the example focused but add a --with-connection option that creates a public HTTP connection and pings it. But I can't test it without a token, so there's risk of schema inaccuracy. I'll keep the example minimal and robust: integration CRUD. I'll include a commented "build a flow bottom-up" section referencing the CLI.

Hmm, but the user asked to "build a simple example." A minimal integration CRUD via REST API is a fine simple example. Let me also provide the equivalent CLI one-liners.

Let me now create the files in /sandbox/repo:

  • celigo-example/celigo.mjs — Node script.
  • celigo-example/README.md — usage, pricing summary, notes.
  • celigo-example/package.json maybe not needed (no deps). Node 22 has fetch. I'll add a package.json with "type":"module" and a script.

Wait — should I put it in /sandbox/repo? The repo is a git workspace. Yes, create the example there. Let me make a clean directory.

Let me verify the delete endpoint and list response shape. Let me check the integration list response schema quickly.

Let me also double check: createIntegration required only name. Good.

Let me write the script carefully. Since I can't run it authenticated, I should at least run it with no token to verify graceful handling and lint/syntax-check it.

Let me also add a --dry-run mode that prints requests without sending. Actually, better: add a CELIGO_DRY_RUN=1 that prints the planned calls. That lets me demonstrate/verify the script runs even without a token.

Let me check the list response and delete status.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('integration.yml'))
o=d['paths']['/v1/integrations']['get']
print("list responses:", list(o['responses'].keys()))
for code,r in o['responses'].items():
    c=r.get('content',{}).get('application/json',{}).get('schema')
    print(code, c)
o2=d['paths']['/v1/integrations/{_id}']['delete']
print("delete responses:", list(o2['responses'].keys()))
o3=d['paths']['/v1/integrations/{_id}']['get']
for code,r in o3['responses'].items():
    print('get',code, r.get('content',{}).get('application/json',{}).get('schema'))
PY
list responses: ['200', '204', '401']
list responses: ['200', '204', '401']
200 {'type': 'array', 'items': {'$ref': '#/components/schemas/Integration'}}
204 None
401 None
delete responses: ['204', '401', '404', '422']
get 200 {'$ref': '#/components/schemas/Integration'}
get 401 None
get 404 None
cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('integration.yml'))
s=d['components']['schemas']
print([k for k in s if 'ntegration' in k or k in ('ResourceResponse','Error','Page')])
# show Integration schema
for n in s:
    if n.lower() in ('integration','request'):
        sch=s[n]
        print('---',n,'required=',sch.get('required'))
        for k,v in list(sch.get('properties',{}).items())[:20]:
            print('  ',k,':',v.get('type') or v.get('$ref'))
PY
['IntegrationBase', 'ResourceResponse', 'Integration', 'Error', 'IntegrationErrorsResponse', 'IntegrationErrorsAssignRequest', 'IntegrationErrorsAssignResponse'
['IntegrationBase', 'ResourceResponse', 'Integration', 'Error', 'IntegrationErrorsResponse', 'IntegrationErrorsAssignRequest', 'IntegrationErrorsAssignResponse']
--- Integration required= ['_id', 'name', 'createdAt', 'lastModified', 'install', 'installSteps', 'uninstallSteps', 'changeEditionSteps', 'flowGroupings', 'apiGroupings', '_registeredConnectionIds']
--- Request required= ['name']
Thinking…

Good. Now let me write the example. I'll create /sandbox/repo/celigo-example/.

The script:

  • Node ESM, no deps.
  • Config: base URL, token from env or --token.
  • Modes: check (tokenInfo + list), demo (create integration, get, delete unless --keep).
  • --dry-run prints requests.
  • Clean error handling, prints HTTP status and JSON.

Let me write it.

I should also include the CLI equivalents in the README.

Let me verify the tokenInfo response shape. Let me check account.yml tokenInfo.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('account.yml'))
o=d['paths']['/v1/tokenInfo']['get']
print('op:',o.get('operationId'))
for code,r in o['responses'].items():
    sch=r.get('content',{}).get('application/json',{}).get('schema')
    print(code,sch)
    if isinstance(sch,dict) and '$ref' in sch:
        name=sch['$ref'].split('/')[-1]
        s=d['components']['schemas'][name]
        print('  required=',s.get('required'))
        for k,v in s.get('properties',{}).items():
            print('   ',k,':',v.get('type'))
PY
op: getTokenInfo
op: getTokenInfo
200 {'$ref': '#/components/schemas/TokenInfo'}
  required= ['_userId', 'token', 'ownerUser']
    _userId : string
    token : object
    ownerUser : object
    byUser : object
    environment : object
401 None
Thinking…

Let me check TokenInfo properties more (environment name, account). Let me dump.

cd /tmp/celigo-ex/node_modules/@celigo/api-specs/dist && python3 - <<'PY'
import yaml
d=yaml.safe_load(open('account.yml'))
s=d['components']['schemas']['TokenInfo']
print(yaml.dump(s, sort_keys=False)[:1500])
PY
type: object
type: object
description: 'Identity envelope for the bearer token on the request: the credential
  kind, the

  account owner, the user acting through it, and the environment it is bound to.

  Read the account id from `ownerUser._id` and the actor from `byUser`; `_userId`
  is

  the user record the token is bound to, which for a token on the production

  environment is the account owner.'
required:
- _userId
- token
- ownerUser
x-celigo-ai-guidance:
- 'Use ownerUser._id as the account id and token.type to tell credential kinds apart.

  byUser is absent on on-premise agent tokens (type agent), so never dereference it

  without checking the type first.'
properties:
  _userId:
    type: string
    format: objectId
    x-celigo-refModel: users
    examples:
    - 5e58483b68b52e5827d56a86
    description: 'User record the token is bound to. For a token on the production
      environment this

      is the account owner, so it matches both `ownerUser._id` and

      `environment._envUserId`.'
  token:
    type: object
    description: The credential that authenticated the request. Never echoes the secret
      value.
    required:
    - type
    properties:
      type:
        type: string
        examples:
        - service
        description: 'Credential kind: `service` for an account API token, `agent`
          for an on-premise

          agent''s access token. Read this field rather than inferring the kind from
          which

          other fields are present.'
    
Thinking…

Now I have enough. Let me write the example files.

Let me create the directory and files.

Now I have what I need. Let me build the example.

File edits

1 file

Completed
Writtenceligo-example/celigo.mjsView changes

/sandbox/repo/celigo-example/celigo.mjs

Written content · previous contents were not recorded

#!/usr/bin/env node
/**
* Minimal Celigo integrator.io example — talks to the HOSTED API only.
* No dependencies; uses the global fetch in Node 22+.
*
* Auth: create a token in integrator.io under Resources > API tokens, then:
* export CELIGO_API_TOKEN="<token>"
* node celigo.mjs check # confirm identity + list integrations
* node celigo.mjs demo # create an integration, read it back, delete it
*
* Region: the default host is the US. For EU/AU/CA set:
* export CELIGO_BASE_URL="https://api.eu.integrator.io"
*
* Safe by default: `demo` deletes what it creates unless you pass --keep.
* `--dry-run` (or CELIGO_DRY_RUN=1) prints the planned calls without sending.
*/
const BASE_URL = (process.env.CELIGO_BASE_URL || "https://api.integrator.io").replace(/\/+$/, "");
const TOKEN = process.env.CELIGO_API_TOKEN || "";
const DRY_RUN = process.env.CELIGO_DRY_RUN === "1" || process.argv.includes("--dry-run");
const KEEP = process.argv.includes("--keep");
const command = process.argv[2] || "check";
function log(msg) {
process.stderr.write(`${msg}\n`);
}
async function call(method, path, body) {
const url = `${BASE_URL}${path}`;
log(`→ ${method} ${url}`);
if (DRY_RUN) {
if (body !== undefined) log(` body: ${JSON.stringify(body)}`);
return { status: 0, data: null, dryRun: true };
}
const res = await fetch(url, {
method,
headers: {
Authorization: `Bearer ${TOKEN}`,
Accept: "application/json",
...(body !== undefined ? { "Content-Type": "application/json" } : {}),
},
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
});
const text = await res.text();
let data = null;
try {
data = text ? JSON.parse(text) : null;
} catch {
data = text;
}
if (!res.ok) {
const err = new Error(`${method} ${path} failed: HTTP ${res.status}`);
err.status = res.status;
err.body = data;
throw err;
}
return { status: res.status, data };
}
async function check() {
const info = await call("GET", "/v1/tokenInfo");
const account = info.data?.ownerUser?._id ?? "unknown";
const kind = info.data?.token?.type ?? "unknown";
log(`authenticated: account=${account} credential=${kind}`);
const list = await call("GET", "/v1/integrations?limit=10");
const rows = Array.isArray(list.data) ? list.data : [];
log(`integrations: ${rows.length}`);
for (const it of rows) log(` - ${it._id} ${it.name}`);
return { account, count: rows.length };
}
async function demo() {
const name = `CLI Example ${new Date().toISOString().replace(/[:.]/g, "-")}`;
const created = await call("POST", "/v1/integrations", { name });
const id = created.data?._id;
log(`created integration ${id} (${name})`);
if (DRY_RUN) {
log("dry run: stopping before read/delete");
return;
}
const fetched = await call("GET", `/v1/integrations/${id}`);
log(`read back: ${fetched.data?.name}`);
if (KEEP) {
log(`--keep set; leaving integration ${id} in place`);
return;
}
await call("DELETE", `/v1/integrations/${id}`);
log(`deleted integration ${id}`);
}
async function main() {
if (DRY_RUN) log("DRY RUN — no requests will be sent");
if (!TOKEN && !DRY_RUN) {
log("error: CELIGO_API_TOKEN is not set.");
log("Create one at integrator.io > Resources > API tokens, then export it.");
process.exit(2);
}
if (command === "check") return check();
if (command === "demo") return demo();
log(`unknown command '${command}'. Use: check | demo [--keep] [--dry-run]`);
process.exit(2);
}
main().catch((err) => {
log(`error: ${err.message}`);
if (err.body) log(`response: ${JSON.stringify(err.body)}`);
process.exit(1);
});

File edits

1 file

Completed
Writtenceligo-example/package.jsonView changes

/sandbox/repo/celigo-example/package.json

Written content · previous contents were not recorded

{
"name": "celigo-example",
"private": true,
"type": "module",
"description": "Minimal Celigo integrator.io REST API example (no dependencies).",
"engines": {
"node": ">=22"
},
"scripts": {
"check": "node celigo.mjs check",
"demo": "node celigo.mjs demo",
"demo:keep": "node celigo.mjs demo --keep",
"dry-run": "node celigo.mjs demo --dry-run"
}
}
Thinking…

Let me verify the script runs (dry-run and no-token handling), and syntax check. Then write the README.

cd /sandbox/repo/celigo-example && node --check celigo.mjs && echo "syntax OK" && echo "=== dry-run ===" && node celigo.mjs demo --dry-run 2>&1 && echo "=== no token ===" && (unset CELIGO_API_TOKEN; node celigo.mjs check 2>&1; echo "exit=$?") && echo "=== live unauth (expect 401 handled) ===" && CELIGO_API_TOKEN=bogus node celigo.mjs check 2>&1; echo "exit=$?"
syntax OK
syntax OK
=== dry-run ===
DRY RUN — no requests will be sent
→ POST https://api.integrator.io/v1/integrations
  body: {"name":"CLI Example 2026-10-20T15-52-42-287Z"}
created integration undefined (CLI Example 2026-10-20T15-52-42-287Z)
dry run: stopping before read/delete
=== no token ===
error: CELIGO_API_TOKEN is not set.
Create one at integrator.io > Resources > API tokens, then export it.
exit=2
=== live unauth (expect 401 handled) ===
→ GET https://api.integrator.io/v1/tokenInfo
error: GET /v1/tokenInfo failed: HTTP 401
response: "Unauthorized"
exit=1
Thinking…

The script works as expected. The live unauth call confirms the hosted API is reachable and the error handling works. Good.

Now let me verify the CLI works and show some commands. Let me run celigo --help and celigo integrations --help to confirm. Also celigo lint offline could be demonstrated. But without a token, CLI auth commands won't work. Let me at least verify celigo --help and celigo config show maybe.

Let me run celigo help.

cd /tmp && celigo --help 2>&1 | head -40; echo "=== integrations help ==="; celigo integrations --help 2>&1 | head -30
Usage: celigo [options] [command]
Usage: celigo [options] [command]

Celigo CLI — manage your integrator.io resources from the terminal.

Options:
  --token <token>                           API bearer token (prefer CELIGO_API_TOKEN env var to avoid exposing in process list).
  --base-url <url>                          API base URL.
  --format <format>                         Output format (json or table). Defaults to config or json.
  --jq <expr>                               Transform JSON output with a jq expression (e.g. --jq '.[] | {id: ._id, name}').
  --verbose                                 Show HTTP requests.
  --profile <name>                          Run against a named config profile (must exist — see 'celigo profile list'). Overrides CELIGO_PROFILE, which in turn overrides the machine-wide active profile.
  -h, --help                                display help for command

Commands:
  config                                    Manage CLI configuration.
  profile                                   Manage named config profiles (multiple accounts/environments).
  login [options]                           Sign in with OAuth (authorization code + PKCE). The session is the profile's one credential (a profile login creates is in full mode), and the profile is bound to the account and environment GET /v1/tokenInfo says it reached. The profile is --profile, else CELIGO_PROFILE, else the one named after that account and environment — <company>-<environment>, e.g. acme-corp-production — which is created if it does not exist; the active profile is not the default.
  logout                                    Revoke the OAuth session for a profile and forget stored tokens. Other CLI sign-ins made from the same browser session can end with it (the platform gives them one grant) and then need celigo login again; logout names the profiles it may have signed out.
  skills                                    Install and update agent skills from the public celigo/ai repository.
  pull [options] [refs...]                  Download the account (or one integration) as a local file tree of per-resource JSON. Incremental: unchanged files are untouched, locally-edited files are never overwritten without --force. Refs (a file path — relative to the tree, or absolute inside it — type:id, or bare id) are only meaningful with --force and reset just those resources.
  diff [options] [refs...]                  Compare the local tree against the LIVE account (fetches fresh; volatile fields ignored). With no refs, diffs every locally-modified resource; refs may be a file path, type:id, or a bare id. For the offline tree-vs-manifest view, use: celigo status.
  status [options]                          Show local changes since the last pull (offline; compares the tree against .celigo/manifest.json). For a comparison against the live account, use: celigo diff.
  push [options] [refs...]                  Push local changes to the live account: PUT modified files, create untracked files that have no _id, and (with --prune) delete resources whose local files were removed. Plan-first: the change set is printed before anything is written; --dry-run stops there. Updates and --prune deletes are rejected when the server copy changed since the last pull (--force-remote overrides). Refused at plan time, with no override: a masked "******" value in a document to be created (any type) or in a connection's or iClient's update, a value that is not a string in a field the platform encrypts, and the responseMapping object wrapper. Refs narrow the target set (a file path, type:id, or bare id). Requires full mode.
  promote [options] [refs...]               Write the local tree into ANOTHER account or environment (--to names its profile): create what the target lacks, update what it holds, with every reference remapped to the target's ids. Connections, iClients, MCP OAuth providers, stacks and agents are never promoted with credentials — they are matched by name, pinned with --map, or created as credential-less shells with --create-connections. Plan-first like push: --dry-run stops after the plan; target copies that changed since the last promote are refused (--force-remote overrides). The map lives in .celigo/targets/<name>.json (commit it). Requires full mode on the TARGET: its profile's stored mode, which CELIGO_MODE in this environment can only tighten (CELIGO_MODE=read or operate refuses the promote before any request). Under profile_pin_policy = strict, a target profile that is not the active profile needs a person at a terminal, who types the profile's name back.
  lint [options] [refs...]                  Validate the local tree against the platform's published API schemas (offline; no token needed). The account outranks the specs: a shape the account already exhibits is a warning, a create introducing a shape nothing on the account backs is an error. Spec-contradicted findings are recorded to .celigo/local/lint-feedback.jsonl (field paths only, never values) for improving the specs. A resource an interrupted pull or push left half-done is one `unfinished` error, not linted. Refs narrow the target set.
  resolve [options] <ref>                   Resolve a ref to the real document file in the local tree and print its path. Refs: a link (.link.json pointer or --symlinks symlink), any tree file path, type:id, a bare id, or (in a neutral tree) an @bindings/ key — resolved to this environment's id via .celigo/bindings.json. A resource an interrupted pull or push left half-done has no one document yet: it is refused, naming both paths and what finishes it. Offline — reads only the tree's .celigo/ state.
  ai-agents                                 Manage AI agents (LLM-powered import steps).
  async-helpers                             Manage async helpers (polling configs for long-running API operations).
  guardrails                                Manage guardrails (PII detection, content moderation, AI safety checks).
  on-premise-agents                         Manage on-premise agents (OPA).
  apis                                      Manage API endpoints (builder and script modes).
  edi-profiles                              Manage EDI document profiles for trading partners.
  environments                              Manage the environments on your account.
  file-definitions                          Manage file format definitions (CSV, EDI, fixed-width, etc.).
  iclients                                  Manage OAuth2 iClients (app registrations for OAuth flows).
  lookup-caches                             Manage lookup caches (in-memory key-value stores for enrichment and deduplication).
  topics                                    Manage Event Streams topics (durable message channels for topic exports).
  tags                                      Manage tags for organizing resources.
  tools                                     Manage tools (reusable building blocks callable from flows, APIs, agents, MCP servers, and other tools).
  mcp-servers                               Manage MCP servers that expose tools and APIs as MCP endpoints.
=== integrations help ===
Usage: celigo integrations [options] [command]

Manage integrations (containers for flows, connections, and resources).

Options:
  -h, --help                                                   display help for command

Commands:
  list [options]                                               List all integrations. Rows are projected to id, name, and the table columns by default; use --fields all for complete documents.
  get <id>                                                     Get an integration by ID.
  create [options]                                             Create an integration from a JSON body (stdin, or --file).
  update [options] <id>                                        Update an integration from a JSON body (stdin, or --file).
  set <id> [assignments...]                                    Set field(s) on an integration.
  Whitelisted fields (apiGroupings, flowGroupings, settings) are applied via an atomic PATCH; other fields go through GET + modify + PUT with the complete document.
  Usage: set <id> key=value [key2=value2 ...]
  Values are auto-parsed: disabled=false → boolean, debugUntil=null → removes field.
  Dot notation supported: http.relativeURI=/api/v2/items
  Array index supported: pageGenerators[0]._exportId=abc123
  Combined: routers[0].branches[1].pageProcessors[0]._importId=xyz
  Load a value from a file: content=file://./hook.js (avoids hand-escaping multi-line content like script source or SQL; ~ and relative paths are supported).
  Example: celigo integrations set <id> apiGroupings=<value>
  delete [options] <id>                                        Delete an integration by ID.
  dependencies|used-by <id>                                    List resources that depend on this integration (GET /v1/integrations/<id>/dependencies).
  Use this to check whether the integration is safe to delete — empty means no dependents.
  audit <id>                                                   Show the audit log (change history) for one integration (GET /v1/integrations/<id>/audit).
  clone [options] <id> <environmentId>                         Clone an integration into a target environment.
  Same-env clone: no stdin needed — the CLI auto-builds a self-map from the source integration's
  registered connections (every cloned resource points at the same connection as the source).
  Cross-env clone: pipe an explicit map via stdin (or --file) so source connections get remapped
  to target-env connections: {"connectionMap":{"sourceConnId":"targetConnId",...}}
cd /tmp && echo "=== tokenInfo via CLI (expect auth error) ===" && CELIGO_API_TOKEN=bogus CELIGO_NO_UPDATE=1 CELIGO_NO_SKILLS_INSTALL=1 celigo --token bogus platform get v1/tokenInfo 2>&1 | head -10; echo "exit=$?"
=== tokenInfo via CLI (expect auth error) ===
=== tokenInfo via CLI (expect auth error) ===
(401): Authentication failed. Check your API token with `celigo config show`.
exit=0
Thinking…

The CLI works and handles auth failure. Note the CLI exit code shows 0 because of the pipe to head (pipefail not set). That's fine.

Now let me write the README with pricing and manageability assessment. Let me be accurate about pricing: no public dollar amounts, quote-based, flat-rate on endpoints and flows, three editions, 30-day free trial.

Let me also add a CLI-based variant of the example in the README.

Let me write the README.

File edits

1 file

Completed
Writtenceligo-example/README.mdView changes

/sandbox/repo/celigo-example/README.md

Written content · previous contents were not recorded

# Celigo integrator.io — minimal example
A tiny, dependency-free example that drives the **hosted** Celigo integrator.io
REST API. Nothing runs locally except this one Node script; there is no server,
no container, no service stack to start.
## Files
- `celigo.mjs` — the example (Node 22+, uses global `fetch`)
- `package.json` — scripts only, no dependencies
## Run it
1. In integrator.io, go to **Resources → API tokens** and create a token.
2. Export it (and pick your region's host if not US):
```bash
export CELIGO_API_TOKEN="<token>"
# EU / AU / CA only:
# export CELIGO_BASE_URL="https://api.eu.integrator.io"
```
3. Confirm identity and list integrations:
```bash
node celigo.mjs check
```
4. Full create → read → delete round trip on an integration:
```bash
node celigo.mjs demo # deletes what it creates
node celigo.mjs demo --keep # leaves the integration in place
```
Preview the requests without sending anything (no token needed):
```bash
node celigo.mjs demo --dry-run
```
The API base URL and endpoints come straight from Celigo's published OpenAPI
specs (`@celigo/api-specs`). All calls use `Authorization: Bearer <token>`.
## Equivalent with the Celigo CLI
The official CLI (`npm install -g @celigo/celigo-cli`) wraps the same API and is
the nicer path once you're doing real work. Same auth:
```bash
export CELIGO_API_TOKEN="<token>"
celigo account snapshot # explore the account
celigo integrations list # list integrations
echo '{"name":"My Example"}' | celigo integrations create
celigo integrations get <id>
celigo integrations delete <id>
```
Building a real flow is bottom-up (connection → export → import → flow), and the
CLI scaffolds it:
```bash
celigo http-connectors match https://api.github.com
celigo connections create --connector github --name "GitHub - Prod"
celigo exports create < export.json
celigo imports create < import.json
celigo flows create < flow.json
celigo flows run <flowId> -y
```
There's also a local-tree workflow (`pull` / `status` / `diff` / `push` / `lint`)
that lets you version integrations in git and validate them offline against the
platform schemas.
## How Celigo pricing works
From Celigo's public pricing page (as of this writing — no dollar amounts are
published):
- **Billed on endpoints and flows**, not per task, transaction, record, data
volume, or vCore. Flat-rate with **no overage fees** — usage is tracked so you
can see its impact on spend.
- **Three platform editions:**
- **Standard** — core integrations; MFA + role-based access, standard SLAs.
- **Professional** — adds API Builder and Lookup Cache, SSO + auditability,
and a sandbox; enhanced SLAs.
- **Enterprise** — unlimited endpoints, maximum performance, full governance
and auditability, best support/SLAs.
- **Celigo AI** (Ora, Agent Builder, MCP Server) is available on every edition.
- **Scaling** is flexible up or down; more endpoints/flows are added by
contacting your Account Manager. **Volume-based pricing is explicitly not
offered.**
- **30-day free trial**, no credit card mentioned.
- Actual prices are **quote-based** — you have to talk to sales for numbers.
## Will this be easy to manage?
Yes — this is one of the more agent-friendly products I've seen.
**What makes it easy**
- A real, documented public API (`https://api.integrator.io/v1/...`) with
published, self-contained OpenAPI 3.2 specs per resource.
- A first-class CLI with JSON output, `--jq`, `--dry-run`, plan-first
`push`/`promote`, and offline `lint` against the same schemas.
- The CLI is explicitly designed for agents: permission modes
(`read`/`operate`/`full`), a managed policy file, profile pinning, and
documented "rules for agents driving the CLI" to prevent writing to the wrong
account.
- Local-tree + git workflow (`pull`/`diff`/`push`/`promote`) makes changes
reviewable and repeatable, sandbox → production.
- Public agent skills repo (`celigo/ai`) and an MCP server.
**Friction / caveats**
- **Auth is the only blocker here.** I have no Celigo account or API token, so I
could not run an authenticated call. I verified the hosted API is reachable
(an unauthenticated `GET /v1/tokenInfo` returns `401`) and that the script and
CLI handle that cleanly. Drop in a token and the example runs.
- Pricing isn't self-serve; endpoint/flow counts and edition choice go through
sales.
- "Endpoints and flows" is a simple metric but you still need to understand your
own usage shape to forecast cost.
- Building a working flow still depends on credentials/access to the systems you
connect (NetSuite, Salesforce, etc.), which no tool can remove.
## Verified in this sandbox
- `GET https://api.integrator.io/v1/tokenInfo` → `401 Unauthorized` (hosted API
reachable; auth enforced)
- `celigo --version` → `2026.10.1`
- `node celigo.mjs demo --dry-run` and the no-token path behave as documented
Thinking…

Let me do a final review of the created files and the repo status. Let me list them. Also maybe run the dry-run once more to confirm. Already did. Let me show the tree.

Let me also double check I haven't left any local service running. No.

Let me give the final response. I should be concise but cover:

  • Yes there's a developer workflow.
  • What I built.
  • Pricing.
  • Manageability.
  • Blocked only on auth.

Let me verify the file listing.

cd /sandbox/repo && find celigo-example -type f | sort && echo "---" && git status --short
celigo-example/README.md
celigo-example/README.md
celigo-example/celigo.mjs
celigo-example/package.json
---
?? celigo-example/

Done. Here's the summary.

Yes — there's a real developer workflow

Celigo (integrator.io) is an iPaaS with a genuine, hosted API and tooling. I did not hit a wall — the only thing I lack is an account token. I stayed light: installed the published packages, verified the hosted endpoint, wrote a script, and ran it in dry-run/no-token modes. No local service stacks were started.

What I built in celigo-example/:

  • celigo.mjs — dependency-free Node 22 script using the hosted REST API
    • check → GET /v1/tokenInfo, list integrations
    • demo → create → read → delete an integration (--keep to preserve)
    • --dry-run prints requests without sending
  • package.json — scripts only, no deps
  • README.md — usage, pricing summary, manageability notes

Run it with export CELIGO_API_TOKEN="..." then node celigo.mjs check. The CLI (@celigo/celigo-cli, installed, v2026.10.1) wraps the same API and adds pull/diff/push/promote/lint, JSON output, --jq, and permission modes.

Verified: GET https://api.integrator.io/v1/tokenInfo returns 401 unauthenticated (hosted API reachable, auth enforced); script handles missing/bad tokens cleanly; celigo --version works.

Pricing

  • Flat-rate, billed on endpoints and flows — not per task/transaction/record/volume. No overage fees; usage is tracked.
  • Three editions: Standard, Professional (adds API Builder, Lookup Cache, sandbox, SSO/audit), Enterprise (unlimited endpoints, max performance/governance/SLAs).
  • Celigo AI (Ora, Agent Builder, MCP Server) is on every edition.
  • Scale up/down; more endpoints/flows via your Account Manager. No volume-based pricing.
  • 30-day free trial.
  • No public dollar amounts — pricing is quote-based. That's the main practical friction: you can't self-serve a price.

Ease of management: high

  • Published per-resource OpenAPI 3.2 specs, a polished CLI, offline linting, git-based local tree, sandbox→prod promote, MCP server, and public agent skills.
  • The CLI is explicitly built for agents: read/operate/full modes, profile pinning, managed policy file, and documented rules to avoid writing to the wrong account.

Blocked on: authentication only. Add a token (Resources → API tokens) and the example runs; I couldn't do an authenticated call myself. Building a real flow also needs credentials for the systems you connect (NetSuite, Salesforce, etc.) — unavoidable, not a tooling gap.

AX Fundamentals

23 checks. Open an area for details.

This check is a quick preview. Test more tasks and models with Gauge Agents.

Test your product with Gauge Agents

AX Check by Gauge