Skip to content

Workflow tools

The curated MCP tool set for the compliance loop: what each tool does, which are operations and which compose them, and the loop they make.

The workflows tool set is for agents that work better with a few larger tools. With it alone an agent can run the whole compliance loop: see what needs doing, take the most urgent task, read its packet or package and playbook, do the work in the authority's portal, report back with evidence, and follow the approval.

Most workflow tools are registry operations, so the REST API has them too, with the same arguments. Four are MCP-only compositions: they call a few registry operations in a row with your credentials, each with its own permission, risk tier, approvals, idempotency and audit, and decide nothing an operation would decide.

ToolWhat it doesKind
entity_compliance_overviewCompliance overviewoperation compliance.overview, see Compliance tools
tasks_nextClaim the next taskoperation tasks.claim_next, see Tasks tools
registration_get_packetGet a registration packetoperation registrations.packet, see Registrations tools
filing_prepare_and_get_packagePrepare a return and get its packageMCP composition of filing_periods.get, filing_periods.lock, filing_periods.prepare, filing_periods.package (below)
task_completeComplete or submit a taskMCP composition of tasks.get, tasks.submit, tasks.complete (below)
approval_statusApproval statusMCP composition of approvals.get (below)
explain_tax_decisionExplain a tax decisionoperation tax.quotes.explain, see Tax tools
subscription_change_previewPreview a plan changeMCP composition of subscriptions.preview_change (below)
tasks_documents_uploadUpload a task documentoperation tasks.documents.upload, see Tasks tools
tasks_failFail a compliance taskoperation tasks.fail, see Tasks tools
tasks_heartbeatExtend a task's leaseoperation tasks.heartbeat, see Tasks tools
tasks_releaseRelease a compliance taskoperation tasks.release, see Tasks tools

The loop

  1. entity_compliance_overview: registrations that need attention, the next deadlines, unfinished tasks and returns due.
  2. tasks_next: claim the most urgent task you can finish (a 15-minute lease; keep it with tasks_heartbeat). Its result links the task's packet or package and the regime's playbook as resources.
  3. For a registration, registration_get_packet; for a return, filing_prepare_and_get_package (locks and prepares the period, which may need approval, then returns the package and links the report files).
  4. Do the work in the authority's portal, under an authorization valid for the regime. Upload the portal's confirmation with tasks_documents_upload.
  5. task_complete with the reference, the receipt and the authorization: dry-run it first. Submissions are compliance tier and usually answer approval_required.
  6. approval_status until it is executed; the registration or filing period then changes, with your evidence attached.
  7. If you can't finish: tasks_release, or tasks_fail with a reason and a retry date.

explain_tax_decision explains a tax quote in plain words; subscription_change_preview shows what a plan change would cost before anyone makes it.

approval_status

Approval status. Workflow tool (MCP only) · calls approvals.get · tool set workflows

The status of an approval request you got from an approval_required answer (approvals.get): pending, approved (running), executed (done exactly as you sent it), rejected, expired or stale (approved, but it could no longer run). finished is true once nothing more will happen; remediation says what to do next. The full request (its input and dry-run result) is in approvals_get.

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (apr_…)yesThe approval request (apr_…).
  • Read-only: changes nothing.

Example

Approved and done

Arguments:

JSON
{
  "id": "apr_01m4ttwd3veh9apbewxheq5xa1"
}

Result output:

JSON
{
  "object": "approval_status",
  "id": "apr_01m4ttwd3veh9apbewxheq5xa1",
  "status": "executed",
  "finished": true,
  "operationId": "tasks.submit",
  "summary": "Submit the task File the One-Stop Shop, Union scheme 2026-Q3 return",
  "approvals": 1,
  "requiredApprovals": 1,
  "rejectionReason": null,
  "failure": null,
  "resultRef": "task_01m4ttwd3veh9apbewxheq5xa9",
  "approveUrl": "https://ownrecord.io/console/acme/approvals/apr_01m4ttwd3veh9apbewxheq5xa1",
  "expiresAt": "2026-11-11T09:10:00.000Z",
  "executedAt": "2026-11-08T10:02:00.000Z",
  "remediation": "Approved and done: the call ran exactly as you sent it. resultRef names what it created or changed."
}

filing_prepare_and_get_package

Prepare a return and get its package. Workflow tool (MCP only) · calls filing_periods.get, filing_periods.lock, filing_periods.prepare, filing_periods.package · tool set workflows

