Write and run an automation

For engineers who automate payment logic with PayScript scripts bound to triggers.

Who this is for

Engineers who automate payment logic with PayScript. This page takes one script from import to a run: import, publish, bind it to a trigger as an automation, run it on demand, and change it later. Programmable payments explains scripts, automations, triggers and their lifecycles.

Before you start

  • PayScript code is Groovy, compiled in a restricted sandbox. It may call only built-in actions and use only the parameters the script declares. Obtain the execution engine's approved action names, arguments and effects before writing new code; the public API does not provide a complete callable-action catalogue.
  • Every write in this guide takes an Idempotency-Key. A retry with the same key replays the first response with Idempotency-Replayed: true.
  • PayScript timestamps are ISO 8601 UTC instants with fixed millisecond precision, for example 2026-08-18T11:26:46.312Z.

From script to accepted execution

%%{init: {"theme": "neutral"}}%%
flowchart TB
    Write["Write approved PayScript document"] --> Import["Import / UNPUBLISHED"]
    Import --> Publish["Publish script / PUBLISHED"]
    Publish --> Bind["Create automation / bind trigger and parameters"]
    Bind --> Run["Request ON_DEMAND execution"]
    Run --> Accepted["202 / retain executionId"]
    Accepted --> Evidence["Obtain operator evidence for outcome"]

Importing and publishing do not run the script. Execution acceptance is not proof of completion; the public API exposes no run-outcome read or execution webhook.

Import script · Publish script · Create automation · Request execution

What this example proves

The example logs a parameter. It demonstrates the document format, multipart import, publication, binding and execution request without inventing a payment-action signature. It does not mint tokens or implement a VAT payment. Replace the logging body with operator-approved actions only after you have their supported names, arguments and behaviour.

Keep the imported script ID, its rootScriptId and version number, the automation ID, and each execution ID in your backend. These describe different resources. An execution ID is not a Treasury transaction ID; the public API does not define a client-visible mapping between them.

1. Write the script document

A script is a YAML document with a triggerType, a trigger block (except for ON_DEMAND), optional params, and a code body. This example, from the API Reference, declares one required decimal parameter:

triggerType: ON_DEMAND
params:
  - { key: vatRate, type: DECIMAL, required: true, label: "VAT rate" }
code: |
  logMessage(vatRate.toString());

Unknown fields are rejected. A trigger block that sets an amount or threshold must also set a currency.

2. Import it

Upload the document as the file part of a multipart request. The script is stored UNPUBLISHED. Importing does not run it.

POST /api/scripts HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Idempotency-Key: 0d7e4b21-5a96-4c3f-8e10-9b2d6f4a1c58
Content-Type: multipart/form-data; boundary=qfp-boundary

--qfp-boundary
Content-Disposition: form-data; name="name"

tax-optimiser
--qfp-boundary
Content-Disposition: form-data; name="description"

Smart VAT tracking
--qfp-boundary
Content-Disposition: form-data; name="file"; filename="tax-optimiser.yaml"
Content-Type: application/x-yaml

triggerType: ON_DEMAND
params:
  - { key: vatRate, type: DECIMAL, required: true, label: "VAT rate" }
code: |
  logMessage(vatRate.toString());
--qfp-boundary--

Illustrative example built from the schema.

HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "name": "tax-optimiser",
  "description": "Smart VAT tracking",
  "status": "UNPUBLISHED",
  "rootScriptId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "versionNumber": 1,
  "triggerType": "ON_DEMAND",
  "scriptIds": [],
  "tenantId": "d36756ac-5326-49b3-a6ed-dd3eaa3371aa",
  "createdBy": "8f14e45f-ceea-467a-9a1e-1c8b4b0b5a21",
  "createdAt": "2026-08-18T11:26:46.312Z",
  "updatedBy": "8f14e45f-ceea-467a-9a1e-1c8b4b0b5a21",
  "updatedAt": "2026-08-18T11:26:46.312Z"
}

The name must be unique in your organisation: 3 to 50 ASCII letters, digits, spaces, hyphens and underscores, with no consecutive separators.

3. Publish it

PATCH /api/scripts/7c9e6679-7425-40de-944b-e07fc1f90ae7 HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Idempotency-Key: 6a1f3c85-2e07-4b9d-a4c2-8d5e0f7b3a16
Content-Type: application/json

{ "status": "PUBLISHED" }

Publishing also publishes every script this one depends on. The response is the script with "status": "PUBLISHED".

4. Create the automation

Bind the published script to its trigger and set its parameter values. The triggerType must match the script's.

POST /api/automations HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Idempotency-Key: 3b8e6d14-9f20-4a57-b1c3-7e4d2a0f9c65
Content-Type: application/json

{
  "alias": "vat-on-request",
  "description": "Applies the standard VAT rate on request",
  "scriptId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "triggerType": "ON_DEMAND",
  "scriptParameters": [
    { "key": "vatRate", "value": ["0.20"], "type": "DECIMAL" }
  ]
}

Illustrative example built from the schema.

HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "c33d1f7a-9e21-4b8c-a6d2-0f3b7c9e5a44",
  "alias": "vat-on-request",
  "description": "Applies the standard VAT rate on request",
  "scriptId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "scriptName": "tax-optimiser",
  "rootScriptId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "scriptVersionNumber": 1,
  "scriptStatus": "PUBLISHED",
  "triggerType": "ON_DEMAND",
  "status": "ACTIVE",
  "scriptParameters": [
    { "key": "vatRate", "value": ["0.20"], "type": "DECIMAL", "required": true, "label": "VAT rate", "linked": false }
  ],
  "triggerParameters": [],
  "tenantId": "d36756ac-5326-49b3-a6ed-dd3eaa3371aa",
  "userId": "8f14e45f-ceea-467a-9a1e-1c8b4b0b5a21",
  "createdBy": "8f14e45f-ceea-467a-9a1e-1c8b4b0b5a21",
  "createdAt": "2026-08-18T11:30:02.118Z",
  "updatedBy": "8f14e45f-ceea-467a-9a1e-1c8b4b0b5a21",
  "updatedAt": "2026-08-18T11:30:02.118Z"
}

The automation is created ACTIVE and owned by the calling user. For a TIME trigger, pass occurrence (for example DAILY) and occurrenceDetails (always including timeZone) in triggerParameters. For a BALANCE trigger, pass the account to monitor, the balance limit and the currency.

5. Run it

Run an ON_DEMAND automation, overriding a parameter for this run only:

POST /api/automations/c33d1f7a-9e21-4b8c-a6d2-0f3b7c9e5a44/executions HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Idempotency-Key: 2b6d9f14-7c3e-4a58-b1d0-9e5f3a7c2d86
Content-Type: application/json

{
  "parameterOverrides": [
    { "key": "vatRate", "value": "0.175", "type": "DECIMAL" }
  ]
}

Illustrative example built from the schema.

HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "executionId": "5f2c8a1e-3b4d-5e6f-9a0b-1c2d3e4f5061",
  "automationId": "c33d1f7a-9e21-4b8c-a6d2-0f3b7c9e5a44",
  "createdAt": "2026-08-18T11:31:15.402Z",
  "parameters": [
    { "key": "vatRate", "value": "0.175", "type": "DECIMAL" }
  ]
}

The 202 confirms the run was accepted. It is not a run record. The API does not return a run's outcome, and no webhook is sent for runs. Record the execution request and obtain operator evidence for its outcome. Do not report 202 as completed execution or settlement. Overrides are never written back to the automation. Omit the body to run with the configured values.

6. Pause, stop or change it

  • Pause and resume with PATCH /api/automations/{automationId}/status: ACTIVE to INACTIVE and back. INACTIVE to DISABLED stops it permanently.
  • GET /api/automations/{automationId}/history lists the creation and every status change, with who made it and when.
  • To change the code of a published script, send the new document as code to PATCH /api/scripts/{scriptId}. This creates the next version, UNPUBLISHED, and marks the old one OUTDATED. Automations on the old version keep running it. Publish the new version, then pause the old automation with ACTIVE to INACTIVE before creating an active replacement. Review accepted runs and the trigger gap with the operator. Reconcile in-flight work before permanently disabling the old automation; overlap can execute the same business intent twice.
  • GET /api/automations filtered by rootScriptId finds every automation on any version of a script.

Operate the automation after implementation

The bank owns the script's intended effect, approved action use, trigger configuration and version handover. Quant Flow imports, publishes and binds the supported document, then accepts execution requests. The operator must supply approved action signatures and run evidence where the external API has no outcome read.

Keep automation and execution IDs separate from Treasury operation IDs. During maintenance, inventory ACTIVE automations and coordinate reversible pauses independently of the adapter's submission pause. Do not assume INACTIVE cancels an accepted run or DISABLED can be resumed. Before changing a published version, review the trigger gap and in-flight execution handling with the owner. See Maintenance and recovery.

Worked example

Steps 1 to 5 above form one worked example: the tax-optimiser script is imported, published, bound as the vat-on-request automation with a VAT rate of 0.20, and run once at 0.175.

View in API Reference

Errors and edge cases

SituationResponseWhat to do
Script fails validation or compilation, or the name is taken400, naming the field or compilation errorFix the document or choose another name
Sending code and status in one PATCH400Send them separately
Editing the code of an OUTDATED or DEPRECATED script409Edit the latest version
Creating an automation on a script that is not PUBLISHED409Publish the script first
triggerType does not match the script's400Use the script's trigger type
Alias already used (compared case-insensitively)400Choose another alias
Running an automation that is not ACTIVE or not ON_DEMAND409Check its status and trigger type
Override with an unknown key, or a value that does not parse as its type422Correct the override
Missing Idempotency-Key on a run400Send a key
An earlier request with the same key is still in progress409Retry after it completes
Deleting a PUBLISHED script, or one with ACTIVE automations or dependants409Disable automations and unpublish first
  • Validate the trigger in your assigned environment before relying on it. Acceptance of TRANSACTION by the schema is not proof that the engine executes it.
  • Confirm the execution identity and policy path for script-submitted instructions before enabling the automation; compilation does not establish settlement authority.
  • A TIME or BALANCE automation that does not fire leaves no trace a client can read. See Limitations.

API Reference

Open an endpoint for request fields, response examples and the interactive API console.

Related pages

Implementation resources

Automations code recipes · Executions code recipes.

Use Implement a backend client for request handling, durable idempotency and outcome tracking. The developer integration coverage map links every public operation to its API Reference and contract-derived code recipe. Replace example identifiers with values from your assigned environment.


Did this page help you?