# Credentials and connections

> Choose the right machine identity or connector, reuse credentials safely, and describe external operations with API Specs.

Use a **service account** when software calls into Hodoflow. Use an **outbound
connector** when a workflow calls an external service, and an **inbound
connector** when an external system or Kafka source sends data into Hodoflow.
An **API Spec** describes the operations an API exposes; it never stores
credentials by itself.

A connector is one integration with one outside service, stored once and reused
by every workflow that needs it. Credentials live on the connector rather than
inside a step's configuration, so rotating a password is one edit instead of a
hunt through your workflows.

**Connectors** in the sidebar opens a health overview: two cards, **Outbound**
and **Inbound**, each with a breakdown of how many of your connectors are
**Verified**, **Failing**, or **Unverified**. Clicking a slice drills into that
subset.

## Outbound and inbound

The direction is about who initiates the call.

- **Outbound** — *Your org → External Services*. Hodoflow calls out, and the
  connector holds the credentials it presents. This is what workflow steps point
  at.
- **Inbound** — *External Services → Your org*. An outside service sends data in,
  and the connector holds the key it must present. Kafka triggers use one, and
  webhook triggers can optionally use one to verify signatures.

**New Connector** asks you to pick the direction first, then the type.

## Connector types

Four types, chosen with the **Integration Type** picker:

| Type | Configuration it holds |
|---|---|
| **HTTP API** | **Base URL** and an authentication method |
| **Amazon S3** | **Bucket Name**, **AWS Region**, an optional **Custom Endpoint URL** for S3-compatible stores such as MinIO, Cloudflare R2, or DigitalOcean Spaces, plus **Access Key ID** and **Secret Access Key** |
| **Kafka** | **Brokers**, **Topic**, **Consumer Group**, **Security Protocol**, SASL credentials where the protocol needs them, and **Auto Offset Reset** |
| **Snowflake** | **Account Identifier**, **Warehouse**, **Database**, optional **Schema** and **Role**, plus **Username** and a **Private Key (PEM)** |

HTTP connectors take one of four **Authentication Type** values: **None**,
**Bearer Token** with an **API Token**, **API Key** with a **Header Name** and
the key itself, or **OAuth 2.0** with a **Client ID** and **Client Secret** and
optional **Advanced token URLs**.

The Snowflake private key field takes a pasted PEM or an **Upload .pem** button.
The file is capped at 16 KB and parsed in the browser — the file itself is never
uploaded, only the key text you can see in the box.

## How credentials are stored

Every secret a connector holds — API tokens, access keys, OAuth secrets, SASL
passwords, private keys — is encrypted at rest and is never sent back to your
browser.

That has one consequence worth expecting. When you edit a connector, its secret
fields are empty with the placeholder *Leave blank to keep current value*.
Leaving them blank keeps what is stored; typing something replaces it. There is
no way to read a stored secret back out of Hodoflow.

## Inbound API keys

An inbound connector using **API Key** authentication has its key generated for
you. Right after creation a banner appears — **Save this API key now** — with a
**Copy** button, and afterwards the key stays available on the connector's page
under **Your Inbound API Key**, again with **Copy**. Send it in the
`Authorization` header on requests into Hodoflow.

## Test connection and health

Outbound connectors have a **Test connection** button on their page, and
**Test Connection** on the new and edit forms. Inbound connectors have neither —
there is nothing for Hodoflow to dial.

A test returns a **Verified** or **Failing** badge with a message, plus
**Last tested**, **Latency**, and the **HTTP** status where one applies. Failure
detail is specific rather than generic: *no base URL configured*, *bucket 'x' not
found*, *Access denied. Check credentials.*, *HTTP 401. Authentication
rejected.*, *no brokers configured*, or *missing required Snowflake fields*.
Snowflake is the one type that must be saved before it can be tested, and says
so: *save the connector first, then run Test Connection*.

Testing a saved connector updates its status, so the result shows up on the list
and the health cards.

Inbound connectors get their status a different way. Repeated authentication
failures from an outside caller flip a connector to **Failing** — five failures
inside a minute — and one success flips it back to **Verified**. The overview
page updates as that happens, without a refresh.

**Unverified** simply means the connector has never been tested and has not
failed. It is the state everything starts in.

## Finding out what depends on a connector

Each connector's page has a **Usage** link listing the workflow versions that
reference it, with **Open builder** on each row. Deleting is refused while
anything still points at it, and offers **View usage** so you can go reassign
those steps first.

## Imported API Specs

**Connectors → API Specs** holds OpenAPI and Swagger documents you have
imported. Each one turns into a list of operations that a workflow's
**API Request** step can bind to, which is how you call a documented API without
hand-writing URLs, parameter names, and header lists.

**Import Spec** takes a `.json`, `.yaml`, or `.yml` file up to 5 MB, by drop or
by browse. It parses immediately and shows you what it found — the spec's title,
version, and every operation with its method, path, and summary — before you
save.

Give it a **Name**, and optionally a **Connector**. The connector is what
supplies the base URL and the authentication used when a bound operation
actually runs, so an HTTP connector pointing at the same API is usually what you
want here.

### Using a spec in a workflow

Add an **API Request** step in the builder. Its inspector asks for an
**API Spec**, then an **Operation** — listed as method and path, with the
operation's summary beneath. Choosing one populates typed
**Path parameters**, **Query parameters**, and **Header parameters** sections,
each field marked required or optional and labelled with its type, plus a
**Request body** box that accepts `{{field}}` template variables from upstream
steps.

There is no URL or method to edit. Both come from the operation, and the
**Output schema** section shows the fields the operation's documented response
will make available to the steps below.

### Replacing a spec

**Re-upload** on a spec's page compares the new document against the old one
before committing anything. **Review spec changes** counts what was added,
changed, removed, and left alone, and names how many workflow steps across how
many workflows are affected. **Continue & overwrite** applies it; bound
workflows then show as stale until their sources are resampled.

Deleting a spec is refused while workflow steps are still bound to it.

## Related

- [Triggers and webhooks](/help/workflows/triggers-and-webhooks) — inbound
  connectors behind Kafka and webhook triggers.
- [Service accounts](/help/credentials-connections/service-accounts) — credentials for callers
  coming *into* your organization, which are a different thing from connectors.
- [Workflows](/help/workflows) — the steps that use outbound connectors.
