Skip to content

Compose & transaction groups

A virtual service rarely mocks just one thing — a “payments” mock might need a checkout endpoint, a refund endpoint, and a webhook callback, each defined once but reused across several virtual services that all talk to a similar dependency. Transaction groups and composition are how you build and share that structure.

A transaction group is a reusable, workspace-scoped named bundle of transactions — think of it as a library shelf of related endpoints (for example, “Stripe-like payments” or “Inventory API v2”) that any virtual service in the workspace can pull from.

  1. Open Transaction groups in the left navigation — it’s a standalone library, not nested under a single virtual service, because one group can be referenced by many virtual services at once.
  2. Click New group, give it a name and description.
  3. Add transactions to the group — method, path, and templated response — exactly as you would on a virtual service’s Transactions tab.
📷 Screenshot to capture — transaction-groups-library

What to show:MaxoPerf Transaction groups library page showing a list of groups with name, description, transaction count, and used-by count

Transaction groups library — each row shows how many transactions the group holds and how many virtual services currently reference it.

The group list shows a used-by count — how many virtual services currently include this group in their composition — so you can see the blast radius of an edit before you make it. Editing a transaction inside a group updates every virtual service that references it, live.

A virtual service’s composition is the ordered list of what it serves: any mix of whole transaction groups and individually-added transactions, resolved as the union of everyone’s transactions (deduplicated) at serve time. Open a virtual service and go to its Compose tab.

📷 Screenshot to capture — vs-composer-panel

What to show:MaxoPerf virtual service Compose tab showing a two-pane layout — a searchable library of groups and transactions on the left, and the ordered composition list on the right, with a ⌘K command palette and drag handles

Compose tab: search or ⌘K the library on the left, build the ordered composition on the right. Drag is a mouse accelerator on the same rows — nothing requires it.

The composer is a two-pane layout: a searchable library (every transaction group and every individual transaction in the workspace) on the left, and the virtual service’s ordered composition on the right. There are three ways to add something to the composition, and they’re fully interchangeable:

  1. Select / press Enter. Click a library row, or focus it and press Enter — the row’s main action is “add to composition.” No drag required.
  2. ⌘K (Ctrl+K). Open the command palette, type to filter across groups and transactions, and pick one.
  3. Drag. A mouse accelerator on the same library rows — pick up a row and drop it into the composition list to reorder or add. The drag handle also supports keyboard-drag (Tab to focus it, Enter/Space to pick up, arrow keys to move, Enter/Space to drop, Escape to cancel).

Adding something already in the composition is a no-op (with a toast, not a silent failure or a duplicate entry) — a group or transaction can’t be added to the same virtual service twice.

Rather than leaving the composer to add a new transaction, use + New transaction docked at the top of the composition pane. It creates the transaction directly in the virtual service’s home group and adds it to the composition in one step — no context switch to the Transactions tab.

Composition edits are local (a draft) until you click Save composition — nothing is sent to the server until then, except an on-the-fly transaction create, which persists immediately along with the composition update, since the server creates both atomically.

When a virtual service’s no-match policy is set to Proxy to a real origin, unmatched requests are forwarded through — and now show up in the Analytics tab as a first-class, named line item (labeled Passthrough) alongside your defined transactions, rather than disappearing into an “unmatched” bucket. This makes it possible to see, at a glance, what share of traffic your defined transactions are actually covering versus what’s still falling through to the real origin — useful for deciding what to mock next.