Skip to content

Template Syntax

Inject dynamic values into configurations.

Template Format

Templates use double curly braces: {{source.field}}

Sources

Environment Variables

json
"{{env.VARIABLE_NAME}}"

Example:

json
{
  "jwt": {
    "secret": "{{env.JWT_SECRET}}"
  }
}

Legacy syntax (also supported):

json
"${VARIABLE_NAME}"

Request Body

json
"{{body.fieldName}}"

Example:

json
{
  "data": {
    "title": "{{body.title}}",
    "content": "{{body.content}}"
  }
}

Nested fields:

json
"{{body.user.name}}"
"{{body.items[0].id}}"

URL Parameters

json
"{{params.paramName}}"

For route /users/:id:

json
{
  "filters": [{
    "column": "id",
    "operator": "eq",
    "value": "{{params.id}}"
  }]
}

Query Parameters

json
"{{query.paramName}}"

For /search?q=term&limit=10:

json
{
  "filters": [{
    "column": "name",
    "operator": "ilike",
    "value": "%{{query.q}}%"
  }],
  "limit": "{{query.limit}}"
}

JWT Claims

json
"{{auth.claimName}}"

Available claims:

  • {{auth.sub}} - Subject (user ID)
  • {{auth.role}} - User role
  • {{auth.tenant_id}} - Tenant ID
  • {{auth.email}} - Email (if included)

Example:

json
{
  "data": {
    "user_id": "{{auth.sub}}",
    "created_by": "{{auth.sub}}"
  }
}

Tenant Context

json
"{{tenant.id}}"
"{{tenant.config.field}}"

Secrets

Reference tenant-specific secrets stored securely in the database.

json
"{{secret:API_KEY}}"
"{{secret:STRIPE_SECRET}}"

Legacy syntax (also supported):

json
"{{secret.SECRET_KEY}}"

Setting Secrets

bash
POST /tenant/secrets
Authorization: Bearer <token>

{
  "key": "STRIPE_SECRET",
  "value": "sk_live_...",
  "metadata": { "description": "Stripe API key" }
}

Using in Config

json
{
  "credentials": {
    "stripe": {
      "secretKey": "{{secret:STRIPE_SECRET}}"
    }
  }
}

Secret Rotation

bash
POST /tenant/secrets/rotate
Authorization: Bearer <token>

{
  "key": "API_KEY",
  "newValue": "new-secret-value",
  "gracePeriodDays": 30
}

Old secret remains valid during grace period.

Secret Expiration

json
{
  "key": "TEMP_TOKEN",
  "value": "temporary-value",
  "expiresAt": "2024-12-31T23:59:59Z"
}

Expired secrets return null when accessed.

Step Results (Workflows)

json
"{{steps.stepId.result}}"
"{{steps.stepId.result.field}}"

Input (Workflows)

json
"{{input.fieldName}}"

String Concatenation

Templates can be embedded in strings:

json
{
  "select": "*, users(name)",
  "filters": [{
    "column": "name",
    "operator": "ilike",
    "value": "%{{query.search}}%"
  }]
}

Default Values

Use JavaScript OR syntax:

json
"{{query.limit || 10}}"

Examples

Full Route Example

json
{
  "path": "/posts/:id",
  "method": "put",
  "requireAuth": true,
  "queries": [{
    "table": "posts",
    "operation": "update",
    "data": {
      "title": "{{body.title}}",
      "content": "{{body.content}}",
      "updated_by": "{{auth.sub}}",
      "updated_at": "now()"
    },
    "filters": [
      { "column": "id", "operator": "eq", "value": "{{params.id}}" },
      { "column": "user_id", "operator": "eq", "value": "{{auth.sub}}" }
    ],
    "select": "*",
    "single": true
  }]
}

Integration Example

json
{
  "integrations": [{
    "type": "slack",
    "action": "sendMessage",
    "params": {
      "channel": "{{env.SLACK_CHANNEL}}",
      "text": "New order from {{body.customer_name}}"
    }
  }]
}

Template Reference

TemplateSourceExample
&#123;&#123;env.VAR&#125;&#125;Environment&#123;&#123;env.API_KEY&#125;&#125;
&#123;&#123;body.field&#125;&#125;Request body&#123;&#123;body.name&#125;&#125;
&#123;&#123;params.param&#125;&#125;URL param&#123;&#123;params.id&#125;&#125;
&#123;&#123;query.param&#125;&#125;Query string&#123;&#123;query.search&#125;&#125;
&#123;&#123;auth.claim&#125;&#125;JWT claim&#123;&#123;auth.sub&#125;&#125;
&#123;&#123;tenant.id&#125;&#125;Tenant ID&#123;&#123;tenant.id&#125;&#125;
&#123;&#123;secret.key&#125;&#125;Tenant secret&#123;&#123;secret.API_KEY&#125;&#125;
&#123;&#123;steps.id.result&#125;&#125;Workflow step&#123;&#123;steps.fetch.result&#125;&#125;
&#123;&#123;input.field&#125;&#125;Workflow input&#123;&#123;input.ticketId&#125;&#125;

Backflow - Configuration-driven API framework