> ## Documentation Index
> Fetch the complete documentation index at: https://getconvoy.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# API-driven onboarding

Convoy is operated through the **HTTP API** and dashboard. There is no single "import tenant" endpoint that creates an entire organisation graph in one request. For large or repeatable setups, use a script or infrastructure-as-code that calls the API in a defined order, driven by the [OpenAPI specification](/api-reference/welcome).

## Suggested provisioning order

1. **Organisation**: Create or select the organisation that owns the work. On self-hosted, `convoy bootstrap` creates a user and a default organisation and can mint a personal API key (see [CLI bootstrap](/cli-file/convoy#bootstrap)).
2. **Project**: Create an **incoming** or **outgoing** project with a personal API key:

```bash theme={null}
curl -X POST "$BASE/api/v1/projects?orgID=$ORG_ID" \
  -H "Authorization: Bearer $PERSONAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "staging",
    "type": "outgoing",
    "config": {
      "signature": {
        "header": "X-Convoy-Signature",
        "versions": [{ "hash": "SHA512", "encoding": "hex" }]
      },
      "strategy": { "type": "linear", "duration": 5, "retry_count": 5 },
      "ratelimit": { "count": 5, "duration": 5 },
      "disable_endpoint": false,
      "search_policy": "720h"
    }
  }'
```

`orgID` is the organisation id from bootstrap (or your existing org). The response includes the project and a one-time project API key. Use that project key for the remaining steps. See [Create a project](/api-reference/projects/create-a-project) and [Organisations and projects](/product-manual/organizations-and-projects) for config field mapping.

3. **Sources** (incoming): Define how events enter Convoy (HTTP, REST API, broker-backed, etc.); see [Sources](/product-manual/sources).
4. **Endpoints** (outgoing): Define destination URLs, timeouts, auth, and optional [verification](/product-manual/endpoint-verification) considerations. For many endpoints at once inside an existing project, use [bulk onboard](#bulk-onboard) after the project exists (and configure sources separately if your topology needs explicit source links).
5. **Subscriptions**: Link sources to endpoints (filters, retry policy, functions); see [Subscriptions](/product-manual/subscriptions).

Re-run or update the same resources idempotently where the API allows; for event ingestion deduplication, see [Idempotency](/product-manual/idempotency).

### Client-side idempotency for endpoints and subscriptions

Idempotency keys apply to event ingestion, not to endpoint or subscription creates. If your job creates both and can fail midway, make creates safe to retry with a deterministic `owner_id` on the endpoint, then `GET /api/v1/projects/{projectID}/endpoints?ownerId=...` before creating. Create the endpoint and subscription only when the list is empty.

## Bulk onboard

`POST /api/v1/projects/{projectID}/onboard` creates endpoints and matching subscriptions in bulk inside a project you already have. It does not replace the full provisioning order above; use it after your project exists.

### Payload formats

Send either JSON or a CSV file (not both in the same request).

**JSON** (`Content-Type: application/json`):

```json theme={null}
{
  "items": [
    { "name": "Acme Production", "url": "https://acme.example.com/webhooks", "event_type": "invoice.paid" },
    { "name": "Acme Staging", "url": "https://staging.acme.example.com/hooks", "auth_username": "convoy", "auth_password": "s3cret" }
  ]
}
```

Each item requires `name` and `url`. Optional fields: `event_type` (defaults to `*`, all events), `auth_username` and `auth_password` (must both be set or both omitted).

**CSV** (`Content-Type: multipart/form-data`, field name `file`, max 10 MB):

```csv theme={null}
name,url,event_type
Acme Production,https://acme.example.com/webhooks,invoice.paid
Acme Staging,https://staging.acme.example.com/hooks,
```

Required columns: `name`, `url`. Optional columns: `event_type`, `auth_username`, `auth_password`.

### Recommended workflow

<Steps>
  <Step title="Dry run">
    Add `?dry_run=true` to validate your payload without creating anything:

    ```bash theme={null}
    curl -X POST "https://{region}.getconvoy.cloud/api/v1/projects/{projectID}/onboard?dry_run=true" \
      -H "Authorization: Bearer $API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"items": [{"name": "Test", "url": "https://example.com/hook"}]}'
    ```

    A **200** response returns validation results:

    ```json theme={null}
    {
      "status": true,
      "message": "Dry run validation complete",
      "data": {
        "total_rows": 1,
        "valid_count": 1,
        "errors": []
      }
    }
    ```

    If there are problems, `errors` lists each one with `row`, `field`, and `message`.
  </Step>

  <Step title="Fix validation errors">
    Correct any rows flagged in the dry-run response and re-run until `errors` is empty.
  </Step>

  <Step title="Submit">
    Remove the `dry_run` parameter and POST the same payload. A **202** confirms the request is accepted:

    ```json theme={null}
    {
      "status": true,
      "message": "Bulk onboard request accepted",
      "data": {
        "batch_count": 1,
        "total_items": 2,
        "message": "Bulk onboard request accepted for processing"
      }
    }
    ```

    Work is processed asynchronously in batches of up to 50 items. If you submit without `dry_run` and there are validation errors, the API returns **400** with the same error shape as the dry run.
  </Step>

  <Step title="Verify">
    Poll the [list endpoints](/api-reference/endpoints/list-all-endpoints) and [list subscriptions](/api-reference/subscriptions/list-all-subscriptions) APIs, or check the dashboard, until the expected resources appear.
  </Step>
</Steps>

For CSV uploads, use `-F` instead of `-d`:

```bash theme={null}
curl -X POST "https://{region}.getconvoy.cloud/api/v1/projects/{projectID}/onboard" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@endpoints.csv"
```

### Limits

| Limit                            | Value |
| -------------------------------- | ----- |
| Maximum items per request        | 1,000 |
| Batch size (items per queue job) | 50    |
| Multipart form size (CSV upload) | 10 MB |

### What gets created

For each valid row the processor creates:

* **Endpoint**: active status, `application/json` content type, auto-generated signing secret.
* **Subscription**: named `{name}-subscription`, type `api`, event type filter set from `event_type` (default `*`). No source is attached; if you need source-to-endpoint wiring for incoming projects, update the subscription via the [subscriptions API](/api-reference/subscriptions/update-a-subscription) after onboard.

If `auth_username` and `auth_password` are both provided, the endpoint is configured with HTTP Basic outbound auth. Basic auth requires a Premium license and the organisation early adopter flag. See [Endpoint authentication](/product-manual/endpoints#basic-authentication-outbound) for details.

### Self-hosted note

The Convoy agent (`convoy agent`) must be running to process onboard batches. If it is not, jobs sit in the queue and endpoints will not appear until the agent starts.

## Export, audit, and backups

* **API listing:** Use list endpoints (projects, endpoints, subscriptions, etc.) to snapshot configuration for audits or drift detection.
* **Self-hosted:** Database backups and restores are your operational responsibility; Convoy stores configuration and state in PostgreSQL.
* **Hosted / Cloud:** Follow your provider's export and support processes for tenant data.

For load and capacity validation after onboarding, see [Architecture](/deployment/architecture), specifically the Benchmarks & Performance section, component sizing, and scaling notes.
