> This page is for version 2025-09-18 (default).
> For other versions, use one of these documentation indexes:
> - 2025-09-18 (default): https://apidocs.polytomic.com/2025-09-18/llms.txt
> - 2024-02-08: https://apidocs.polytomic.com/2024-02-08/llms.txt
> - 2023-04-25: https://apidocs.polytomic.com/2023-04-25/llms.txt
> - 2022-12-12: https://apidocs.polytomic.com/2022-12-12/llms.txt
> - 2021-05-23: https://apidocs.polytomic.com/2021-05-23/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://apidocs.polytomic.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://apidocs.polytomic.com/_mcp/server.

# Prepare Harbor Action

POST https://app.polytomic.com/api/harbors/{harbor_id}/actions/prepare
Content-Type: application/json

Validate and prepare an enabled action without executing it, returning a server-issued execution identifier.

Use a writable scoped credential belonging to this Harbor. An administrator must
first enable the destination Connection, operation, and input fields. Select an
identity with [List actions](../../../../../api-reference/harbors/actions/list), then inspect
its fields with [Describe action](../../../../../api-reference/harbors/actions/describe).

Preparation validates and temporarily stores the exact destination, lookup, and
input. It returns a server-generated `execution_id` and `expires_at`. You do not
supply an execution UUID. Preparation neither performs nor approves a destination
mutation. Call [Execute action](../../../../../api-reference/harbors/actions/execute) with only
the returned identifier within 15 minutes. Polytomic checks current permissions,
provider capabilities, and the saved Connection again at execution.

Supply one advertised lookup when `lookup_fields` is nonempty. Otherwise omit
`lookup`. Omitted input fields remain unchanged. Explicit `null` requires
`nullable: true`. Empty and blank strings follow the advertised constraints.
Values are JSON scalars; arrays, nested objects, and type coercion are unsupported.
Numbers must use integer JSON notation, without a decimal point or exponent, and
lie between -9007199254740991 and 9007199254740991. Preserve opaque IDs as strings.
Unknown envelope properties, duplicate keys, invalid Unicode, trailing JSON, and
bodies larger than 256 KiB are rejected.

## Lifetime and recovery

Prepared arguments are fixed for that identifier. Polytomic removes them when
execution is claimed and periodically cleans up expired, unexecuted preparations.
Execution receipts and Activity event metadata contain no submitted values.
Polytomic retains a separate encrypted copy of the target and submitted values
for 90 days from preparation. Only Organization administrators can reveal these
details in the audit ledger. MCP receipts do not expose them. This evidence
records your request, not a verified before-and-after record state.
Preparation alone does not create an execution receipt.

If the preparation response is lost, you may prepare again: no destination
mutation occurred. Each preparation creates a distinct execution identifier.

> ⚠️ Preserve the identifier after execution
>
> After submitting an execution, use its original `execution_id` to investigate
> an uncertain outcome. Do not prepare a replacement action to retry it.

Send a new nonzero UUID in `X-Polytomic-Activity-Request-ID` for each HTTP request.
MCP supplies this transport header automatically. `X-Polytomic-Harbor-Session` is
optional for direct REST requests; a supplied session must be active and bound
to your credential and Harbor. Preparation is recorded as `action.prepared`,
with its original actor and execution identifier. Expired, unexecuted
preparations are recorded as `action.preparation_expired`. Execution records its
own actor and attempt separately.

Reference: https://apidocs.polytomic.com/api-reference/harbors/actions/prepare

## Authentication

- `Authorization` header (bearer token, required) — Bearer user API key
- `Authorization` header (basic auth, required) — Basic organization-scoped API key

## Request

### Path parameters

- `harbor_id` (string, required) — Unique identifier of the Harbor.

### Headers

- `X-Polytomic-Harbor-Session` (string, optional)
- `X-Polytomic-Activity-Request-ID` (string, optional)

### Body (application/json)

This endpoint expects a PrepareHarborActionRequest.

- `connection_id` (string, required) — Explicit destination connection ID from action discovery. Must have this action and its submitted fields enabled in this Harbor.
- `input` (map from string to any, required)
- `operation_id` (string, required) — Exact operation_id from action discovery.
- `schema_id` (string, required) — Exact schema_id from action discovery.
- `lookup` (ActionLookup, optional)

## Response

### 200

OK

- `data` (HarborActionPreparation, optional)

## Types

### ActionLookup

- `field_id` (string, optional)
- `value` (any, optional)

### HarborActionPreparation

- `execution_id` (string, optional)
- `expires_at` (datetime, optional)

## Examples

**Request**

```json
{
  "connection_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
  "operation_id": "string",
  "schema_id": "string"
}
```

**Response**

```json
{
  "data": {
    "execution_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
    "expires_at": "2024-01-15T09:30:00Z"
  }
}
```

**SDK Code**

```python
import requests

url = "https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare"

payload = {
    "connection_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
    "operation_id": "string",
    "schema_id": "string"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"connection_id":"248df4b7-aa70-47b8-a036-33ac447e668d","operation_id":"string","schema_id":"string"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare"

	payload := strings.NewReader("{\n  \"connection_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\",\n  \"operation_id\": \"string\",\n  \"schema_id\": \"string\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"connection_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\",\n  \"operation_id\": \"string\",\n  \"schema_id\": \"string\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"connection_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\",\n  \"operation_id\": \"string\",\n  \"schema_id\": \"string\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare', [
  'body' => '{
  "connection_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
  "operation_id": "string",
  "schema_id": "string"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"connection_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\",\n  \"operation_id\": \"string\",\n  \"schema_id\": \"string\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "connection_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
  "operation_id": "string",
  "schema_id": "string"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/prepare")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```