---
title: "Remember that external work has been PREPARED for this action (for example a Gmail draft was created). Does not change the action's lifecycle, status or expected_signal_at. Re-posting the same externalSource + externalDraftId returns the existing record with duplicate_preparation_rejected: true instead of creating a second one."
method: POST
path: "/actions/{id}/preparations"
---

# Remember that external work has been PREPARED for this action (for example a Gmail draft was created). Does not change the action's lifecycle, status or expected_signal_at. Re-posting the same externalSource + externalDraftId returns the existing record with duplicate_preparation_rejected: true instead of creating a second one.

`POST /actions/{id}/preparations`

## Request

- Base URL: `https://forbiz.io/api/public/agent`
- URL: `https://forbiz.io/api/public/agent/actions/{id}/preparations`
- Auth: HTTP bearer

## Path parameters

- `id` string, required

## Headers

- `Idempotency-Key` string

## Request body

- PreparationInput
  - `externalSource` string, required: For example 'gmail'.
  - `externalDraftId` string: Stable external id; guarantees the same draft is never remembered twice.
  - `externalThreadId` string
  - `channel` 'email' | 'phone' | 'linkedin' | 'meeting' | 'other'
  - `campaignTargetId` string
  - `outreachId` string
  - `recipientSnapshot` string
  - `subjectSnapshot` string
  - `bodySnapshot` string: Hashed for comparison; the hash is stored, not required from the caller.
  - `preparedAt` string, date-time
  - `evidenceId` string
  - `note` string

## Response `200`

Duplicate external draft; nothing created

- PreparationEnvelope
  - `ok` boolean
  - `owner` Owner: Ownership of the record. Never means the performer of an operation — use /actions/{id}/history for actor semantics.
    - `type` 'human'
    - `user_id` string: Owning Forbiz user. Action payloads never repeat raw ownership UUIDs.
    - `workspace_id` string, nullable
    - `note` string
  - `preparation` Preparation: External work that exists but has NOT been sent. prepared_at is when the draft existed, executed_at is when it actually left the external system, recorded_at is when Forbiz learned about it.
    - `id` string
    - `action_id` string
    - `outreach_id` string, nullable
    - `campaign_target_id` string, nullable
    - `channel` 'email' | 'phone' | 'linkedin' | 'meeting' | 'other'
    - `external_source` string
    - `external_draft_id` string, nullable
    - `external_thread_id` string, nullable
    - `recipient_snapshot` string, nullable
    - `subject_snapshot` string, nullable
    - `status` 'prepared' | 'executed' | 'superseded' | 'discarded'
    - `prepared_at` string, date-time
    - `executed_at` string, date-time, nullable
    - `recorded_at` string, date-time
  - `duplicate_preparation_rejected` boolean
  - `action_unchanged` object

## Other responses

- `201`: Preparation created
- `208`: Idempotent replay of a previous request with the same Idempotency-Key. Nothing was applied again.
- `404`: Not found

---

[API](https://skmtc.dev/forbiz/apis/forbiz-external-agent-api.md) · [All operations](https://skmtc.dev/forbiz/apis/forbiz-external-agent-api/llms.txt) · [OpenAPI document](https://skmtc.dev/forbiz/apis/forbiz-external-agent-api/revisions/e5b10d59dc5f?raw)
