# STAC Asset Catalog Preflight (`immemorial_sarinda/stac-asset-catalog-preflight`) Actor

Check one supplied STAC 1.1.0 Collection and up to 100 Items for IDs, membership, links, declared extents and asset metadata. Get one complete deterministic report. Restricted declaration profile; no imagery, URL fetching or STAC conformance certification.

- **URL**: https://apify.com/immemorial_sarinda/stac-asset-catalog-preflight.md
- **Developed by:** [Picknotes](https://apify.com/immemorial_sarinda) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$100.00 / 1,000 completed reports

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## STAC Asset Catalog Preflight

Check one supplied STAC 1.1.0 Collection and up to 100 supplied Items in the supported declaration profile. The report checks IDs, membership, links, declared spatial and temporal extents, assets and asset definitions. It does not fetch imagery, URLs or assets; validate asset availability, geometry coordinates or topology; establish license validity, ownership or rights; certify STAC conformance; or assert that supplied Items exhaust the Collection. Unsupported cases produce incomplete reports and cannot be completed deliveries. Complete reports may contain error findings.

### Input

For the built-in example, submit:

```json
{"useDemo": true}
```

Omit catalogJson and omit consent or set it to false in demo mode. For your own data, set useDemo to false, supply catalogJson as the exact original UTF-8 text of an object containing collection and items, and set authorizedNonpersonalNonconfidentialData to true. Submit only authorized, nonpersonal and nonconfidential data. The platform stores input before execution. No confidentiality, retention, deletion, hosting-location or secret-detection guarantee is made.

### Read and save your report

Each completed delivery contains one full thirteen-field dataset item. Its reportJson field contains the complete report as a JSON string. Use the run's dataset output to download the raw JSON export. Do not select fields or enable cleaning, flattening or unwinding. Save the downloaded item or single-item array as item.json.

The following complete Python 3 standard-library recipe saves the exact UTF-8 report bytes without reformatting them. Save it as save_report.py, then run:

```text
python3 -B save_report.py item.json report.json
```

report.json must not already exist. Use a trusted local directory. This recipe checks the report's byte count and SHA-256 against the exported item. It does not validate the full public consistency policy, prove sender authenticity, or prove that the report accurately represents the original input. A sender who changes the report can also change its hash. Review the report before sharing it.

```python
import hashlib
import json
import os
import stat
import sys


def unique_pairs(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("Duplicate JSON key")
        result[key] = value
    return result


def reject_constant(value):
    raise ValueError("Non-finite JSON number")


def main():
    if len(sys.argv) != 3:
        raise ValueError("Usage: save_report.py item.json new-report.json")
    with open(sys.argv[1], "rb") as source:
        if not stat.S_ISREG(os.fstat(source.fileno()).st_mode):
            raise ValueError("Input must be a regular file")
        raw = source.read(8_000_001)
    if len(raw) > 8_000_000:
        raise ValueError("Export exceeds 8 MB; use a single complete item")
    item = json.loads(raw.decode("utf-8"), object_pairs_hook=unique_pairs,
                      parse_constant=reject_constant)
    if type(item) is list:
        if len(item) != 1:
            raise ValueError("Expected exactly one item")
        item = item[0]
    if type(item) is not dict or type(item.get("reportJson")) is not str:
        raise ValueError("Missing reportJson string")
    report = item["reportJson"].encode("utf-8")
    if not 1 <= len(report) <= 4_194_304:
        raise ValueError("Invalid report size")
    if type(item.get("reportBytes")) is not int or item["reportBytes"] != len(report):
        raise ValueError("Report byte count mismatch")
    if type(item.get("reportSha256")) is not str or hashlib.sha256(report).hexdigest() != item["reportSha256"]:
        raise ValueError("Report SHA-256 mismatch")
    json.loads(report.decode("utf-8"), object_pairs_hook=unique_pairs,
               parse_constant=reject_constant)
    with open(sys.argv[2], "xb") as output:
        output.write(report)


if __name__ == "__main__":
    try:
        main()
    except (OSError, ValueError, TypeError, RecursionError) as error:
        print("Report not saved: " + str(error), file=sys.stderr)
        raise SystemExit(2)
```

A separate four-file buyer helper provides additional source-free consistency checks. It is optional; the recipe above needs no helper download. Neither approach proves original-source truth or sender authenticity.

### Limits and uncertain outcomes

Raw input is at most 2 MiB. The report is at most 4 MiB and must also satisfy 4 + inputBytes + reportBytes <= 4,500,000. The escaped full delivery must fit within 4,500,000 bytes. Nothing is truncated. Execution uses a 10-second private-worker deadline and a 50-second outer deadline.

Each completed report costs USD 0.10, including platform usage and reports with findings. A receipt describes the expected identity of the completion event; it is not a payment confirmation or proof of configured billing, a charge or settlement. Check the platform's displayed price and spending limit before running. If a run times out, exits with code 124, or reports an uncertain delivery, inspect its existing dataset and charges before taking any further action. An append may already have succeeded or been billed. Do not automatically repost or rerun it.

# Actor input Schema

## `authorizedNonpersonalNonconfidentialData` (type: `boolean`):

Required to be true when useDemo is false: confirms that you are authorized to submit this catalog and that it contains no personal or confidential data. Omit or set to false in demo mode.

## `catalogJson` (type: `string`):

Own mode only: exact JSON envelope with collection and items. Required with useDemo=false and explicit consent. At most 2 MiB UTF8; no URL fetching. Omit in demo mode.

## `useDemo` (type: `boolean`):

Set to true to use the built-in example; omit catalogJson and omit consent or set it to false. Set to false for your own catalogJson; authorizedNonpersonalNonconfidentialData must then be true.

## Actor input object example

```json
{
  "authorizedNonpersonalNonconfidentialData": false,
  "useDemo": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "useDemo": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("immemorial_sarinda/stac-asset-catalog-preflight").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "useDemo": True }

# Run the Actor and wait for it to finish
run = client.actor("immemorial_sarinda/stac-asset-catalog-preflight").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "useDemo": true
}' |
apify call immemorial_sarinda/stac-asset-catalog-preflight --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,immemorial_sarinda/stac-asset-catalog-preflight"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/CJ4sY048t4MZgGdTe/builds/S1tfdi7MMrmp7qCgB/openapi.json
