# API Origin Health Report - is this API alive, and paid? (`vital_tuxedo/api-origin-health-report`) Actor

Bulk due-diligence on API origins. One row per URL: a liveness verdict from a closed set (LIVE, PAUSED, GATED, CHALLENGED, DEGRADED, DEAD, UNKNOWN), a confidence, coded reasons, the origin reached after redirects, the RFC 9309 robots disposition, any payment rail on the wire, catalogue surfaces.

- **URL**: https://apify.com/vital\_tuxedo/api-origin-health-report.md
- **Developed by:** [Stephen Psaradellis](https://apify.com/vital_tuxedo) (community)
- **Categories:** Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## API Origin Health Report

**Is this API alive, and does it actually take money?** Give it a list of API
origins. Get back one row each: a verdict, the evidence behind it, and the
sources that evidence came from.

Built for the moment before you commit: you are choosing between four vendors,
inheriting a service catalogue nobody has audited, or checking whether the 200
integrations in your `.env` are all still there.

### What one row tells you

| field | what it is |
|---|---|
| `verdict` | `LIVE`, `PAUSED`, `GATED`, `CHALLENGED`, `DEGRADED`, `DEAD` or `UNKNOWN`. A closed set — never a score out of 100 |
| `confidence` | how much of the evidence the verdict rests on |
| `reasons` | coded reasons, each naming the **source** that produced it |
| `origin_measured` | the scheme and host actually reached, after redirects — often not the one you submitted |
| `final_url` | where the primary GET ended up |
| `http_status` | the status of that GET |
| `robots` | `allowed`, `disallowed` or `unknown`, matched under RFC 9309 |
| `payment` | any payment rail the origin advertises on the wire (a `402` with an `accepts` array, an x402 well-known), or `null` |
| `surfaces` | five catalogue paths — `/openapi.json`, `/api/v1/services`, `/api/v1/discover`, `/discover`, `/.well-known/x402` — each with its status and counts of JSON rows, priced rows and payee-naming rows |
| `warranty` | what the row does and does not claim |

### The two modes

**Full report** — robots, the primary GET, up to 3 of the health sidecars a service may publish
(`/health`, `/healthz`, `/api/health`, `/api/v1/health`, `/status`,
`/.well-known/health`) and the 5 catalogue surfaces. About 10 requests per
origin. Use it on a shortlist.

**Liveness only** — robots and the primary GET. About 2 requests. Use it to
sweep a long list and then re-run the interesting rows as full reports.

### What it will not do

- **It will not invent uptime.** One read at one moment is one read at one
  moment. There is no rolling availability figure here, because we did not
  measure one.
- **It will not give advice or a grade.** Verdicts and counts, with sources.
  What that means for your vendor choice is yours.
- **It will not ignore robots.txt.** With *Respect robots.txt* on (the
  default), a URL the origin disallows for this user agent is reported as
  skipped, no request is made to it, and **you are not charged for it**. The
  match is RFC 9309, so `*` and `$` mean what the publisher meant by them —
  not the `startswith` comparison the Python standard library still does,
  which silently passes exactly the paths a site wrote down to forbid.
- **It will not pad a partial answer.** An unreadable `robots.txt` is
  `unknown`, never `allowed`. An origin the input cap stranded is reported as
  stranded, not guessed.

### Pricing

| event | price | when |
|---|---|---|
| `origin-report` | **$0.50** | one origin measured in full |
| `origin-liveness` | **$0.01** | one origin measured in liveness mode |

**You are not charged** for a URL skipped by robots.txt, a URL stranded beyond
`maxOrigins`, an entry that is not a parseable URL, or a duplicate. And an
origin that **does not resolve** is billed at the liveness price, not the
report price — the report's other nine requests never happened, so you do not
pay for them.

No start fee. Starting the Actor with no input at all measures nothing and
costs nothing.

### Input

```json
{
  "origins": ["https://api.github.com", "httpbin.org", "https://api.stripe.com"],
  "mode": "report",
  "respectRobots": true,
  "maxOrigins": 100,
  "concurrency": 8
}
```

`maxOrigins` is capped at 5000, which is also the largest a single run can
bill: 5000 × $0.50 = $2500.

### Where this comes from

This Actor is not a re-implementation of something. It runs `liveness.py`,
the instrument behind a working paid API that has been serving this exact
report — the same verdict set, the same reason codes, the same catalogue
sweep — on its own metered route. That file is vendored here byte for byte
and pinned to its source by a test, so the two cannot drift.

The reason it is on Apify Store is plainer than it sounds: the API sold this
report to software agents, and software agents did not buy it — over 3,600
price quotes and one sale. So the same measurement is offered to the people who
were going to have to make the vendor decision anyway.

Independent of any venue, and stated up front: this is a **measurement
instrument**, not a monitoring product. If you need alerting, a status page or
an SLA, buy one of those. If you need to know what 500 API origins are
actually doing right now, with the evidence attached, this is that.

# Actor input Schema

## `origins` (type: `array`):

The URLs to measure, one per line. A bare host is read as https. Duplicates are collapsed on the trailing slash and charged once. Deliberately has no schema default: an Actor started with no input at all must measure nothing and bill nothing, and an absent input lands on the schema's default when there is one (ops:an\_absent\_input\_is\_not\_the\_schemas\_default).

## `mode` (type: `string`):

report: the full read - robots, the primary GET, up to 3 health sidecars and 5 catalogue surfaces, about 10 requests per origin. liveness: robots and the primary GET only, about 2 requests, for sweeping a long list cheaply.

## `respectRobots` (type: `boolean`):

On: a URL the origin's robots.txt disallows for this user agent is reported as skipped, no request is made to it, and it is not charged. The match is RFC 9309, so \* and $ mean what the publisher meant by them. An unreadable robots.txt is recorded as unknown and does not block.

## `maxOrigins` (type: `integer`):

Hard cap on how many origins one run measures, after de-duplication. URLs beyond it are reported in the run summary as stranded and are charged nothing. 5000 is the actor's own ceiling.

## `concurrency` (type: `integer`):

How many origins are measured at once.

## Actor input object example

```json
{
  "origins": [
    "https://api.apis.guru",
    "https://api.github.com",
    "https://httpbin.org"
  ],
  "mode": "report",
  "respectRobots": true,
  "maxOrigins": 100,
  "concurrency": 8
}
```

# Actor output Schema

## `rows` (type: `string`):

One row per origin: verdict, confidence, reasons, robots, payment rails and catalogue surfaces.

## `runSummary` (type: `string`):

Counts for the run: submitted, measured, skipped by robots, stranded over the cap, charged events and the verdict histogram.

# 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 = {
    "origins": [
        "https://api.apis.guru",
        "https://api.github.com",
        "https://httpbin.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vital_tuxedo/api-origin-health-report").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 = { "origins": [
        "https://api.apis.guru",
        "https://api.github.com",
        "https://httpbin.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("vital_tuxedo/api-origin-health-report").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 '{
  "origins": [
    "https://api.apis.guru",
    "https://api.github.com",
    "https://httpbin.org"
  ]
}' |
apify call vital_tuxedo/api-origin-health-report --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vital_tuxedo/api-origin-health-report"
        }
    }
}

```

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/XILpMxp4Xx5oROscI/builds/lHv7Cdx1Y883Dglla/openapi.json
