> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Operations and External Calls

> Make business changes that commit locally and reach external systems durably

An operation is a named business change, such as cancelling an order or
correcting an invoice. It runs its preparation in an ordinary
[mutation](/functions/mutation-functions) transaction, and it can ask for work in
an external system by submitting durable external calls. Everything an
operation prepares commits together, or not at all.

Here is an operation that cancels an order and asks a billing system to void its
invoice:

```ts bijection/orders.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { defineOperation } from "bijection/server";
import { BijectionError, v } from "bijection/values";
import { orders } from "./schema";
import { billing } from "./billing";

export const cancel = defineOperation({
  on: orders,
  target: { argument: "order_id" },
  args: { order_id: v.id("order_records"), invoice_id: v.id("invoices") },
  returns: v.object({ call: v.string() }),
  prepare: async (ctx, args) => {
    const order = await ctx.db.get(args.order_id);
    if (!order || order.status === "cancelled") {
      throw new BijectionError({
        code: "ORDER_STATE",
        message: "This order can no longer be cancelled",
      });
    }
    await ctx.db.patch(args.order_id, { status: "cancelled" });
    const call = await ctx.externalCalls.submit(billing.commands.voidInvoice, {
      target: args.invoice_id,
      args: { reason: "order cancelled" },
    });
    return { call };
  },
});
```

When this operation is accepted, the order's new status and the intent to void
the invoice are committed in one transaction. The billing system is called
afterwards, and its answer is recorded separately.

## Operations, mutations and actions

Operations are built on the functions you already know. An operation does not
replace [mutations](/functions/mutation-functions) or
[actions](/functions/actions), and `action` keeps its ordinary meaning: a
function that can call third-party APIs directly with `fetch`.

| | Mutations | Actions | Operations |
| - | - | - | - |
| Database access | Yes | Through queries/mutations | Yes |
| Transactional | Yes | No | Yes |
| Reaches external systems | No | Yes, directly | Yes, through external calls |
| Stable request identity and recovery | No | No | Yes, with a request key |
| Preview without committing | No | No | Yes |
| Requires an explicit grant to call | No | No | Yes |

Reach for an operation when a change matters to the business: when it must be
retried without being applied twice, when a person should be able to preview it
first, or when it has to ask an external system to do something.

## What happens when you call an operation

<Steps>
  <Step title="Preview (optional)">
    A preview runs the same preparation on the current data, reports the changes
    and external calls it would make, and then discards them. Nothing is
    accepted, reserved or sent.
  </Step>

  <Step title="Acceptance">
    The caller submits the operation with a request key. Preparation runs in one
    transaction. Its local changes, its external calls and the retained request
    commit together, and the caller receives an acceptance receipt.
  </Step>

  <Step title="Delivery">
    After the commit, each external call is delivered to its destination through
    the integration command it names. Delivery follows the destination's declared
    contract, not a generic retry loop.
  </Step>

  <Step title="Outcome">
    Each call ends with an outcome the destination's evidence supports: for
    example delivered, refused, or unknown. An unknown outcome stays unknown until
    it is reconciled.
  </Step>
</Steps>

<Note>
  An acceptance receipt proves that your local changes committed. It is not
  evidence that an external system applied anything. Follow each call's status
  for that.
</Note>

## Learn more

<CardGroup cols={2}>
  <Card title="Defining operations" href="/operations/defining-operations">
    Declare an operation with `defineOperation`: its object type, target,
    arguments, result and preparation.
  </Card>

  <Card title="Calling operations" href="/operations/calling-operations">
    Request keys, previews, recovery after a lost response, and status.
  </Card>

  <Card title="External calls" href="/operations/external-calls">
    Submit durable external calls and follow their lifecycle and outcomes.
  </Card>

  <Card title="Operation interfaces" href="/operations/operation-interfaces">
    Share one operation shape across object types and discover implementations.
  </Card>

  <Card title="Durable waits" href="/operations/durable-waits">
    Commit work at a business-time boundary with `defineWait`, and require
    source freshness with `sourceBarrier`.
  </Card>

  <Card title="CLI and console" href="/operations/cli-and-dashboard">
    Run, preview and recover operations with `bijection run`, and follow them in
    the console.
  </Card>
</CardGroup>

External calls are delivered through the commands of an
[integration](/integrations/overview). Who may call an operation is decided by
[access rules and grants](/access/overview).
