Build your own approval inbox

For integration engineers who surface approval tasks in the bank's own workflow tools instead of the Management Panel.

Who this is for

Integration engineers who want approvers to work in the bank's own workflow or case-management tool. This page covers listing an approver's tasks, reading the request behind a task, approving, rejecting and reassigning, keeping the inbox current, and the evidence each action leaves. Policy, approvals and audit explains requests, tasks, steps and groups.

How the inbox works

  • An approval request is one decision your organisation owes on one resource. It holds one or more tasks.
  • A task is owed by a group or one person. Its approverIds hold the people it resolved to when it was created. Any one of them may decide it.
  • Tasks at a lower step must resolve before a higher step can be acted on.
  • One rejection ends the whole request as REJECTED. The request is APPROVED only when every task is approved.

Approvers act with their own identity

The inbox and every decision are matched on the caller's sub. Your tool must therefore call the API with the approver's own access token, not a shared service identity. Each approver needs their own platform user, added to the approval groups your policies name. A shared identity would see only its own tasks, and every decision would be recorded against it.

Authenticate each approver through the identity provider configured for your deployment and use that person's own access token. Machine credentials and an initiator's token must not stand in for the person deciding a task.

1. List the approver's tasks

GET /api/approvals/tasks?status=PENDING&page=0&size=20 HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <approver's access token>
API-Version: 1.0.0

Illustrative example built from the schema.

{
  "data": [
    {
      "taskId": "7e3b1c52-9a40-4d18-b6f2-0c5d8e1a3f97",
      "requestId": "c2a9f4e1-5b73-4f0d-8e26-1d7b3c9a6e05",
      "action": "FIAT_PAYMENT",
      "resourceId": "PAY-2026-000418",
      "step": 1,
      "status": "PENDING",
      "reason": "Over 50,000 EUR: compliance sign-off"
    }
  ],
  "page": 0,
  "size": 20,
  "totalItems": 1,
  "totalPages": 1
}

The list returns one task status per call (PENDING if you omit status), newest first. It includes tasks owed to groups the approver belonged to when the task was created.

2. Read the request behind a task

Show the approver the full context before they decide: earlier steps, who acted and what they said, and the deadline.

GET /api/approvals/requests/c2a9f4e1-5b73-4f0d-8e26-1d7b3c9a6e05 HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <approver's access token>
API-Version: 1.0.0

Illustrative example built from the schema.

{
  "id": "c2a9f4e1-5b73-4f0d-8e26-1d7b3c9a6e05",
  "action": "FIAT_PAYMENT",
  "resourceId": "PAY-2026-000418",
  "reason": "Over 50,000 EUR",
  "status": "PENDING",
  "sourceType": "POLICY",
  "sourceRef": "4b8d2e61-0f37-4a95-9c1e-6a2d8f3b5c70",
  "initiatedBy": "3d6f9a12-8b45-4c7e-a0d1-5e2f7b9c4a86",
  "expiresAt": "2026-09-16T09:00:00.000Z",
  "resolvedAt": null,
  "resolvedBy": null,
  "tasks": [
    {
      "id": "1a4c7e20-6d93-4b58-8f0e-2c5a9d3b7e61",
      "step": 0,
      "approverExpr": "#payments_manager",
      "approverIds": ["9b2e5d71-4c08-4f6a-b3d9-7e1a0c6f2b48"],
      "actedBy": "9b2e5d71-4c08-4f6a-b3d9-7e1a0c6f2b48",
      "autoApproved": false,
      "status": "APPROVED",
      "reason": "Over 50,000 EUR: payments manager",
      "comment": "Supplier and invoice verified",
      "actedAt": "2026-09-02T09:41:12.000Z"
    },
    {
      "id": "7e3b1c52-9a40-4d18-b6f2-0c5d8e1a3f97",
      "step": 1,
      "approverExpr": "#compliance",
      "approverIds": ["6c1f8a35-2d70-4e9b-a4c6-8b3e0d5f1a92", "e4a7b2d9-1c56-4f83-9e0a-3d8c6b1f7a24"],
      "actedBy": null,
      "autoApproved": false,
      "status": "PENDING",
      "reason": "Over 50,000 EUR: compliance sign-off",
      "comment": null,
      "actedAt": null
    }
  ]
}

3. Approve or reject

Send the approver's decision with an optional comment. The comment becomes part of the record.

POST /api/approvals/tasks/7e3b1c52-9a40-4d18-b6f2-0c5d8e1a3f97/approve HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <approver's access token>
API-Version: 1.0.0
Content-Type: application/json

{ "comment": "Counterparty screened, no match" }