Takes a filing period as far as it can go towards filing, then returns its filing package: it locks an open period (filing_periods.lock, compliance tier: under your approval policy this answers approval_required), prepares a locked one (filing_periods.prepare: the report is generated from the ledger and invoices and must reconcile with the ledger), and once the period is prepared (or later) reads filing_periods.package. Steps already done are skipped, so call it again after an approval with the same idempotency_key and it continues. steps says what each step did.

The result links the package and the report files as resources (package.json, report.csv, report.xlsx) and the regime's filing playbook: read them there rather than asking for more tool output. A dry_run stops after the first step that would change the period (the next one needs it done). When the period is prepared, its filing.prepare task finishes by itself.

Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (fp_…)yesThe filing period (fp_…).
entity_idID (ent_…)noThe legal entity to act on (ent_…), when your credentials cover more than one.
idempotency_keystringnoA unique string for this call. Retrying with the same key and arguments never acts twice and continues where the last call stopped. When left out, the server generates one and returns it in the result's idempotency_key. (1–200 characters)
dry_runbooleannotrue: check permissions and rules and compute the first change's result, then roll it back. Nothing is saved. (default false)
  • Legal entity: pass entity_id with an organization credential.
  • Idempotency: the result returns the idempotency_key used. A composition with several changes derives one key per step from it (<key>:lock, <key>:prepare), so a retry with the same key replays the steps already done and continues where it stopped.
  • Dry run: supported, for the first step that would change something.

Example

A locked period: prepared, then its package

Arguments:

JSON
{
  "id": "fp_01m4ttwd3veh9apbewxheq5xa7"
}

Result output:

JSON
{
  "object": "filing_preparation",
  "steps": [
    {
      "operation": "filing_periods.lock",
      "outcome": "not_needed"
    },
    {
      "operation": "filing_periods.prepare",
      "outcome": "done"
    }
  ],
  "filingPeriod": {
    "id": "fp_01m4ttwd3veh9apbewxheq5xa7",
    "status": "prepared"
  },
  "package": {
    "object": "filing_package",
    "filingPeriodId": "fp_01m4ttwd3veh9apbewxheq5xa7"
  }
}

subscription_change_preview

Preview a plan change. Workflow tool (MCP only) · calls subscriptions.preview_change · tool set workflows

Shows exactly what a plan or quantity change of a subscription would do, without changing anything (subscriptions.preview_change): upgrade or downgrade, when it applies, the invoice it would issue now (prorations, discounts, tax at today's rates, credit balance applied, amount due) or the scheduled change, and the monthly recurring amount before and after. Send the same arguments to subscriptions_update to make the change (financial tier: dry-run it, and expect an approval above your limits).

Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (sub_…)yes–
itemsarray of objectnoItem changes: { id, priceId } swaps a price, { id, quantity } changes seats, { priceId, quantity } adds an item, { id, deleted: true } removes one. Items not named stay. (1–40 items)
prorationBehaviorone of create_prorations, always_invoice, nonenocreate_prorations (credit unused time and charge the remaining time on the next invoice; a net credit goes to the customer credit balance), always_invoice (invoice the proration now) or none.
effectiveone of now, period_endnonow, or at the end of the current period (period_end, stored as pendingUpdate). Default: upgrades and interval changes now with always_invoice, downgrades at the period end.
paymentBehaviorone of allow_incomplete, pending_if_incompletenoFor a change invoiced now: allow_incomplete (default; the change applies and a failed payment goes to dunning) or pending_if_incomplete (the old items stay until the invoice is paid).
couponIdID (cpn_…)noApply a coupon to the subscription.
promotionCodestringnoA promotion code as the customer typed it (case doesn't matter). (1–50 characters)
entity_idID (ent_…)noThe legal entity to act on (ent_…), when your credentials cover more than one.
brand_idID (brd_…)noThe brand to act on (brd_…), when your credentials cover more than one.
  • Brand: pass brand_id with an organization or entity credential.
  • Read-only: changes nothing.

Example

What upgrading to Pro now costs

Arguments:

JSON
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y3"
    }
  ]
}

Result output:

