OXYGENOxygen/ Docs
Providers

Custom HTTP integrations

Turn any HTTP API into catalog tools with a JSON manifest.

A custom HTTP integration registers your own HTTP API as provider tools. Each operation you declare becomes a callable tool (custom_http.<slug>.<operation>) usable from tool columns, workflows, and recipes — with auth handled by Oxygen, not your code.

Use it when the recipe-native HTTP tools are not enough: oxygen.http_json_request (GET) and oxygen.http_json_post (POST with JSON body) only reach anonymous public HTTPS endpoints — no credentials, no custom headers. Custom HTTP operations support GET, POST, PUT, PATCH, and DELETE with typed body/query/path fields and stored credentials.

Registering

oxygen custom-integrations apply --manifest ./my-integration.json --json
oxygen custom-integrations list --json

apply requires exactly one of --manifest <path> (a JSON file) or --manifest-json '<json>' (inline). Credentials are not passed here — see Credentials.

Manifest shape

{
  "version": 1,
  "slug": "lead_scorer",
  "name": "Lead Scorer",
  "description": "Score leads via our internal API.",
  "baseUrl": "https://api.example.com/",
  "auth": { "type": "bearer" },
  "operations": [
    {
      "operation": "score_lead",
      "displayName": "Score Lead",
      "method": "POST",
      "path": "/score",
      "summary": "Score a lead by email.",
      "effect": "read",
      "fields": [
        { "key": "email", "type": "string", "required": true, "description": "Lead email.", "location": "body" }
      ]
    }
  ]
}

This mints the tool custom_http.lead_scorer.score_lead.

Top-level fields

FieldRequiredNotes
versionNoDefaults to 1; must be 1 if set.
slugYesIntegration id. Must match ^[a-z][a-z0-9_]{0,62}$.
nameYesDisplay name.
descriptionNoDefaults to a generated description.
baseUrlYesPublic HTTPS URL. Private/internal hosts are rejected.
authNoDefaults to { "type": "none" }. See Auth.
operationsYesNon-empty array. Operation ids must be unique.

Operation fields

FieldRequiredNotes
operationYesOperation id, same slug rules as above.
methodYesGET, POST, PUT, PATCH, or DELETE.
pathYesMust start with /. Appended to baseUrl; supports {param} segments filled by location: "path" fields.
displayNameNoDefaults to a titleized operation id.
summaryNoDefaults to <METHOD> <path>.
effectNoread (default) or write. Writes follow approval rules.
sideEffectClassNoDerived from effect unless set.
fieldsNoTyped inputs — see below. With no fields, a GET forwards the raw input as query params and other methods forward it as the JSON body.
timeoutMsNoDefault 10000, max 30000.
maxResponseBytesNoDefault 1000000, max 5000000.
outputPathNoDot-path to project out of the response.
inputSchema / outputSchemaNoOptional JSON Schemas for the tool descriptor.

Field entries

FieldRequiredNotes
keyYesInput name (slug rules).
typeNostring (default), number, boolean, string[], number[], object, object[], array.
requiredNoDefaults to true.
descriptionNoDefaults to the key.
locationNobody, query, or path. Defaults to query on GET, otherwise body.
wireKeyNoRename the key on the wire.

Auth

auth.typeExtra fieldsSent as
none
bearerAuthorization: Bearer <secret>
api_key_headerheader, prefix?<header>: <prefix><secret>
api_key_queryparam?<param>=<secret>
basicusernameAuthorization: Basic base64(<username>:<secret>)

Credentials

The manifest never contains the secret (apply rejects a secrets field). After apply, attach the token/key from the terminal:

oxygen custom-integrations connect lead_scorer --secrets-file ./.env

--secrets-file reads a .env-style file (a single entry, or one named API_KEY/TOKEN/PASSWORD/SECRET) so the credential stays out of shell history; --api-key <value> passes it inline. The web Connections page (/connections/custom_http) does the same thing. Either way, Oxygen stores the credential encrypted and injects it server-side at call time — recipe and column code never sees it, and it never enters a recipe bundle or run log.

Calling the tools

oxygen tools get custom_http.lead_scorer.score_lead --json
oxygen tools run custom_http.lead_scorer.score_lead --input-json '{"email":"a@b.com"}' --mode dry-run --json

In a recipe, allowlist the tool id and call it with ctx.tools.run("custom_http.lead_scorer.score_lead", { email }, { key }). In a table, bind it as a tool column.

  • Integrations — connection state and auth modes.
  • Recipes — calling custom tools from workflow code.
  • Approvals — write-effect operations and live runs.

On this page