The response is the whole request. Here the last pending task was approved, so the request is now APPROVED, resolvedBy is the approver's sub, and the waiting operation is released.

Illustrative example built from the schema, abbreviated to the changed fields.

{
  "id": "c2a9f4e1-5b73-4f0d-8e26-1d7b3c9a6e05",
  "status": "APPROVED",
  "resolvedAt": "2026-09-02T11:05:37.000Z",
  "resolvedBy": "6c1f8a35-2d70-4e9b-a4c6-8b3e0d5f1a92",
  "tasks": [
    { "id": "1a4c7e20-6d93-4b58-8f0e-2c5a9d3b7e61", "step": 0, "status": "APPROVED" },
    {
      "id": "7e3b1c52-9a40-4d18-b6f2-0c5d8e1a3f97",
      "step": 1,
      "status": "APPROVED",
      "actedBy": "6c1f8a35-2d70-4e9b-a4c6-8b3e0d5f1a92",
      "comment": "Counterparty screened, no match",
      "actedAt": "2026-09-02T11:05:37.000Z"
    }
  ]
}

Rejecting uses POST /api/approvals/tasks/{taskId}/reject with the same body. The request becomes REJECTED at once and any other pending tasks become SKIPPED.

4. Reassign a task

Move a pending task to another group or person, for example before an approver's leave.

POST /api/approvals/tasks/7e3b1c52-9a40-4d18-b6f2-0c5d8e1a3f97/reassign HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Content-Type: application/json

{ "approver": "#deputy_mlro", "reason": "Primary approver on leave" }

approverIds is replaced by the new group's members, with the request's initiator removed. approverExpr keeps the original expression. The task records reassignedFrom, reassignedBy, reassignedAt and reassignReason.

The current API allows any authenticated caller in the tenant to cancel a request or reassign a pending task; the public contract does not restrict these operations to an initiator or administrator. Enforce your bank's authorization policy in the approval application and review it against the deployed endpoint behavior.

5. Cancel a request

POST /api/approvals/requests/{requestId}/cancel withdraws a PENDING request. Pending tasks become CANCELLED. Tasks already decided keep their outcome.

Keep the inbox current

  • Webhooks. Subscribe to approval.requested, approval.granted, approval.rejected and approval.expired. See Webhooks.
  • Polling. Refresh the approver's list with GET /api/approvals/tasks. For a supervisor view, GET /api/approvals/requests lists every request in the organisation with its tasks, filtered by status, actedBy, action, resourceId or a resolution date range. A date range excludes unresolved requests.
  • Deadlines. Show expiresAt. A request past its deadline becomes EXPIRED at the next expiry sweep, and its outcome is passed back to the waiting operation. After expiry, read the affected transaction rather than deriving its state from the request alone. Treasury maps an expired policy decision to FAILED with POLICY_EXPIRED while awaiting a decision; an expiry while parked for approval is handled as a refusal. Retain the actual returned state and failureCode.

Evidence

Each task records who decided it (actedBy), when (actedAt) and their comment. Each request records who raised it (initiatedBy), who resolved it and when. Group tasks keep both the group that was asked (approverExpr) and the people it resolved to (approverIds), frozen when the task was created. System actions are named, for example system:auto-approval and system:ttl-sweeper. See Audit and evidence.

Worked example

Steps 1 to 3 above form one worked example: a two-step request for a payment over 50,000 EUR. The payments manager approved step 0. A compliance team member lists their inbox, reads the request, and approves step 1 with a comment, which resolves the request as APPROVED.

View in API Reference

Errors and edge cases

SituationResponseWhat to do
The caller is not in the task's approverIds403Check the approver's group membership when the task was created
The caller is the request's initiator403Route the task to another approver
The task is no longer PENDING409Refresh the request; another approver may have acted
A task at a lower step is still PENDING409Wait for the earlier step
Reassigning to a group that resolves to nobody, or only to the initiator400Choose another group or person
Reassigning to the same set of approvers409No change needed
Cancelling a request that is not PENDING409Refresh the request
A task or request in another organisation404Check the identifier
  • A task with no approverIds, such as a manual-review task, appears in no inbox. Build a supervisor view on GET /api/approvals/requests so these are reassigned.
  • A named-user approver is stored as given, lower-cased and unvalidated. A mistyped id matches nobody and the task waits until reassigned or expired.
  • POST /api/approvals/requests raises a manual request with no policy behind it. It takes no idempotency key, so a retried call can create a second request.

Follow a Recipe

Step through the code in JavaScript or Python, inspect illustrative responses, and open the connected endpoint schemas.

API Reference

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

Related pages

Implementation resources

Approval groups code recipes · Approvals 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?