Skip to main content

Integration Hierarchy

ORQO integrations are built from four primitives that stack on top of each other. Understanding this hierarchy is essential for deciding what to build.

App (optional)
└── Skills (one App can host many Skills sharing one OAuth)
├── Tool (what agents can do — Python tool definitions)
└── Credential (how tools authenticate)

Tools are the atomic unit — a single capability like send_email or gmail_search. Credentials store encrypted API keys and secrets. Skills bundle tools + credentials + knowledge into a package assignable to agents. Apps are thin HTTP shells that add channel logic — webhook receipt, inbound parsing, outbound delivery, platform formatting — and (when OAuth is involved) anchor the OAuth flow ORQO drives. One App can host many Skills: a single Google App, for example, can host Drive, Calendar, and Gmail Skills sharing one OAuth credential.

Not every integration needs all four layers. The key question is: does your integration need to receive webhooks or deliver messages on a channel?

The Two Real Examples

This guide uses two integrations built into ORQO to illustrate the hierarchy:

Send MailReceive SendGrid Emails
What it doesAgents send emails via SMTPInbound emails create conversations
TypeSkill onlyApp + Skill
Whysend_email is a built-in engine tool. Just wire a credential.Needs webhook endpoint, signature verification, protocol translation.
Toolsend_email (built-in)None (inbound-only, no agent tools)
CredentialEMAIL_SMTP (host, port, username, password)SENDGRID_WEBHOOK_SECRET + EMAIL_SMTP
AdapterNoneYes
CapabilitiesN/A (skills don't have capabilities)["send", "receive"]

Layer 1: Tools

Tools are the atomic capabilities agents can use. They come from three sources:

SourceExampleHow implemented
Standard Tool Librarysend_email, web_search, read_file, store_knowledge, query_knowledge_graphEngine-native tools, browsable in the Developer Portal's Tool Library
Python tools on a Skillgmail_search, send_slack_message, bannerbear_create_imagePython source compiled by the engine's DynamicToolFactory at runtime. Authored via the Developer Portal (or by IntegrationBuilder's Tool Coder). Bundled into a Skill.
External MCP serversAnything from a third-party MCP server you connectTools discovered from the server's own /mcp endpoint when you register it as a standalone MCP server

Send Mail uses send_email — a built-in engine tool. No adapter or MCP server needed.

Receive SendGrid Emails has no agent-facing tools. Its Skill is empty; the adapter's value is in the inbound webhook pipeline, not in tool execution.

Layer 2: Credentials

Credentials store encrypted secrets that tools need to authenticate. Each credential has a type that defines its field schema:

TypeFieldsUsed by
api_keytokenSlack, GitHub, SendGrid webhook secret
textCustom fieldsSMTP (host, port, username, password, encryption)
oauth2client_id, client_secret, access_token, refresh_tokenGoogle Drive, Gmail, Reddit

Credentials can be shared between multiple Apps and Skills. For example, Google Drive, Gmail, and Google Calendar all share a single GOOGLE_OAUTH2 credential. See Shared Credentials for details.

Credential Mapping

Each credential in the manifest declares a maps_to field that tells ORQO the field name your adapter expects:

{
"credentials": [
{ "key": "MY_SERVICE_TOKEN", "type": "api_key", "label": "API Key", "maps_to": "token" }
]
}

