Skip to main content
An integration is a third-party app Erdo can act in on your behalf: a database it queries, a warehouse it builds datasets from, a SaaS API an agent or a script calls. Connecting one is the moment its credentials become available to your organization, and it happens in one of two ways. The thing worth internalizing before you start is what decides which way you get. It is not whether the app is one of Erdo’s own native integrations or one of the thousands fronted by our connector platform. It is simply this: do you already hold the credential?
  • You hold it — a database password, an API key, a service-account JSON. There is nobody to send anywhere, so you pass it and the connection exists when the call returns. This is true for native integrations and for SaaS apps whose auth type is keys.
  • You don’t hold it — the app authorizes with OAuth, which means the provider mints the credential during the authorization. There is nothing you could pass, because it does not exist yet. You get back a connect_url, somebody opens it in a browser, and a status check confirms the result.
That asymmetry is why passing credentials to an OAuth app is rejected with an error rather than accepted. An error naming the reason is the only honest answer: the alternative is a call that appears to succeed while storing nothing. All three surfaces — the CLI, the erdo_connect_integration MCP tool, and POST /v1/integrations-connect — run the same code, so everything below behaves identically whichever one you drive.

Find the app and how it authorizes

Search the catalog before connecting. The result tells you the identifier to pass and the auth type that decides your flow:
The columns are the app identifier, its source (native or pipedream), its auth types, and its display name. Over REST the same catalog is GET /v1/integration-apps?query=postgres. An empty query lists native integrations plus popular connectable apps. When a native integration and a catalog app share an identifier, the native one wins — so the identifier you pass to connect always resolves the same way it did in apps.

Connect with credentials

CLI

-c takes one key=value per credential field and repeats:
The field names are the ones the app declares — api_key for a key-auth app, the connection fields for a database. Get one wrong and the connect call fails rather than half-succeeding; for a catalog app the provider’s own message about the offending field is passed straight back to you.

MCP

erdo_connect_integration takes the same thing as a credentials object:

REST

All three answer with the same shape — app, integration_id, status, and a next_step line saying what is actually known:

Verified, or merely stored

The distinction matters when something later fails, so the two cases say different things. A native credential integration is created, exercised against the provider, and activated in the one call. Credentials that don’t work fail the call, and the half-made integration is removed rather than left behind for you to trip over — so status: "active" means Erdo has talked to the provider with those exact credentials. A keys catalog app is different, and its next_step says so plainly: the credentials are stored and the integration is ready to use; they were not validated against the provider — the first action run is what confirms them. The connector platform saves what it is handed without calling the vendor, so a success here means “stored”, not “correct”. Treat the first action you run as the real test.

Connect an OAuth app

Connect it with no credentials. You get status: "pending" and a URL:
Open the URL, authorize, then check status — that call reconciles the connection server-side, so a headless caller finishes the flow without ever touching a browser SDK. Over REST and MCP, return_url sends the person’s browser back to your own page after they authorize instead of Erdo’s data page — worth setting when you are embedding the connect flow in a product of your own. It must be an absolute http(s) URL with no embedded credentials, and it is ignored by apps that connect in one call.
Passing credentials to an OAuth app is an error, not a no-op. The message explains why the app cannot take them — an OAuth provider mints the credential during the authorization, a no-auth app has none — and points you at the flow that does work.

Check status

Over REST: GET /v1/integrations-connect/{app}. Either way you get the app, a connected boolean, the matching integrations, and an optional note counting connections confirmed by this call. “Not connected” is an ordinary answer, not a failure:
This is worth stating because it used to be a 503. Our connector platform does not materialise a record for an end user until that user’s first connection completes, and asking about a user it has never seen answers not found — which is the same fact as “you have connected nothing”, not an outage. Every status check for every catalog app failed that way for anyone starting from zero, which is exactly when you are most likely to be checking. A real provider failure still surfaces as an error, so the signal you want kept its meaning.

Apollo, end to end

Apollo is the worked example of a key-authenticated integration: you paste a key and it is connected, with no browser step anywhere in the flow.
The key comes from Apollo under Settings → Integrations → API. Erdo stores it encrypted and sends it to Apollo in the X-Api-Key header, never as a URL parameter — a key in a URL ends up in every log line that records one.
Connecting confirms Apollo is reachable; it cannot confirm your key. Apollo’s key-test endpoint answers 200 even to a key that is not a key at all, so verification has nothing to fail on. The first enrich_person call is what names a bad key, and it says so explicitly when Apollo rejects it.

enrich_person

Apollo has one action. It takes an email address and returns what Apollo knows about that person professionally:
Email only, deliberately. Apollo will also match on a name plus a company domain, but that form guesses — it returns whoever fits best, and you cannot tell a confident match from a plausible one. An address is an identity you already hold for anyone who filled in a form, so the answer is either about that person or about nobody. When Apollo has a record:
When it doesn’t, you get found: false and the address, and nothing else. found is the field to branch on. A miss is a successful answer, not an error — Apollo simply has no record of that address. Because a miss returns no other keys, writing the result straight into a dataset cannot quietly produce a row of empty strings that looks like a person nobody knows anything about. Genuine failures — a rejected key, a rate limit, an Apollo outage — come back as errors, never disguised as found: false. Each successful match costs one Apollo credit. Personal email addresses and phone numbers are never requested and never returned: asking for them turns a one-credit lookup into as many as nine and pulls contact details into Erdo that nobody asked for, so the request omits them and the result has no field to carry them.

Calling it unattended

enrich_person reads and changes nothing — not in Apollo, not in Erdo — so it needs no approval, which is what lets an automation running at 3am use it. A scripted automation or an event pipeline step invokes it directly:
The script never holds the Apollo key — it asks for an enrichment and gets a person back, and the credential stays in Erdo’s encrypted storage. Agents reach the same action through run_integration_action.

CLI

The erdo integrations commands in context with the rest of the CLI.

MCP

The integration tools an AI assistant drives, and their REST mirrors.

Automations

Scripted work that calls a connected app on a schedule or a trigger.

Data

Turning a connected database or warehouse into a queryable dataset.