Getting Started with Conduit

Conduit bridges inbound email to HTTP webhooks. When an email arrives at your Conduit address, Conduit immediately delivers it as an HTTP POST to a URL you configure. This guide walks you through creating an account and setting up your first webhook.


1. Create an account

Using the web UI

  1. Open your Conduit instance in a browser and go to /app/signup.
  2. Enter your email address and choose a password of at least 12 characters.
  3. Click Create account.

You are signed in automatically and taken to the dashboard.

Using the API

POST /api/v1/accounts
Content-Type: application/json

{
  "email": "you@example.com",
  "password": "correct-horse-battery-staple"
}

A successful response returns your account details:

{
  "id": "acc_01HX...",
  "email": "you@example.com",
  "created_at": "2024-01-15T10:00:00Z"
}

2. Sign in

Using the web UI

Go to /app/signin, enter your email and password, and click Sign in.

If two-factor authentication is enabled on your account you are prompted for a code from your authenticator app before being taken to the dashboard.

Using the API

Exchange your credentials for a short-lived access token and a refresh token:

POST /api/v1/sessions
Content-Type: application/json

{
  "email": "you@example.com",
  "password": "correct-horse-battery-staple"
}
{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "expires_in": 900
}

The access_token is valid for 15 minutes. Use the refresh_token to obtain a new access token without signing in again:

POST /api/v1/sessions/refresh
Content-Type: application/json

{
  "refresh_token": "eyJ..."
}

Include the access token in the Authorization header for all subsequent requests:

Authorization: Bearer <access_token>

Two-factor authentication (TOTP)

If 2FA is enabled, the sign-in response returns a TOTP challenge rather than tokens:

{
  "totp_required": true,
  "totp_token": "..."
}

Complete the challenge with a code from your authenticator app:

POST /api/v1/sessions/2fa
Content-Type: application/json

{
  "totp_token": "...",
  "code": "123456"
}

3. Create your first webhook

A webhook maps an email address to an HTTP endpoint. When an email arrives at the address, Conduit posts the message to your endpoint.

Public domain vs. custom domain

Conduit has one public domain (by default incoming.conduit.email). Every account can create webhooks on it for free — no verification required. When you use the public domain, the local part (the part before @) is derived automatically from the webhook ID and cannot be changed:

webhook-01HX...@incoming.conduit.email

If you need a memorable address like orders@mail.yourcompany.com, you must first claim and verify your own domain. See Using a Custom Domain for details.

Using the web UI

  1. Go to Webhooks (/app/webhooks) and click + New.
  2. To use the public domain, leave the domain selector set to Public — the address is assigned automatically after you save. To use one of your verified private domains, select Private domain and enter the full email address (e.g. alerts@mail.yourcompany.com).
  3. Enter the target HTTPS URL that should receive the webhook payload.
  4. Click Create webhook.

The webhook detail page shows the generated secret. Copy this secret now — it is not shown again. You need it to verify the signature on your endpoint.

Using the API

Public domain webhook (omit address):

POST /api/v1/webhooks
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "target_url": "https://myapp.example.com/hooks/email"
}

Conduit assigns an address automatically:

{
  "id": "wh_01HX...",
  "address": "webhook-01HX...@incoming.conduit.email",
  "target_url": "https://myapp.example.com/hooks/email",
  "secret": "whsec_...",
  "active": true,
  "rate_limit": 0,
  "created_at": "2024-01-15T10:01:00Z",
  "updated_at": "2024-01-15T10:01:00Z"
}

Private domain webhook (requires a verified domain):

POST /api/v1/webhooks
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "address": "alerts@mail.yourcompany.com",
  "target_url": "https://myapp.example.com/hooks/email"
}

The secret field is only returned at creation time. Copy it now.


4. Verify the signature on your endpoint

Every delivery from Conduit includes an X-Conduit-Signature header containing an HMAC-SHA256 signature of the raw request body, keyed with your webhook secret:

X-Conduit-Signature: sha256=<hex-encoded-digest>

Verify this signature in your endpoint before processing the payload:

import hmac
import hashlib

def verify_signature(body: bytes, secret: str, header: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)

Reject requests where the signature does not match.

If you need to rotate the secret, use the Rotate secret button on the webhook detail page in the UI, or call PUT /api/v1/webhooks/{id} with a new secret value.


5. Send a test email

Point any mail client or mail server at the Conduit SMTP gateway (default port 2525) and send an email to your webhook address. Conduit will forward the message as a JSON POST to your endpoint and return the SMTP response code that reflects the delivery outcome:

Outcome SMTP code Meaning
Success (HTTP 2xx) 250 Message accepted
Transient failure (HTTP 5xx / timeout) 450 MTA will retry
Permanent failure (HTTP 4xx) 550 MTA will bounce

To review delivery attempts, open the webhook detail page in the UI and click Logs, or call GET /api/v1/webhooks/{id}/logs.


Next steps