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

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Invoke a journey

> Start a journey run from the API, find it by run ID, and cancel it.

export const Endpoint = ({method, path, name, href, children, bare}) => {
  const verb = String(method || "").toUpperCase();
  const title = verb + " " + path;
  const label = children || name || path;
  if (bare) {
    return href ? <a href={href}><code>{title}</code></a> : <code>{title}</code>;
  }
  if (!href) {
    return <span className="cx-endpoint" data-method={verb} title={title}>
        <span className="cx-endpoint-label">{label}</span>
        <span className="cx-endpoint-method">{verb}</span>
      </span>;
  }
  return <a className="cx-endpoint" data-method={verb} href={href} title={title}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">{verb}</span>
    </a>;
};

export const AppLink = ({href, children, name, bare}) => {
  const label = children || name || "Open in Courier";
  if (bare) {
    return <a href={href} target="_blank" rel="noreferrer">{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="app" href={href} target="_blank" rel="noreferrer">
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method" aria-hidden="true">↗</span>
    </a>;
};

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

<Info>
  <Doc href="/docs/journeys/overview">Journeys</Doc> covers the snapshot, delays, and cancellation model.
</Info>

Start a Journey run from the API, then find it by its run ID.

## Prerequisites

* A published journey with an **API** trigger
* <AppLink href="https://app.courier.com/settings/api-keys">A Courier API key</AppLink>

## Run a journey

<Steps>
  <Step title="Invoke a journey">
    Start a run with the invoke endpoint, referencing the journey by its ID or alias in the path.

    * `user_id`, or a `profile` with contact info, for the recipient.
    * `data`, optional, matching the trigger schema.
    * An `Idempotency-Key` header, so a retried request returns the same run instead of starting a second one.

    The response returns a `runId`.

    <CodeGroup>
      ```javascript Node.js theme={null}
      const journeysInvokeResponse = await client.journeys.invoke('welcome-journey', {
        user_id: 'user_123',
        data: { order_id: 'ORD-9042', order_total: 49.99 },
      });
      ```

      ```python Python theme={null}
      journeys_invoke_response = client.journeys.invoke(
          template_id="welcome-journey",
          user_id="user_123",
          data={
              "order_id": "ORD-9042",
              "order_total": 49.99,
          },
      )
      ```

      ```bash cURL theme={null}
      curl -X POST https://api.courier.com/journeys/welcome-journey/invoke \
        -H "Authorization: Bearer $COURIER_API_KEY" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: unique-key-123" \
        -d '{
          "user_id": "user_123",
          "data": { "order_id": "ORD-9042", "order_total": 49.99 }
        }'
      ```

      ```ruby Ruby theme={null}
      journeys_invoke_response = courier.journeys.invoke(
        "welcome-journey",
        user_id: "user_123",
        data: {order_id: "ORD-9042", order_total: 49.99}
      )
      ```

      ```go Go theme={null}
      journeysInvokeResponse, err := client.Journeys.Invoke(
      	context.TODO(),
      	"welcome-journey",
      	courier.JourneyInvokeParams{
      		JourneysInvokeRequest: courier.JourneysInvokeRequestParam{
      			UserID: courier.String("user_123"),
      			Data: map[string]any{
      				"order_id":    "ORD-9042",
      				"order_total": 49.99,
      			},
      		},
      	},
      )
      ```

      ```java Java theme={null}
      JourneyInvokeParams params = JourneyInvokeParams.builder()
          .templateId("welcome-journey")
          .journeysInvokeRequest(JourneysInvokeRequest.builder()
              .userId("user_123")
              .data(JourneysInvokeRequest.Data.builder()
                  .putAdditionalProperty("order_id", JsonValue.from("ORD-9042"))
                  .putAdditionalProperty("order_total", JsonValue.from(49.99))
                  .build())
              .build())
          .build();
      JourneysInvokeResponse journeysInvokeResponse = client.journeys().invoke(params);
      ```

      ```php PHP theme={null}
      $journeysInvokeResponse = $client->journeys->invoke(
        'welcome-journey',
        userID: 'user_123',
        data: ['order_id' => 'ORD-9042', 'order_total' => 49.99],
      );
      ```

      ```csharp C# theme={null}
      JourneyInvokeParams parameters = new()
      {
          TemplateID = "welcome-journey",
          UserID = "user_123",
          Data = new Dictionary<string, JsonElement>()
          {
              { "order_id", JsonSerializer.SerializeToElement("ORD-9042") },
              { "order_total", JsonSerializer.SerializeToElement(49.99) },
          },
      };

      var journeysInvokeResponse = await client.Journeys.Invoke(parameters);
      ```

      ```bash CLI theme={null}
      courier journeys invoke \
        --api-key "$COURIER_API_KEY" \
        --template-id welcome-journey \
        --user-id user_123 \
        --data '{order_id: ORD-9042, order_total: 49.99}'
      ```

      ```text MCP theme={null}
      With Courier MCP, start my welcome-journey for user_123 with the order details.
      ```
    </CodeGroup>
  </Step>

  <Step title="Inspect a run">
    Run inspection is a console view. There is no public endpoint for a run's step-by-step trace. Take the `runId` from the invoke response, open the journey's **Logs** tab, and search for it. The detail view overlays each node's outcome on the graph. Click a node to see its step context: input data, profile, conditions evaluated, and output. See <Doc href="/docs/monitor/journey-metrics">journey metrics & inspection</Doc> for the run states and what each view shows.
  </Step>
</Steps>

## Cancel a run

Cancel in-flight runs with the cancel endpoint. Target either a `cancelation_token`, which cancels every run sharing it, or a single `run_id`. You set the token in the journey's settings, so runs carry it from the moment they start.

<CodeGroup>
  ```javascript Node.js theme={null}
  const cancelJourneyResponse = await client.journeys.cancel({ cancelation_token: 'order-9042-flow' });
  ```

  ```python Python highlight={2} theme={null}
  cancel_journey_response = client.journeys.cancel(
      cancelation_token="order-9042-flow",
  )
  ```

  ```bash cURL highlight={5} theme={null}
  curl -X POST https://api.courier.com/journeys/cancel \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "cancelation_token": "order-9042-flow"
    }'
  ```

  ```ruby Ruby theme={null}
  cancel_journey_response = courier.journeys.cancel(cancel_journey_request: {cancelation_token: "order-9042-flow"})
  ```

  ```go Go highlight={3-4} theme={null}
  cancelJourneyResponse, err := client.Journeys.Cancel(context.TODO(), courier.JourneyCancelParams{
  	CancelJourneyRequest: courier.CancelJourneyRequestUnionParam{
  		OfByCancelationToken: &courier.CancelJourneyRequestByCancelationTokenParam{
  			CancelationToken: "order-9042-flow",
  		},
  	},
  })
  ```

  ```java Java highlight={1-2} theme={null}
  CancelJourneyRequest.ByCancelationToken params = CancelJourneyRequest.ByCancelationToken.builder()
      .cancelationToken("order-9042-flow")
      .build();
  CancelJourneyResponse cancelJourneyResponse = client.journeys().cancel(params);
  ```

  ```php PHP highlight={2} theme={null}
  $cancelJourneyResponse = $client->journeys->cancel(
    cancelationToken: 'order-9042-flow'
  );
  ```

  ```csharp C# highlight={3} theme={null}
  JourneyCancelParams parameters = new()
  {
      CancelJourneyRequest = new ByCancelationToken("order-9042-flow")
  };

  var cancelJourneyResponse = await client.Journeys.Cancel(parameters);
  ```

  ```bash CLI highlight={3} theme={null}
  courier journeys cancel \
    --api-key "$COURIER_API_KEY" \
    --cancelation-token order-9042-flow
  ```
</CodeGroup>

To cancel one run instead, pass the `run_id` from the invoke response in place of `cancelation_token`. <Endpoint method="POST" path="/journeys/cancel" name="Cancel Journey runs" href="/docs/api-reference/journeys/cancel-journey-runs" /> takes exactly one of the two. Sending both or neither returns `400`.

It returns `202` with the run and its resulting status:

| Status      | Meaning                                                    |
| ----------- | ---------------------------------------------------------- |
| `CANCELED`  | The run was active (or already canceled), and is canceled. |
| `PROCESSED` | The run had already finished. Nothing changed.             |
| `ERROR`     | The run had already ended in an error. Nothing changed.    |

Only active runs are affected, so canceling is idempotent and always safe. A `run_id` Courier can't find for your workspace returns `404`. To build the token itself, or to cancel from inside a flow, see the <Doc href="/docs/journeys/nodes/cancel">cancel node</Doc>.
