Skip to main content

Supabase ExecModule

Overview

SupabaseModule connects ValkyrAI workflows to the Supabase Data API through the native map I/O ExecModule ABI. Workflow Studio discovers it as SupabaseModule. The project URL and API credential resolve only from a READY IntegrationAccount; workflow input cannot supply either value or redirect the module to another host.

The first release implements the official n8n Supabase node's core row lifecycle and adds bounded schema discovery, provider upsert, and PostgreSQL function execution:

  • get_schema
  • list_rows
  • get_row
  • insert_rows
  • upsert_rows
  • update_rows
  • delete_rows
  • call_rpc

Read operations can retry transient failures. Every mutation runs exactly once so a timeout cannot silently duplicate a row, repeat a function side effect, or delete data twice.

Usage

  1. Create or select a Supabase project and expose only the database schema required by the workflow.
  2. Keep Row Level Security enabled and define policies for the automation identity.
  3. Create a ValkyrAI IntegrationAccount with the exact https://<project-ref>.supabase.co project URL in accountId and the least-privilege Supabase API key in the encrypted apiKey field.
  4. Set the account status to READY and bind it through ExecModuleConfig.authConfig.integrationAccount.
  5. Add SupabaseModule, select an operation, and map table, filter, row, or RPC inputs from workflow state.
  6. Prefer upsert_rows with a durable unique key when a workflow may be resumed after interruption.

Inputs

NameTypeRequirementDefaultDescription and constraints
operationstringRequiredNoneOne of the eight operations above.
schemastringOptionalpublicExposed PostgreSQL schema profile; a simple unquoted identifier.
tablestringRow operationsNoneTable or view; a simple unquoted identifier.
functionstringcall_rpcNonePostgreSQL function exposed through /rpc; a simple unquoted identifier.
selectstringRead operations*PostgREST projection, including bounded relation syntax; maximum 2,048 characters.
filtersarray or JSON stringRequired for get/update/deleteNoneUp to 20 {column, operator, value} objects.
orderstringOptional list_rowsProvider defaultPostgREST order expression such as created_at.desc; maximum 512 characters.
offsetintegerOptional list_rows0Starting range offset, 0–1,000,000.
limitintegerOptional list_rows100Maximum returned rows, 1–10,000.
returnAllbooleanOptional list_rowsfalseFollow range pages until exhaustion; still capped at 10,000 rows.
rowsarray or JSON stringInsert/upsertNone1–1,000 non-empty row objects.
valuesobject or JSON stringupdate_rowsNoneNon-empty changed-column object, no larger than 1 MiB.
onConflictstringupsert_rowsNoneOne through ten comma-separated unique-column names.
argsobject or JSON stringOptional call_rpc{}Named function arguments, no larger than 1 MiB.
confirmDeletebooleandelete_rowsfalseMust be true before a delete request is sent.

Supported filter operators are eq, neq, gt, gte, lt, lte, like, ilike, is, in, cs, cd, ov, fts, plfts, phfts, and wfts. in requires a non-empty array of at most 100 simple scalar values. Update and delete always require at least one structured filter.

Outputs

NameTypeWhen presentDescription
statusstringAlwayssuccess or error.
operationstringAlwaysNormalized operation.
attemptsintegerAlwaysTotal provider attempts across the execution.
httpStatusintegerProvider respondedLast Supabase HTTP status.
dataobjectSchema, single row, or scalar RPC successBounded provider representation.
itemsarrayList or row mutation successBounded rows returned by Supabase.
countintegerList or row mutation successNumber of emitted rows.
hasMorebooleanlist_rowsWhether another range starts at nextOffset.
nextOffsetintegerAnother page existsProvider row offset for a later execution.
requestIdstringProvider supplies oneSupabase correlation ID.
errorobjectFailureSafe {code, message, httpStatus?, retryable} details.

The API key, Authorization header, service-role material, and unbounded provider bodies are never returned.

IntegrationAccount Requirements

SettingRequirement
ProviderSupabase
accountIdExact https://<project-ref>.supabase.co project URL
apiKeyPreferred encrypted SecureField containing an anon/publishable or service-role/secret key
passwordLegacy key fallback only; prefer apiKey
statusMust be READY
AuthorizationSent as both apikey and Authorization: Bearer per the Data API contract

Use an anon or publishable key when Row Level Security policies can grant exactly the required access. A service-role or secret key bypasses RLS and should be reserved for tightly controlled server-side automation with minimum database privileges. Never put either key in workflow payloads, examples, logs, launch content, or error messages.

The custom schema must be exposed in Supabase API settings and allowed by the bound principal. Accept-Profile is used for reads and Content-Profile for writes and RPC calls.

Configuration

{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:supabase-revenue-ops"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 60000,
"jitter": false
},
"executionConfig": {"timeoutMs": 30000},
"payloadConfig": {
"parameters": "{\"operation\":\"list_rows\",\"schema\":\"public\",\"table\":\"leads\",\"select\":\"id,email,stage\",\"limit\":100}"
}
}

