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 withIdempotency-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:
ACTIVEtoINACTIVEand back.INACTIVEtoDISABLEDstops 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
codetoPATCH /api/scripts/{scriptId}. This creates the next version,UNPUBLISHED, and marks the old oneOUTDATED. Automations on the old version keep running it. Publish the new version, then pause the old automation withACTIVEtoINACTIVEbefore 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
rootScriptIdfinds 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
- Import a script ·
POST- Update a script ·
PATCH- Create an automation ·
POST- Request an execution ·
POST
Errors and edge cases
| Situation | Response | What to do |
|---|---|---|
| Script fails validation or compilation, or the name is taken | 400, naming the field or compilation error | Fix the document or choose another name |
Sending code and status in one PATCH | 400 | Send them separately |
Editing the code of an OUTDATED or DEPRECATED script | 409 | Edit the latest version |
Creating an automation on a script that is not PUBLISHED | 409 | Publish the script first |
triggerType does not match the script's | 400 | Use the script's trigger type |
| Alias already used (compared case-insensitively) | 400 | Choose another alias |
Running an automation that is not ACTIVE or not ON_DEMAND | 409 | Check its status and trigger type |
Override with an unknown key, or a value that does not parse as its type | 422 | Correct the override |
Missing Idempotency-Key on a run | 400 | Send a key |
| An earlier request with the same key is still in progress | 409 | Retry after it completes |
Deleting a PUBLISHED script, or one with ACTIVE automations or dependants | 409 | Disable automations and unpublish first |
- Validate the trigger in your assigned environment before relying on it. Acceptance of
TRANSACTIONby 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
TIMEorBALANCEautomation 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.
| Operation | Method |
|---|---|
| Import a script | POST |
| Get a script | GET |
| Update a script | PATCH |
| Download a script's source | GET |
| Clone a script | POST |
| Delete a script | DELETE |
| List automations | GET |
| Create an automation | POST |
| Run an on demand automation | POST |
| Update an automation's status | PATCH |
| Get an automation's status change history | GET |
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.
Updated 4 days ago