JSON
{
  "object": "subscription_change_preview",
  "subscriptionId": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "direction": "upgrade",
  "intervalChange": false,
  "effective": "now",
  "prorationBehavior": "always_invoice",
  "settlement": "invoice_now",
  "invoice": {
    "id": "inv_01m4tx5nj8emwbyf7y9vcf47yk",
    "object": "invoice",
    "livemode": false,
    "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "number": null,
    "numbering": null,
    "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
    "subscriptionId": null,
    "collectionMethod": "send_invoice",
    "kind": "invoice",
    "status": "open",
    "language": "en",
    "issuedAt": "2026-10-20T09:00:00.000Z",
    "issueDate": "2026-10-20",
    "taxPoint": "2026-10-20T09:00:00.000Z",
    "taxPointDate": "2026-10-20",
    "daysUntilDue": 14,
    "dueDate": "2026-11-03",
    "seller": {
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
      "legalName": "Acme Digital d.o.o.",
      "tradingName": null,
      "address": {
        "line1": "Ilica 1",
        "line2": null,
        "city": "Zagreb",
        "postalCode": "10000",
        "region": null,
        "country": "HR"
      },
      "companyRegistryId": "080000001",
      "taxIds": [
        {
          "type": "eu_vat",
          "value": "HR12345678901",
          "regimeId": null
        }
      ],
      "brand": {
        "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
        "name": "Genno",
        "primaryColor": "#0E6B5C",
        "accentColor": null,
        "supportEmail": "help@genno.example",
        "supportUrl": null
      },
      "footerText": null
    },
    "buyer": {
      "type": "b2b",
      "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
      "name": "Alpen Apps GmbH",
      "email": "billing@alpen.example",
      "address": null,
      "country": "AT",
      "taxId": {
        "type": "eu_vat",
        "value": "ATU00000000",
        "country": "AT"
      }
    },
    "currency": "EUR",
    "lines": [
      {
        "id": "1",
        "description": "Implementation workshop (days)",
        "productId": "prod_01m4tx5nj8emwbyf7y9vcf47yr",
        "priceId": null,
        "quantity": 2,
        "taxCategoryId": "consulting_remote",
        "taxBehavior": "exclusive",
        "unitAmount": {
          "amount": "600000000",
          "currency": "EUR"
        },
        "net": {
          "amount": "1200000000",
          "currency": "EUR"
        },
        "tax": {
          "ratePpm": "0",
          "amount": {
            "amount": "0",
            "currency": "EUR"
          },
          "jurisdictionId": "AT",
          "regimeId": "EU_OSS_UNION",
          "decision": "reverse_charge",
          "rateKind": null,
          "rateId": null,
          "pendingRegistration": false
        },
        "gross": {
          "amount": "1200000000",
          "currency": "EUR"
        },
        "kind": "invoice_item",
        "period": null,
        "subscriptionItemId": null,
        "invoiceItemId": "ii_01m4tx5nj8emwbyf7y9vcf47ys",
        "discount": null,
        "meteredQuantity": null
      }
    ],
    "totals": {
      "net": {
        "amount": "1200000000",
        "currency": "EUR"
      },
      "tax": {
        "amount": "0",
        "currency": "EUR"
      },
      "gross": {
        "amount": "1200000000",
        "currency": "EUR"
      },
      "taxByRate": [
        {
          "ratePpm": "0",
          "jurisdictionId": "AT",
          "regimeId": "EU_OSS_UNION",
          "decision": "reverse_charge",
          "net": {
            "amount": "1200000000",
            "currency": "EUR"
          },
          "tax": {
            "amount": "0",
            "currency": "EUR"
          }
        }
      ]
    },
    "taxCurrencyTotals": null,
    "creditApplied": {
      "amount": "200000000",
      "currency": "EUR"
    },
    "amountDue": {
      "amount": "1000000000",
      "currency": "EUR"
    },
    "notes": [
      {
        "code": "reverse_charge",
        "text": "Prijenos porezne obveze (reverse charge) – čl. 17. st. 1. Zakona o PDV-u"
      }
    ],
    "fieldCheck": {
      "invoicingRuleIds": [],
      "missing": ["buyer_address"],
      "unchecked": []
    },
    "pendingRegistration": false,
    "paymentIds": [],
    "creditNoteIds": [],
    "ledgerTxnIds": ["txn_01m4tx5nj8emwbyf7y9vcf47yn"],
    "quoteId": "tq_01m4tx5nj8emwbyf7y9vcf47xr",
    "quoteIds": ["tq_01m4tx5nj8emwbyf7y9vcf47xr"],
    "pdf": {
      "status": "pending",
      "fileId": null,
      "sha256": null,
      "size": null,
      "templateVersion": null,
      "renderedAt": null,
      "url": "/api/v1/invoices/inv_01m4tx5nj8emwbyf7y9vcf47yk/pdf"
    },
    "finalizedAt": "2026-10-20T09:00:00.000Z",
    "paidAt": null,
    "payment": null,
    "voidedAt": null,
    "markedUncollectibleAt": null,
    "emailedAt": null,
    "sentAt": null,
    "draft": null,
    "metadata": {
      "contract": "ENT-2026-07"
    },
    "version": 2,
    "createdAt": "2026-10-20T08:30:00.000Z",
    "updatedAt": "2026-10-20T09:00:00.000Z"
  },
  "pendingItems": [],
  "credit": null,
  "subscription": {
    "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
    "object": "subscription",
    "livemode": false,
    "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
    "status": "active",
    "items": [
      {
        "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
        "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y3",
        "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
        "quantity": 3,
        "createdAt": "2026-10-13T12:00:00.000Z"
      }
    ],
    "currency": "EUR",
    "mrr": {
      "amount": "147000000",
      "currency": "EUR"
    },
    "collectionMethod": "charge_automatically",
    "daysUntilDue": null,
    "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
    "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
    "currentPeriodStart": "2026-10-13T12:00:00.000Z",
    "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
    "trialStart": null,
    "trialEnd": null,
    "trialEndBehavior": "convert",
    "cancelAtPeriodEnd": false,
    "cancelAt": null,
    "canceledAt": null,
    "endedAt": null,
    "cancellation": null,
    "pause": null,
    "discountIds": [],
    "pendingUpdate": null,
    "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
    "incompleteExpiresAt": null,
    "testClockId": null,
    "dunning": null,
    "usageThreshold": null,
    "entitlementGraceUntil": null,
    "metadata": {
      "crm_account": "A-1042"
    },
    "version": 2,
    "createdAt": "2026-10-13T12:00:00.000Z",
    "updatedAt": "2026-10-13T12:00:00.000Z"
  },
  "mrrBefore": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "mrrAfter": {
    "amount": "147000000",
    "currency": "EUR"
  },
  "mrrDelta": {
    "amount": "60000000",
    "currency": "EUR"
  }
}

