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

# Describe Harbor Action

GET https://app.polytomic.com/api/harbors/{harbor_id}/actions/describe

Describe one granted operation and its currently available enabled fields.

Select an identity from [List actions](../../../../../api-reference/harbors/actions/list).
Supply its `connection_id`, `schema_id`, and `operation_id`. Use a scoped
credential belonging to this Harbor; description does not require write access.

`effect` identifies an operation as `read_only` or `mutating`. For read-only
operations, `lookup_fields` and `output_fields` contain only fields both granted
by the administrator and currently available through the Connection.
`input_fields` is empty. Use
[Lookup action](../../../../../api-reference/harbors/actions/lookup) to return one projected
record without preparation.

For mutations, `input_fields` contains only granted, currently available fields.
`lookup_fields` and `output_fields` describe the connector's lookup and output.
Fields retain their types, constraints, required flags, and nullability. Supply
exactly one lookup when `lookup_fields` is nonempty; otherwise omit it. Omitted
input fields remain unchanged. Explicit null requires `nullable: true`.

For mutations, `idempotency` describes remote deduplication, not permission to
retry. Harbor write receipts remain metadata-only.

A provider discovery failure or a granted operation that is no longer available
returns `503 Service Unavailable`, not an empty field list. An ungranted identity
returns `403 Forbidden`. These responses do not revoke saved permissions.
Polytomic checks current grants and provider capabilities again at execution.

Description fetches only the selected object's operations. It does not fetch
fields for the entire catalog. Lookup permissions are checked against fresh
provider metadata. Provider permissions and automation still apply.

Send a new nonzero UUID in `X-Polytomic-Activity-Request-ID`. A supplied
`X-Polytomic-Harbor-Session` must be active and bound to this credential and
Harbor. Successful description is recorded as `action.listed`.

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

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

### Query parameters

- `connection_id` (string, required)
- `schema_id` (string, required)
- `operation_id` (string, required)

### Headers

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

## Response

### 200

OK

- `data` (HarborActionCapability, optional)

## Types

### HarborActionCapability

- `description` (string, optional)
- `effect` (string, optional)
- `idempotency` (SchemaOperationIdempotency, optional)
- `input_fields` (list of HarborActionField, optional, nullable)
- `lookup_fields` (list of HarborActionField, optional, nullable)
- `name` (string, optional)
- `operation_id` (string, optional)
- `output_fields` (list of HarborActionField, optional, nullable)
- `schema_id` (string, optional)

### SchemaOperationIdempotency

- `retention_ns` (long, optional)
- `scope` (string, optional)

### HarborActionField

- `definition` (TypesDefinition, optional) — Detailed field type: a type name such as "bigint", or an array naming a complex type followed by its details, such as \["decimal", \{"precision": 10, "scale": 2}] or \["array", "string"].
- `description` (string, optional)
- `id` (string, optional)
- `max_bytes` (integer, optional)
- `name` (string, optional)
- `non_blank` (boolean, optional)
- `nullable` (boolean, optional)
- `pattern` (string, optional)
- `required` (boolean, optional)
- `type` (enum, optional)
  - Allowed values: `unknown`, `string`, `number`, `boolean`, `datetime`, `array`, `object`, `binary`
- `values` (list of CompletionValue, optional)

### TypesDefinition

Detailed field type: a type name such as "bigint", or an array naming a complex type followed by its details, such as \["decimal", \{"precision": 10, "scale": 2}] or \["array", "string"].

### CompletionValue

- `depends_on` (map from string to string, optional)
- `label` (string, optional, nullable)
- `path` (string, optional, nullable)
- `value` (any, optional)

## Examples

**Response**

```json
{
  "data": {
    "description": "string",
    "effect": "string",
    "idempotency": {
      "retention_ns": 1,
      "scope": "string"
    },
    "input_fields": [
      {
        "definition": "binary",
        "description": "string",
        "id": "string",
        "max_bytes": 1,
        "name": "string",
        "non_blank": true,
        "nullable": true,
        "pattern": "string",
        "required": true,
        "type": "unknown",
        "values": [
          {
            "depends_on": {},
            "label": "string",
            "path": "string"
          }
        ]
      }
    ],
    "lookup_fields": [
      {
        "definition": "binary",
        "description": "string",
        "id": "string",
        "max_bytes": 1,
        "name": "string",
        "non_blank": true,
        "nullable": true,
        "pattern": "string",
        "required": true,
        "type": "unknown",
        "values": [
          {
            "depends_on": {},
            "label": "string",
            "path": "string"
          }
        ]
      }
    ],
    "name": "string",
    "operation_id": "string",
    "output_fields": [
      {
        "definition": "binary",
        "description": "string",
        "id": "string",
        "max_bytes": 1,
        "name": "string",
        "non_blank": true,
        "nullable": true,
        "pattern": "string",
        "required": true,
        "type": "unknown",
        "values": [
          {
            "depends_on": {},
            "label": "string",
            "path": "string"
          }
        ]
      }
    ],
    "schema_id": "string"
  }
}
```

**SDK Code**

```python
import requests

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

querystring = {"connection_id":"248df4b7-aa70-47b8-a036-33ac447e668d","operation_id":"operation_id","schema_id":"schema_id"}

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

```javascript
const url = 'https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/describe?connection_id=248df4b7-aa70-47b8-a036-33ac447e668d&operation_id=operation_id&schema_id=schema_id';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

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"
	"net/http"
	"io"
)

func main() {

	url := "https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/describe?connection_id=248df4b7-aa70-47b8-a036-33ac447e668d&operation_id=operation_id&schema_id=schema_id"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	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/describe?connection_id=248df4b7-aa70-47b8-a036-33ac447e668d&operation_id=operation_id&schema_id=schema_id")

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

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

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.get("https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/describe?connection_id=248df4b7-aa70-47b8-a036-33ac447e668d&operation_id=operation_id&schema_id=schema_id")
  .header("Authorization", "Bearer <token>")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/describe?connection_id=248df4b7-aa70-47b8-a036-33ac447e668d&operation_id=operation_id&schema_id=schema_id', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/describe?connection_id=248df4b7-aa70-47b8-a036-33ac447e668d&operation_id=operation_id&schema_id=schema_id");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://app.polytomic.com/api/harbors/248df4b7-aa70-47b8-a036-33ac447e668d/actions/describe?connection_id=248df4b7-aa70-47b8-a036-33ac447e668d&operation_id=operation_id&schema_id=schema_id")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

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()
```