> 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.

# Execute Harbor Action

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

Execute a prepared action with at most one application attempt per server-issued execution identifier.

First call [Prepare action](../../../../../api-reference/harbors/actions/prepare). Submit only
its server-issued `execution_id` using a writable scoped credential belonging to
the same Harbor. The destination, operation, lookup, and input are fixed by
preparation. No per-request approval is required.

Polytomic checks current grants, provider capabilities, and the saved Connection
again before execution. Preparation does not reserve permission. An expired
preparation cannot start an execution. It returns `410 Gone` while the expired
preparation remains available, or `404 Not Found` after cleanup.

> 🚧 Updates can overwrite intervening edits
>
> Enabled operations can act on records accessible through the saved Connection
> and may trigger provider automation. Preparation does not lock the destination
> record. Action permission does not grant read access.

## One intended attempt

An identifier already claimed for execution returns its original receipt,
including through another eligible credential or after action disablement.
Receipts remain available after prepared arguments are removed or expire.
They are retained independently of Activity history.

An `action.attempt_started` event means permission to attempt the action was
claimed, not that the provider received it. Disabling actions blocks new claims
but does not recall an accepted attempt. This is at most one application attempt
per execution identifier, not a remote exactly-once guarantee. Advertised remote
idempotency does not authorize automatic replay.

## Results and recovery

Keep `execution_id` and the returned `status_path`. `succeeded` means the provider
confirmed the operation and Polytomic recorded that outcome. `failed` means the
operation was rejected. `executing` is incomplete. `recovery_required: true`
does not confirm durable acceptance or completion. Use the status path after a
timeout or server error. A missing receipt does not prove no operation occurred.

> ⚠️ An unknown outcome is terminal
>
> `unknown` means the operation may have happened. Investigate the record and
> provider automation. Do not resubmit or prepare a replacement action to retry.
> Polytomic never automatically retries an uncertain attempt. An overdue
> executing receipt becomes unknown after its 90-second deadline.

Send a separate 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. Receipts and
Activity contain operation identity, lookup field names, submitted field names,
original attribution, and safe outcome categories. They exclude lookup values,
input values, output payloads, and raw provider errors.

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

## 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 an ExecuteHarborActionRequest.

- `execution_id` (string, required) — Server-issued identifier returned by prepare. Preserve it for status recovery; never prepare a replacement to retry uncertainty.

## Response

### 200

OK

- `data` (HarborActionExecutionResponse, optional)

## Types

### HarborActionExecutionResponse

- `connection_id` (string, optional)
- `credential_id` (string, optional) — Original credential attribution, including when another credential submits a duplicate.
- `deadline_at` (datetime, optional)
- `execution_id` (string, optional)
- `failure_category` (string, optional)
- `field_ids` (list of string, optional, nullable) — Submitted field names only, never their values.
- `finished_at` (datetime, optional, nullable)
- `lookup_field_id` (string, optional)
- `operation_id` (string, optional)
- `recovery_required` (boolean, optional) — True when receipt persistence was interrupted or uncertain. Inspect status; this response does not confirm durable acceptance or completion.
- `schema_id` (string, optional)
- `started_at` (datetime, optional)
- `status` (enum, optional)
  - Allowed values: `executing`, `succeeded`, `failed`, `unknown`
- `status_path` (string, optional)

## Examples

**Request**

```json
{
  "execution_id": "248df4b7-aa70-47b8-a036-33ac447e668d"
}
```

**Response**

```json
{
  "data": {
    "connection_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
    "credential_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
    "deadline_at": "2024-01-15T09:30:00Z",
    "execution_id": "248df4b7-aa70-47b8-a036-33ac447e668d",
    "failure_category": "string",
    "field_ids": [
      "string"
    ],
    "finished_at": "2024-01-15T09:30:00Z",
    "lookup_field_id": "string",
    "operation_id": "string",
    "recovery_required": true,
    "schema_id": "string",
    "started_at": "2024-01-15T09:30:00Z",
    "status": "executing",
    "status_path": "string"
  }
}
```

**SDK Code**

```python
import requests

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

payload = { "execution_id": "248df4b7-aa70-47b8-a036-33ac447e668d" }
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/execute';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"execution_id":"248df4b7-aa70-47b8-a036-33ac447e668d"}'
};

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/execute"

	payload := strings.NewReader("{\n  \"execution_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\"\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/execute")

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  \"execution_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\"\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/execute")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"execution_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\"\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/execute', [
  'body' => '{
  "execution_id": "248df4b7-aa70-47b8-a036-33ac447e668d"
}',
  '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/execute");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"execution_id\": \"248df4b7-aa70-47b8-a036-33ac447e668d\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["execution_id": "248df4b7-aa70-47b8-a036-33ac447e668d"] 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/execute")! 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()
```