task_complete

Complete or submit a task. Workflow tool (MCP only) · calls tasks.get, tasks.submit, tasks.complete · tool set workflows

Finishes a compliance task the way its type needs (its completeWith): tasks.submit for the types whose completion changes a registration or a filing period (filing.submit, filing.pay, registration.submit, registration.confirm, deregistration.submit; compliance tier, so it may answer approval_required), else tasks.complete (write tier). It reads the task first (tasks.get), then calls that one operation with your arguments, your idempotency_key and dry_run.

Submissions take the authority's reference (and effectiveFrom for registration.confirm, paidOn for filing.pay), the authorizationId you acted under (*.submit tasks), and outputs (receipt files uploaded with tasks_documents_upload, more references, notes). Work tasks take only outputs: sending a reference or an authorization for one is refused. Dry-run first. When the answer is approval_required, nothing changed yet: follow it with approval_status.

Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false

Arguments

ArgumentTypeRequiredDescription
idID (task_…)yesThe task (task_…).
referencestringnoSubmissions: the authority's reference (the return's, the application's, the payment's). (1–200 characters)
effectiveFromstringnoregistration.confirm: the first day the registration is effective.
paidOnstringnofiling.pay: the day the tax was paid.
authorizationIdID (atz_…)no*.submit tasks: the authorization the work was done under.
outputsobjectnoEvidence: more references by name, when it was submitted, receipt files, notes.
expectedVersionintegernoRefuse if the task changed since this version. (1–9007199254740991)
entity_idID (ent_…)noThe legal entity to act on (ent_…), when your credentials cover more than one.
idempotency_keystringnoA unique string for this call. Retrying with the same key and arguments never acts twice and continues where the last call stopped. When left out, the server generates one and returns it in the result's idempotency_key. (1–200 characters)
dry_runbooleannotrue: check permissions and rules and compute the first change's result, then roll it back. Nothing is saved. (default false)
  • Legal entity: pass entity_id with an organization credential.
  • Idempotency: the result returns the idempotency_key used. A composition with several changes derives one key per step from it (<key>:lock, <key>:prepare), so a retry with the same key replays the steps already done and continues where it stopped.
  • Dry run: supported, for the first step that would change something.

Example

Submit the filed Q3 return, which needs approval

Arguments:

JSON
{
  "id": "task_01m4ttwd3veh9apbewxheq5xa9",
  "reference": "HR/HR12345678901/Q3.2026",
  "authorizationId": "atz_01m4ttwd3veh9apbewxheq5xa3",
  "outputs": {
    "files": ["file_01m4ttwd3veh9apbewxheq5xah"]
  }
}

Result output:

JSON
{
  "object": "task_completion",
  "operation": "tasks.submit",
  "task": {
    "id": "task_01m4ttwd3veh9apbewxheq5xa9",
    "type": "filing.submit",
    "status": "done"
  }
}