# Custom Integration

Euno's Custom integration provides the simplest way to ingest data resources directly into your data model. This integration accepts raw observation objects, making it perfect for custom data sources, manual uploads, or integrating systems that don't have dedicated Euno integrations.

### How It Works

The integration follows these steps:

1. **Provides a secure endpoint** Euno generates a unique trigger secret and endpoint URL for receiving custom observations
2. **Accepts Observation Objects** The integration accepts both single observations and arrays of observations via HTTP POST, using only the [supported Custom integration properties](/sources/custom-integrations/custom-integration/custom-integration-properties-reference.md)
3. **Validates and Processes**
   * Validates each observation against supported properties and value types
   * Stores observations directly in your data model
   * Tracks processing statistics and validation errors

## Setting up Euno's Custom Integration

### Step 1: Access the Sources Page

1. Navigate to the **Sources** page in the Euno application
2. Click on the **Add New Source** button
3. Select **Custom** from the available integrations

### Step 2: General Configuration

| Configuration | Description                                                                 |
| ------------- | --------------------------------------------------------------------------- |
| **Name**\*    | Descriptive name for your Custom source (for example, "Manual Data Upload") |

\* Required field.

Custom integration requires no additional configuration fields. It is a push-based integration with no schedule — observations are sent whenever your pipeline or script runs.

### Step 3: Resource Cleanup Options

Configure automatic **resource cleanup** options to manage outdated resources:

* **Immediate Cleanup (default)**: Remove resources not detected in the most recent successful source integration run
* **No Cleanup**: Keep all resources indefinitely, even if they are no longer detected in a run

Time-based cleanup is not available for Custom sources.

### Step 4: Save Configuration

Click **Save**. Euno opens a modal with:

* Your **trigger secret** — copy and store it securely; it is shown only once
* The **`prepare-upload` endpoint URL** — for bulk file uploads (see [Handling High Volume of Observations](/sources/custom-integrations/custom-integration/handling-high-volume-of-observations.md))

Use the trigger secret as a Bearer token in the `Authorization` header for all API calls.

### Step 5: API Endpoints

Custom integration exposes two endpoints. Replace `YOUR_ACCOUNT_ID` and `YOUR_INTEGRATION_ID` with the values from your Euno account.

| Endpoint                                                   | Use for                                                                            |
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `POST .../integrations/YOUR_INTEGRATION_ID/run`            | Inline JSON — single observations or small batches                                 |
| `POST .../integrations/YOUR_INTEGRATION_ID/prepare-upload` | Bulk file upload — request a signed URL for a `.json`, `.jsonl`, or `.ndjson` file |

Both endpoints require `Authorization: Bearer YOUR_TRIGGER_SECRET`.

The `/run` URL is not shown in the Euno UI; construct it from your account ID and integration ID as in the examples below. The `prepare-upload` URL is shown in the post-save modal and in **Reset Trigger Key**.

**Rotating your trigger secret:** Open your Custom source on the **Sources** page and click **Reset Trigger Key** to generate a new secret. This invalidates the previous secret immediately.

## Sending Custom Observations

See [Custom Integration Properties Reference](/sources/custom-integrations/custom-integration/custom-integration-properties-reference.md) for the full list of supported properties and observation format constraints.

### Example: Table with Tags and Metadata

Here's a complete example of a custom observation for a table with tags:

```json
{
  "uri": "custom.analytics.customer_summary",
  "properties": {
    "type": "table",
    "name": "customer_summary",
    "description": "Aggregated customer metrics and analytics",
    "database_technology": "snowflake",
    "tags": ["customer_data", "analytics", "production"],
    "meta": {
      "owner": "data-team",
      "environment": "production",
      "classification": "internal"
    }
  }
}
```

### cURL Command Examples

#### Single Observation Upload

```bash
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TRIGGER_SECRET_HERE" \
  -d '{
    "uri": "custom.sales.monthly_revenue",
    "properties": {
      "type": "table",
      "name": "monthly_revenue",
      "description": "Monthly revenue aggregations by product line",
      "database_technology": "snowflake",
      "tags": ["revenue", "monthly", "sales"],
      "meta": {
        "department": "sales",
        "update_frequency": "monthly"
      }
    }
  }' \
  https://api.app.euno.ai/accounts/YOUR_ACCOUNT_ID/integrations/YOUR_INTEGRATION_ID/run
```

#### Multiple Observations Upload

```bash
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TRIGGER_SECRET_HERE" \
  -d '[
    {
      "uri": "custom.marketing.campaigns",
      "properties": {
        "type": "table",
        "name": "campaigns",
        "tags": ["marketing", "campaigns"]
      }
    },
    {
      "uri": "custom.marketing.campaign_analytics",
      "properties": {
        "type": "view",
        "name": "campaign_analytics",
        "description": "Derived analytics from campaign performance",
        "tags": ["marketing", "analytics", "derived"]
      }
    }
  ]' \
  https://api.app.euno.ai/accounts/YOUR_ACCOUNT_ID/integrations/YOUR_INTEGRATION_ID/run
```

## What Euno Ingests

Custom integration accepts observations for **any resource type** you define in the `type` property. Each observation must include `type` and `name`. See the [properties reference](/sources/custom-integrations/custom-integration/custom-integration-properties-reference.md) for supported metadata and lineage fields.

## Handling High Volume of Observations

The inline `/run` examples above are ideal for small payloads. When you need to upload **many observations in a single run** — especially from a pipeline or a large export — use Euno's **prepare-upload** flow to upload a `.json`, `.jsonl`, or `.ndjson` file directly to cloud storage.

This avoids HTTP request size limits and is the recommended approach for production bulk ingestion.

[→ Handling High Volume of Observations](/sources/custom-integrations/custom-integration/handling-high-volume-of-observations.md)

## Example: Homegrown ELT Pipeline

For a step-by-step example of documenting a Python job that reads from one Snowflake table and writes to another — including which observations to emit and how to wire lineage — see:

[→ Example: Homegrown ELT Pipeline](/sources/custom-integrations/custom-integration/example-homegrown-elt-pipeline.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.euno.ai/sources/custom-integrations/custom-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