The account reference is illustrative. Persisted workflows use the generated IntegrationAccount relationship and SecureFields.

Operations

OperationData API behaviorSide effect
get_schemaReads the bounded PostgREST OpenAPI description for the selected exposed schema.Read-only; safe retries enabled.
list_rowsReads table/view rows with projection, structured filters, order, range, and bounded pagination.Read-only; safe retries enabled.
get_rowReads the first row matching at least one structured filter.Read-only; safe retries enabled.
insert_rowsInserts 1–1,000 rows and requests their representations.Mutation; never retried automatically.
upsert_rowsUses on_conflict plus resolution=merge-duplicates.Provider upsert; never retried automatically after ambiguity.
update_rowsPatches rows matching at least one structured filter and returns them.Mutation; never retried automatically.
delete_rowsPermanently deletes filtered rows and returns their representations.Destructive; requires confirmation; never retried.
call_rpcInvokes an exposed PostgreSQL function with named JSON arguments.Function-defined; never retried automatically.

Errors and Failure Modes

CodeTypical causeRetryableResolution
VALIDATION_ERRORInvalid project URL, key, identifier, filter, payload, or absent delete confirmation.NoCorrect the named value. No unsafe request was made.
UNSUPPORTED_OPERATIONUnknown operation.NoSelect a documented operation.
INTEGRATION_ACCOUNT_REQUIREDNo account is bound.NoBind a Supabase IntegrationAccount.
INTEGRATION_ACCOUNT_NOT_READYAccount status is not READY.NoRepair or reconnect the account.
NOT_FOUNDget_row matched no visible row.NoVerify filters, RLS, schema, and table.
SUPABASE_HTTP_400PostgREST rejected a filter, projection, body, or function signature.NoCorrect the bounded provider error.
SUPABASE_HTTP_401Key is invalid or expired.NoRotate the key in IntegrationAccount.
SUPABASE_HTTP_403RLS, grants, or API exposure denies the action.NoFix the smallest applicable policy or grant. Do not bypass RLS casually.
SUPABASE_HTTP_404Table, schema, function, or visible route is absent.NoVerify exposure and identifiers.
SUPABASE_HTTP_409Unique or concurrency conflict.NoRe-read provider state and reconcile.
SUPABASE_HTTP_429Project rate limit.Yes for reads onlyHonor Retry-After and configured backoff.
SUPABASE_HTTP_5xxTransient Data API failure.Yes for reads onlyRetry reads; reconcile mutations before any resubmission.
NETWORK_ERRORTimeout, DNS, TLS, or connectivity failure.Yes for reads onlyVerify connectivity. Treat a write timeout as ambiguous.
RESPONSE_TOO_LARGEResponse exceeded 10 MiB.NoNarrow the projection/filter or lower the limit.
INVALID_PROVIDER_RESPONSEProvider response shape did not match the selected operation.NoUse the request ID and verify Data API compatibility.

Example

Upsert an agent-qualified lead using the unique email column:

{
"operation": "upsert_rows",
"schema": "public",
"table": "leads",
"onConflict": "email",
"rows": [
{
"email": "buyer@example.com",
"company": "Example Industries",
"stage": "qualified",
"source": "valkyrai-research"
}
]
}

Expected result shape:

{
"status": "success",
"operation": "upsert_rows",
"httpStatus": 200,
"attempts": 1,
"count": 1,
"items": [
{
"id": 42,
"email": "buyer@example.com",
"company": "Example Industries",
"stage": "qualified",
"source": "valkyrai-research"
}
]
}

Notes

  • Pagination uses HTTP Range and Content-Range, requests at most 1,000 rows per page, and never emits more than 10,000 rows per execution. Stable order is strongly recommended for multi-page reads.
  • Only get_schema, list_rows, and get_row retry HTTP 408, 429, and selected 5xx responses. Integer and RFC 1123 Retry-After values are honored before exponential backoff.
  • Insert, upsert, update, delete, and RPC requests run once. After an ambiguous timeout, query provider state using a durable business key before resubmitting.
  • Supabase project quotas, PostgREST maximum-row settings, database statement timeouts, RLS, grants, triggers, and function behavior still apply.
  • upsert_rows is provider-idempotent only when onConflict identifies a real unique constraint and the row values are safe to merge.
  • delete_rows is permanent and requires both at least one structured filter and confirmDelete=true. There is no automatic compensation.
  • call_rpc can be read-only or highly destructive depending on the function. Keep volatile or side-effecting functions narrowly granted and design them to accept caller idempotency keys where practical.
  • Custom Supabase domains, self-hosted Supabase, Storage, Auth, Realtime, Edge Functions, vector-search helpers, CSV transfer, logical OR/NOT filter groups, and bulk inputs above 1,000 rows are deferred.
  • Functional reference: n8n's Supabase node provides row create, delete, get, get-many, and update behavior with schema selection, filters, mapping, ordering, and pagination. ValkyrAI implements those semantics through its own ABI and IntegrationAccount model, then adds explicit upsert, schema, RPC, retry, redaction, and destructive-action controls.