The Supabase connector is the first and primary data source for the xentropy data platform. It ingests tables from your Supabase project's PostgREST API into your tenant's Delta Lake on R2.

#

  • A Supabase project with at least one public table
  • Your Supabase project URL (e.g., https://abc123.supabase.co)
  • A service_role key (bypasses Row Level Security)

Security note: The service_role key is stored in your tenant's encrypted config file on R2. It is used only by the ingestion worker and is never exposed to end users.

#

POST /api/data-platform/connectors
Authorization: Bearer <your-jwt>
X-Tenant-Id: <your-tenant-id>
Content-Type: application/json

{
  "name": "My Supabase Project",
  "type": "supabase",
  "config": {
    "supabase_url": "https://abc123.supabase.co",
    "service_role_key": "eyJhbGciOiJIUzI1NiIs...",
    "sync_interval_seconds": 300
  }
}

#

  1. The connector is registered in your tenant's config file
  2. The ingestion worker picks it up within 30 seconds
  3. Discovery phase: The connector fetches the OpenAPI schema from GET /rest/v1/ to list all exposed public tables
  4. Sync phase: Each table is fetched in 1000-row pages and written as a Delta table

#

The connector automatically excludes internal Supabase tables:

| Pattern | Examples | |---------|----------| | auth.* | auth.users, auth.sessions | | api_keys | Standalone API keys table | | supabase_* | Migration history, internal state | | pgbouncer_* | Connection pooler config |

#

After the first sync completes (typically 1-5 minutes depending on table sizes), check your schema:

GET /api/data-platform/schema
Authorization: Bearer <your-jwt>
X-Tenant-Id: <your-tenant-id>

Response:

{
  "tables": [
    {
      "name": "events",
      "columns": [
        { "name": "id", "type": "int8", "nullable": false },
        { "name": "event_name", "type": "text", "nullable": true }
      ],
      "rowCount": 15000
    },
    {
      "name": "users",
      "columns": [
        { "name": "user_id", "type": "int8", "nullable": false },
        { "name": "name", "type": "text", "nullable": true },
        { "name": "active", "type": "bool", "nullable": true }
      ],
      "rowCount": 342
    }
  ]
}

#

You can connect multiple Supabase projects to the same tenant. Each connector is independent with its own sync schedule. To add another:

POST /api/data-platform/connectors
...same shape with a different supabase_url and service_role_key

#

DELETE /api/data-platform/connectors/{connectorId}
Authorization: Bearer <your-jwt>
X-Tenant-Id: <your-tenant-id>

This removes the connector configuration. The existing Delta tables are not deleted — they remain available for queries until you remove them separately.

#

Connector discovery fails:

  • Verify the Supabase URL is correct (should end in .supabase.co or a custom domain)
  • Confirm the service_role key has not expired or been revoked
  • Check that your Supabase project has at least one public table

Sync completes but 0 rows fetched:

  • The connector may be hitting a 416 (Range Not Satisfiable) response for empty tables — this is normal
  • Verify the tables have data in the Supabase dashboard

Sync times out for large tables:

  • The per-page timeout is 60 seconds. If a single page fetch exceeds this, the sync fails. Very large text or JSONB columns can cause slow responses
  • Increase page_size (default 1000) in the connector config if your rows are small, or decrease it if they contain large payloads