External Sources

Collections can be configured to proxy any REST API. Agents use the same manage_document and sql_query tools — they don't know whether data lives in Rekor or an external system.

How It Works

Add a sources config to any collection. Each source defines API endpoints, authentication, and field mapping. When a document operation includes an external_source that matches a configured source, Rekor proxies the operation to the external API.

rekor collections upsert invoices \
  --name "Invoices" \
  --schema '{"type":"object","properties":{"amount":{"type":"number"},"status":{"type":"string"}}}' \
  --sources '[{
    "name": "stripe",
    "auth": {
      "header": "Authorization",
      "value_template": "Bearer {{secret}}",
      "secret": "sk_live_..."
    },
    "field_mapping": {
      "to_external": {
        "amount": "amount_due",
        "status": "invoice_status"
      }
    },
    "get": { "url": "https://api.stripe.com/v1/invoices/{{external_id}}", "method": "GET", "response_path": "data" },
    "list": { "url": "https://api.stripe.com/v1/invoices", "method": "GET", "response_path": "data", "total_path": "total_count" },
    "create": { "url": "https://api.stripe.com/v1/invoices", "method": "POST" },
    "update": { "url": "https://api.stripe.com/v1/invoices/{{external_id}}", "method": "POST" }
  }]'

Agent Experience

The agent uses the exact same tools for proxied and native documents:

# Proxied to Stripe API
manage_document(upsert, collection: "invoices", external_id: "inv_123", external_source: "stripe", data: {amount: 5000})

# Stored in Rekor
manage_document(upsert, collection: "notes", data: {title: "Follow up"})

Field Mapping DSL

Map between Rekor's canonical schema and external API formats. Supports simple renames and rich transformations.

Simple Rename

{ "status": "invoice_status" }

Nested Path

{ "customer_name": { "path": "account.contact.full_name" } }

Enum Mapping

{ "status": { "path": "state", "values": { "active": "ACTIVE", "draft": "DRAFT" } } }

Type Transform

{ "amount": { "path": "total", "transform": "to_number" } }

Available transforms: lowercase, uppercase, trim, to_string, to_number, to_boolean, iso_date

Default Values

{ "currency": { "path": "currency", "default": "usd" } }

Array Access

{ "first_item": { "path": "items[0].name", "array_mode": "first" } }

Array modes: first, last, flatten

Modes

ModeReadsWritesSource of Truth
NativeRekorRekorRekor (default)
ProxyExternal APIExternal APIExternal system
Sync In (planned)RekorExternal APIExternal system
Native + Sync Out (planned)RekorRekor → ExternalRekor

Multiple Sources

A single collection can have multiple external sources. The external_source field on each document determines which backend handles it. Documents without an external_source use Rekor's native storage.

Deterministic IDs

Proxied documents get stable Rekor IDs derived from (collection, external_source, external_id). This means proxied documents can participate in relationships — linking a Stripe invoice to an internal project works seamlessly.

Security

Source secrets are encrypted at rest and never returned in API responses. They are decrypted only at request time to authenticate with the external API.

External Sources — Rekor