# Step Outputs

[Actions](https://prismatic.io/docs/custom-connectors/actions.md) and [Triggers](https://prismatic.io/docs/custom-connectors/triggers.md) can return a variety of data types. To return a simple string, number, boolean, array, or object your return block can read:

```typescript
// return a string:
return {
  data: "some string",
};
// return a number:
return {
  data: 123.45,
};
// return a boolean:
return {
  data: true,
};
// return an array:
return {
  data: [1, 2, 3, 4, "a", "b"],
};
// return an object:
return {
  data: {
    key1: "value1",
    key2: ["value2", 123],
  },
};

```

Those values can be used as inputs in subsequent steps by referencing this step's `results`:

![Step results from an action in Prismatic app](/docs/assets/images/step-results-de709fdd89c75df85d74a5fca27694f8.png)

If you'd like to return binary data (for example, a PDF file), see [Returning binary data from an action](https://prismatic.io/docs/custom-connectors/binary-files.md#returning-binary-data-from-an-action).

## Example payloads[​](#example-payloads "Direct link to Example payloads")

Your custom trigger or action's results can be used as [inputs](https://prismatic.io/docs/custom-connectors/inputs.md) for subsequent steps. But, until the action is executed, the actual results are not available. As an integration builder or as one of your customers' [embedded workflow builder](https://prismatic.io/docs/embed/workflow-builder.md) users, you may want to add several steps to your workflow without having to run your entire workflow after adding each step.

Your action can provide an example payload in a number of ways that allow your end users to build their workflows faster.

### Selecting an example payload in the integration designer[​](#selecting-an-example-payload-in-the-integration-designer "Direct link to Selecting an example payload in the integration designer")

As an organization user in the integration designer, you can select which step result type you'd like to reference as you map step results to inputs. Depending on what are defined for the action, you can select from:

* A recent test run
* A stand-alone step result from an out-of-band `perform` or `examplePerform` invocation
* Sample data from output schema or example payload

![Selecting an example payload in the integration designer](/docs/assets/images/example-reference-selector-92aded6e006564619cd670e3b488b1b9.png)

### Example payloads in the embedded workflow builder[​](#example-payloads-in-the-embedded-workflow-builder "Direct link to Example payloads in the embedded workflow builder")

Your customers using the embedded workflow builder will be presented the best example possible based on recent executions and what example data is available. The embedded workflow builder will present a step result based on this logic:

<!-- -->

### Safely running the perform function[​](#safely-running-the-perform-function "Direct link to Safely running the perform function")

**When to use:** If your action is non-destructive (does not modify data), and you set `performSafety` to `'safe'`, the integration designer and embedded workflow builder will invoke your `perform` function outside of an execution to provide example data.

The best data your component can yield is real data. With real data, your customer can be guaranteed to be presented with an accurate shape of the step's return value. For example, if they have custom fields associated with a certain record type in a CRM, the real data will include those custom fields.

Note: your reference step must be fully configured with a valid connection.

Run perform function safely

```typescript
action({
  display: {
    label: "Fetch a Record",
    description: "Fetch a record from Acme",
  },
  inputs: {
    connection: input({
      label: "Connection",
      type: "connection",
      required: true,
    }),
    recordId: input({
      label: "Record ID",
      type: "string",
      required: true,
    }),
  },
  perform: async (context, inputs) => {
    const record = await fetchRecord({
      recordId: inputs.recordId,
      apiKey: inputs.connection.fields.apiKey,
    });
    return { data: record };
  },
  performSafety: "safe",
});

```

### `examplePerform`[​](#exampleperform "Direct link to exampleperform")

**When to use:** If your action mutates data (creates, updates, or deletes data), but you still want to provide real data for example purposes, you can define an `examplePerform` function.

Similar to a `perform` function, the `examplePerform` function is defined on the action and is invoked outside of execution when the step is referenced if it is defined, the step is fully configured (including any connections).

Run examplePerform function

```typescript
action({
  display: {
    label: "Update a Record",
    description: "Update a record in Acme",
  },
  inputs: {
    connection: input({
      label: "Connection",
      type: "connection",
      required: true,
    }),
    recordId: input({
      label: "Record ID",
      type: "string",
      required: true,
    }),
    name: input({ label: "Name", type: "string" }),
    email: input({ label: "Email", type: "string" }),
    companyId: input({ label: "Company ID", type: "string" }),
  },
  perform: async (context, inputs) => {
    const record = await updateRecord({
      recordId: inputs.recordId,
      apiKey: inputs.connection.fields.apiKey,
      newData: {
        name: inputs.name,
        email: inputs.email,
        companyId: inputs.companyId,
      },
    });
    return { data: record };
  },
  examplePerform: async (context, inputs) => {
    const record = await fetchRecord({
      recordId: inputs.recordId,
      apiKey: inputs.connection.fields.apiKey,
    });
    // Return the record, simulating an update to fields that changed
    return {
      data: {
        ...record,
        ...(inputs.name ? { name: inputs.name } : {}),
        ...(inputs.email ? { email: inputs.email } : {}),
        ...(inputs.companyId ? { companyId: inputs.companyId } : {}),
      },
    };
  },
});

```

### Static output schema[​](#static-output-schema "Direct link to Static output schema")

**When to use:** you know the shape of the data your action will return, and would like the workflow builder to yield lorem ipsum data based on that shape. Output schema is particularly useful when consumed by the embedded workflow builder [AI Copilot](https://prismatic.io/docs/embed/workflow-builder/ai-copilot.md) since it provides clear guidance on the structure of the data that will flow through the workflow, including which return fields to expect all the time and which return fields are optional.

The step does not need to be fully configured to yield an example based on output schema.

Static output schema

```typescript
action({
  display: {
    label: "Fetch a Record",
    description: "Fetch a record from Acme",
  },
  inputs: {
    connection: input({
      label: "Connection",
      type: "connection",
      required: true,
    }),
    recordId: input({
      label: "Record ID",
      type: "string",
      required: true,
    }),
  },
  perform: async (context, inputs) => {
    const record = await fetchRecord({
      recordId: inputs.recordId,
      apiKey: inputs.connection.fields.apiKey,
    });
    return { data: record };
  },
  outputSchema: {
    type: "actionOutput",
    schema: {
      type: "object",
      properties: {
        person: {
          type: "object",
          properties: {
            first: { type: "string" },
            last: { type: "string" },
          },
          required: ["last"], // Only last name is guaranteed
        },
        age: { type: "number", minimum: 0, maximum: 123 },
      },
      required: ["person", "age"],
    },
  },
});

```

### Static example payload[​](#static-example-payload "Direct link to Static example payload")

**When to use:** you know the shape of the result of your action and would like to provide your own example data.

Include an example payload in addition to other example sources

We recommend that you include an `examplePayload` in addition to other example strategies (like setting `performSafety` to `'safe'` or defining an `examplePerform` function). That way, if the step is not fully configured and cannot be run outside of an execution, the reference picker has something to fall back on.

Static example payload

```typescript
action({
  display: {
    label: "Fetch a Record",
    description: "Fetch a record from Acme",
  },
  inputs: {
    connection: input({
      label: "Connection",
      type: "connection",
      required: true,
    }),
    recordId: input({
      label: "Record ID",
      type: "string",
      required: true,
    }),
  },
  perform: async (context, inputs) => {
    const record = await fetchRecord({
      recordId: inputs.recordId,
      apiKey: inputs.connection.fields.apiKey,
    });
    return { data: record };
  },
  examplePayload: {
    data: {
      person: {
        first: "John",
        last: "Doe",
      },
      age: 20,
    },
  },
});

```

**Note:** your `examplePayload` must match the exact TypeScript type of the return value of your `perform` function. If your `perform` function's return value does not match the type of the example payload, TypeScript will generate a helpful error message:

![Example Result Data Type Mismatch in Typescript](/docs/assets/images/example-result-data-type-mismatch-452b765b9db0b37daa9a6d365e260e6b.png)