For multi-field credentials (like SMTP with host/port/username/password), all fields are passed in the request body on adapter calls (/verify-webhook, /deliver, /sources/*):

{ "host": "smtp.gmail.com", "port": "587", "username": "bot@example.com", "password": "..." }

Python tools on a Skill receive the same credential record — they read whichever fields they need (e.g. access_token) when invoked by an agent.

Layer 3: Skills

A Skill bundles tools + credentials + knowledge into a unit assignable to agents. The knowledge field is injected into the agent's context, telling it what tools are available and how to use them.

Send Mail — A Minimal Skill

In the manifest, this skill looks like:

{
"schema_version": "1.0",
"name": "Send Mail",
"description": "Send emails to recipients via SMTP, AWS SES, or SendGrid.",
"icon": "envelope",
"category": "communication",

"credentials": [
{
"key": "EMAIL_SMTP",
"type": "text",
"label": "SMTP Server",
"maps_to": "smtp_config"
}
],

"skill": {
"name": "Send Mail",
"knowledge": "You can send emails. Write clear subject lines. Keep messages concise and professional.",
"tool_names": ["send_email"]
},

"setup_instructions": [
"Add your SMTP server details (host, port, username, password)",
"Assign the credential to this skill",
"Assign the skill to your agents"
]
}

This is the simplest possible integration: one built-in tool, one credential, a few lines of knowledge. No adapter, no MCP server, no OAuth.

MCP Servers Auto-Create Skills

When you connect a standalone MCP server, ORQO automatically creates a linked Skill that bundles the server's discovered tools. You don't need to write a manifest or submit to the Developer Portal — the MCP server connection is enough. The auto-created Skill appears in the Team Builder for drag-and-drop assignment, just like any other Skill.

This means the hierarchy for standalone MCP servers is:

MCP Server (connect + verify)
└── Skill (auto-created, tools synced from server)
└── Credential (mirrored from server)

When a Skill is Enough

A standalone Skill (no App) is the right shape when:

  • The tools are built-in engine tools (e.g. send_email, web_search)
  • The tools are Python tools that call a vendor REST API (e.g. Bannerbear's image-generation API)
  • Authentication is a simple API key, OAuth-via-developer-account, or SMTP credential
  • There are no webhooks to receive and no platform messages to deliver

Pure-API integrations like Bannerbear are Skills with Python tools and no adapter at all — there's nothing for an HTTP shell to do.

If the tools come from an external MCP server you connect, you don't need to write a manifest at all — registering the server auto-creates a Skill bundling its discovered tools.

Layer 4: Apps

An App adds a thin HTTP adapter service that handles channel logic only. You need an App when the integration requires:

  • Webhook handling — receiving events from external services
  • OAuth anchoring — declaring oauth_config so ORQO can drive the OAuth flow on the App's behalf (the adapter itself never sees the OAuth code; ORQO owns initial exchange and refresh)
  • Inbound parsing & outbound delivery — converting webhooks to ORQO's normalized message shape, sending platform messages back out
  • Document-source sync — exposing optional /sources/list-changes + /sources/fetch-file so ORQO can ingest files from the platform

If you only need to call a vendor API in response to agent decisions (no webhooks, no message delivery, no document sync), build a Skill with Python tools instead — there's nothing for an adapter to do.

Multi-Skill Apps

One App can host multiple Skills that share its OAuth credential. The canonical example is Google: a single Google App anchors one OAuth flow, and Drive, Calendar, and Gmail each appear as separate Skills hanging off it. This keeps users from re-authenticating per product area and lets agents be granted just the surface they need ("Drive read-only", not "all of Google").

Receive SendGrid Emails — A Channel App

{
"schema_version": "1.0",
"name": "Receive SendGrid Emails",
"description": "Receive inbound emails via SendGrid webhook.",
"icon": "envelope-open",
"category": "communication",
"capabilities": ["send", "receive"],

"credentials": [
{
"key": "SENDGRID_WEBHOOK_SECRET",
"type": "api_key",
"label": "SendGrid Webhook Secret",
"maps_to": "signing_secret"
},
{
"key": "EMAIL_SMTP",
"type": "text",
"label": "SMTP Server (for replies)",
"maps_to": "smtp_config"
}
],

"skill": {
"name": "Receive SendGrid Emails",
"knowledge": "You receive and respond to inbound emails via SendGrid. Replies are sent automatically through the email channel."
}
}

The adapter implements these endpoints:

EndpointPurpose
GET /healthHealth check
GET /manifest.jsonServe the manifest
POST /verify-webhookVerify SendGrid ECDSA signature on inbound webhooks
POST /parse-inboundNormalize email → { sender, message, thread_id, is_dm, dedup_key }
POST /deliverSend reply via SMTP mail relay
POST /formatConvert markdown to plain text for email

The Inbound Flow

1. Someone sends an email to your configured domain
2. SendGrid Inbound Parse POSTs the email to ORQO's webhook endpoint
3. ORQO calls adapter /verify-webhook (signature check)
4. ORQO calls adapter /parse-inbound (normalize)
5. Contact resolution (find the sender in your contacts)
6. Doorkeeper agent processes the message
7. Auto-reply sent via adapter /deliver → SMTP relay → email

Design Principle: One App Per Provider

Each external provider gets its own App. The App name carries the direction:

NameProviderDirection
Receive SendGrid EmailsSendGridInbound
Send MailSMTP (any)Outbound
GmailGoogleBidirectional (API)
SlackSlackBidirectional (channel)

If you later need Mailgun inbound, create a separate Receive Mailgun Emails App with its own adapter. Don't add provider auto-detection to an existing adapter.

Putting It Together

Here's how the layers compose for different integration patterns:

Pattern: ToolFactory Tool Only (Bannerbear)

Agent
└── Tool: bannerbear_create_image (ToolFactory)

The simplest integration: a ToolFactory tool assigned directly to the agent. No credential, no skill, no adapter. The engine compiles the Python source at runtime and the agent calls it like any other tool.

Pattern: Skill Only (Send Mail)

Agent
└── Skill: Send Mail
├── Tool: send_email (built-in)
└── Credential: EMAIL_SMTP

Agent calls send_email → engine resolves SMTP credential → engine sends email via mail relay. No adapter involved.

Pattern: App + Skill (Receive SendGrid Emails)

Agent
└── Skill: Receive SendGrid Emails (auto-created by App)
└── Credential: EMAIL_SMTP + SENDGRID_WEBHOOK_SECRET

App: Receive SendGrid Emails
├── Adapter: HTTP service handling webhooks
├── Webhook: ORQO's webhook endpoint
└── Contact Channels: email addresses of contacts

Inbound: external email → webhook → adapter → conversation. Outbound reply: adapter → SMTP relay → email.

Pattern: App + Skill with Tools (Slack)

Agent
└── Skill: Slack
├── Tools: send_slack_message, list_slack_channels (Python tools)
└── Credential: SLACK_BOT_TOKEN

App: Slack
├── Adapter: thin HTTP shell — webhook verify, parse-inbound, deliver, format
├── Webhook: ORQO's webhook endpoint
└── Contact Channels: Slack user IDs

This is the fullest pattern: the adapter handles inbound webhooks and outbound delivery; the Skill's Python tools let agents proactively call the Slack API. Both share the SLACK_BOT_TOKEN credential.

Pattern: Multi-Skill App (Google)

Agent
├── Skill: Google Drive ─┐
├── Skill: Google Calendar ─┤ Python tools, all sharing
└── Skill: Gmail ─┘ one GOOGLE_OAUTH2 credential

App: Google
├── Adapter: thin HTTP shell — webhook verify, parse-inbound, deliver, format,
│ optional /sources/* for Drive/Gmail document sync
└── OAuth: one consent flow, one refresh schedule

A single OAuth flow anchors three Skills. Agents can be assigned just Drive, just Gmail, or any combination — without forking the integration or asking the user to authenticate three times.

Next Steps