TrigRun
Guides

Request Templates and Response Matching

Use dynamic execution variables in outbound requests and classify success from response body content.

TrigRun supports two advanced request features for scheduled jobs:

  • dynamic variables that render at execution time
  • response body matching that can fail a request even when the HTTP status is 200

It also supports:

  • structured response assertions against JSON fields, headers, body text, and status codes
  • response output mapping so transformed fields can be forwarded in downstream callbacks as output

These features are useful when the target API expects per-request metadata or when application-level success is encoded in the response body instead of the status code.

Supported dynamic variables

TrigRun currently supports three execution-scoped variables:

VariableExample rendered valueBest for
{{timestamp}}2026-03-16T12:34:56.000Zaudit timestamps, signed payloads, freshness markers
{{uuid}}123e4567-e89b-42d3-a456-426614174000request IDs, idempotency keys, correlation IDs
{{execution_id}}cm9x8abc123tracing a TrigRun execution through your downstream system

Where variables can be used

You can use variables in:

  • request.url
  • request header values
  • plain string request bodies
  • string fields inside JSON request bodies

You cannot use variables in:

  • header names
  • JSON object keys
  • secret://name references

How rendering works

  • Variables are rendered once when the execution starts.
  • The same rendered values are reused across retries of that execution.
  • {{uuid}} does not change between retries.
  • TrigRun still injects X-Cron-Service-Execution-Id automatically on every outbound request.

URL examples

Timestamp in a query string

{
  "request": {
    "url": "https://api.example.com/sync?triggered_at={{timestamp}}",
    "method": "POST"
  }
}

Stable request ID per execution

{
  "request": {
    "url": "https://api.example.com/jobs/run?request_id={{uuid}}&execution={{execution_id}}",
    "method": "POST"
  }
}

Header examples

Correlation IDs

{
  "request": {
    "headers": {
      "X-Request-Id": "{{uuid}}",
      "X-Execution-Id": "{{execution_id}}",
      "X-Sent-At": "{{timestamp}}"
    }
  }
}

Combining variables with secrets

{
  "request": {
    "headers": {
      "Authorization": "secret://partner-token",
      "Idempotency-Key": "{{uuid}}"
    }
  }
}

The secret reference is resolved as-is. Variables are not allowed inside secret://... values.

Body examples

Plain string body

{
  "request": {
    "body": "Triggered by execution {{execution_id}} at {{timestamp}}"
  }
}

JSON body

{
  "request": {
    "body": {
      "meta": {
        "request_id": "{{uuid}}",
        "execution_id": "{{execution_id}}",
        "sent_at": "{{timestamp}}"
      },
      "run_type": "scheduled"
    }
  }
}

Response body matching

By default, TrigRun decides success from success_statuses only.

You can make success stricter with response_matcher:

{
  "request": {
    "url": "https://api.example.com/run",
    "method": "POST",
    "success_statuses": [200],
    "response_matcher": {
      "success_pattern": "\"status\"\\s*:\\s*\"ok\"",
      "failure_pattern": "\"status\"\\s*:\\s*\"failed\"",
      "flags": "i"
    }
  }
}

Matching rules

TrigRun evaluates a completed HTTP response in this order:

  1. worker errors such as timeouts or network failures fail the attempt
  2. if failure_pattern matches, the attempt fails
  3. if the status code is not in success_statuses, the attempt fails
  4. if success_pattern is configured and does not match, the attempt fails
  5. otherwise, the attempt succeeds

Important behavior:

  • failure_pattern wins over success_pattern
  • response body matching never converts a failed status code into success
  • a 200 response that fails body matching is treated as failed and does not create a new retry path

Structured response assertions

If you want more reliable validation than raw regex, use response_assertions.

Example: require status = ok and fail when error_code exists.

{
  "request": {
    "response_assertions": {
      "success": {
        "match": "all",
        "rules": [
          {
            "source": "json_body",
            "path": "status",
            "operator": "equals",
            "value": "ok"
          }
        ]
      },
      "failure": {
        "match": "any",
        "rules": [
          {
            "source": "json_body",
            "path": "error_code",
            "operator": "exists"
          },
          {
            "source": "body_text",
            "operator": "contains",
            "value": "quota exceeded"
          }
        ]
      }
    }
  }
}

Supported assertion sources:

  • json_body
  • body_text
  • status_code
  • header

Supported operators:

  • equals
  • not_equals
  • contains
  • not_contains
  • exists
  • not_exists
  • matches_regex

Response output mapping

Use response_output_template to transform the final response into a compact object for downstream systems.

TrigRun stores this mapped object on the execution as final_output and includes it as output in success and failure callbacks.

{
  "request": {
    "response_output_template": {
      "external_id": "{{response.body.data.id}}",
      "status": "{{response.body.status}}",
      "http_status": "{{response.status_code}}",
      "execution_id": "{{execution.id}}",
      "job_name": "{{job.name}}"
    }
  }
}

Useful mapping placeholders:

  • {{response.status_code}}
  • {{response.body.status}}
  • {{response.body.data.id}}
  • {{response.body_text}}
  • {{execution.id}}
  • {{execution.status}}
  • {{job.id}}
  • {{job.name}}
  • {{timestamp}}

Common use cases

APIs that always return 200

Some APIs always respond with 200 and put the real outcome in JSON:

{
  "status": "failed",
  "message": "quota exceeded"
}

Use a failure pattern so TrigRun records this as a failed execution instead of a success.

Require an explicit success marker

If the target returns 200 for accepted-but-not-complete work, require a success marker:

{
  "response_matcher": {
    "success_pattern": "\"complete\"\\s*:\\s*true"
  }
}

Case-insensitive response matching

{
  "response_matcher": {
    "failure_pattern": "error",
    "flags": "i"
  }
}

Validation limits

  • supported regex flags: i, m, s, u
  • g is not supported
  • each regex pattern is limited to 512 characters
  • TrigRun evaluates patterns against the first 64 KiB of the response body

Full example

curl -X POST https://api.trigrun.com/v1/jobs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "partner-sync",
    "kind": "cron",
    "schedule": {
      "cron": "*/10 * * * *"
    },
    "request": {
      "url": "https://partner.example.com/sync?request_id={{uuid}}&triggered_at={{timestamp}}",
      "method": "POST",
      "headers": {
        "Authorization": "secret://partner-token",
        "X-Execution-Id": "{{execution_id}}",
        "Idempotency-Key": "{{uuid}}"
      },
      "body": {
        "execution_id": "{{execution_id}}",
        "request_id": "{{uuid}}",
        "started_at": "{{timestamp}}"
      },
      "success_statuses": [200],
      "response_matcher": {
        "success_pattern": "\"status\"\\s*:\\s*\"ok\"",
        "failure_pattern": "\"status\"\\s*:\\s*\"failed\"",
        "flags": "i"
      },
      "response_assertions": {
        "success": {
          "match": "all",
          "rules": [
            {
              "source": "json_body",
              "path": "status",
              "operator": "equals",
              "value": "ok"
            }
          ]
        }
      },
      "response_output_template": {
        "external_id": "{{response.body.data.id}}",
        "execution_id": "{{execution.id}}",
        "request_id": "{{uuid}}"
      }
    }
  }'