# Schedule standby delivery (`honzakirchner/schedule-standby-delivery`) Actor

Actor helps to deliver a webhook from Apify schedule

- **URL**: https://apify.com/honzakirchner/schedule-standby-delivery.md
- **Developed by:** [Jan Kirchner](https://apify.com/honzakirchner) (community)
- **Categories:** Automation
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

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

Schedule Standby Delivery is a tiny Actor with one job: **POST a JSON payload to a URL you configure**, authenticated with a shared secret. Point an Apify schedule at it and it becomes a cron trigger for any HTTP endpoint — a standby Actor, an internal API, a webhook receiver.

### What does Schedule Standby Delivery do?

It takes three things — a **target URL**, a **JSON payload**, and a **secret** — and sends the payload to the URL as an HTTP POST with `Content-Type: application/json`. The secret goes out in the `Authorization: Bearer <secret>` header so the receiving endpoint can reject anything that is not from you. The body also carries a `_apifyRun` object describing the run that sent it, including the **ID of the schedule that triggered it**. The status, headers, and body of the response are stored in the run's key-value store and dataset, so every scheduled delivery leaves an auditable record.

Running it on the Apify platform gives you scheduling, run history, retries, alerting, and API access without hosting a cron job yourself.

### Why use Schedule Standby Delivery?

- **Wake up a standby Actor on a schedule.** Apify schedules start Actor runs; they do not send HTTP requests. This Actor bridges the gap.
- **Trigger any webhook on a cron.** Nightly reindex, hourly cache warm-up, weekly report generation — anything behind an HTTP endpoint.
- **Keep the secret out of the schedule config.** The secret is a secret input field: it is encrypted at rest and censored in the Console.
- **A schedule that never looks broken.** A rejected or unreachable endpoint is recorded as a failed delivery, not as a failed run, so your run history stays readable and alerting stays under your control.

### How to use Schedule Standby Delivery

1. Open the Actor's **Input** tab.
2. Fill in the **Target URL** you want to call.
3. Paste the **JSON payload** the endpoint expects (leave it as `{}` if the call itself is the signal).
4. Enter the **Secret** your endpoint checks for.
5. Click **Start** to test it once, then create a **Schedule** with the same input to run it periodically.

### Input

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `url` | string | yes | — | Absolute `http(s)` URL the payload is POSTed to. |
| `payload` | object | no | `{}` | JSON object sent as the request body. |
| `secret` | string (secret) | yes | — | Sent verbatim as `Authorization: Bearer <secret>`. |
| `maxRetries` | integer | no | `3` | Extra attempts after the first one. |

Each attempt times out after 120 seconds.

```json
{
    "url": "https://my-actor.apify.actor/deliver",
    "payload": { "repositoryUrl": "https://github.com/owner/repo", "mode": "nightly" },
    "secret": "<your secret>",
    "maxRetries": 3
}
```

### What the receiver gets

The request body is the payload you configured, plus one reserved key, `_apifyRun`, holding what the platform knows about the run that sent it. The input above is delivered as:

```json
{
    "repositoryUrl": "https://github.com/owner/repo",
    "mode": "nightly",
    "_apifyRun": {
        "origin": "SCHEDULER",
        "runId": "aBc123XyZ",
        "scheduleId": "sChEd123",
        "scheduledAt": "2026-08-19T02:00:00.000Z"
    }
}
```

| Field | Description |
| --- | --- |
| `origin` | How the run started: `SCHEDULER` for a scheduled run, `WEB` for a manual one, `API`, `CLI`, … |
| `runId` | ID of the run that sent the request. Useful for correlating the receiver's logs with the run log. |
| `scheduleId` | ID of the schedule that triggered the run. **Absent when no schedule triggered it.** |
| `scheduledAt` | ISO timestamp of when the schedule fired. Absent along with `scheduleId`. |

Fields the platform did not report are left out rather than sent as `null`, so a receiver can treat "has a `scheduleId`" as "this was a scheduled delivery". Reading them costs one API call before the delivery; if that call fails, the payload is still delivered and `_apifyRun` carries only what was already known.

`_apifyRun` is reserved: a payload key of the same name is replaced by the real run metadata. Every other payload key is passed through untouched at the top level, so a receiver that ignores `_apifyRun` needs no changes.

### Output

The result is written to the `OUTPUT` record of the default key-value store and pushed to the default dataset. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
{
    "url": "https://my-actor.apify.actor/deliver",
    "ok": true,
    "requestBodyBytes": 74,
    "runMeta": {
        "origin": "SCHEDULER",
        "runId": "aBc123XyZ",
        "scheduleId": "sChEd123",
        "scheduledAt": "2026-08-19T02:00:00.000Z"
    },
    "attempts": [{ "attempt": 1, "status": 200, "durationMillis": 412 }],
    "response": {
        "status": 200,
        "statusText": "OK",
        "headers": { "content-type": "application/json" },
        "body": "{\"accepted\":true}"
    },
    "finishedAt": "2026-08-10T02:00:00.412Z"
}
```

| Field | Description |
| --- | --- |
| `url` | The URL that was called. |
| `ok` | `true` when the endpoint answered with a 2xx status. |
| `requestBodyBytes` | Size of the JSON body that was sent. |
| `runMeta` | The `_apifyRun` object that went out with the payload. |
| `attempts` | One entry per attempt, with its status or error and duration. |
| `response` | Status, status text, headers, and body (truncated at 10,000 characters). Absent when no response was ever received. |
| `error` | Message of the final failure. Absent on success. |
| `finishedAt` | ISO timestamp of when the delivery finished. |

### Retries and failures

Network errors, timeouts, and the statuses `408`, `425`, `429`, and `5xx` are retried up to `maxRetries` times with exponential backoff (1s, 2s, 4s, … capped at 30s). Statuses the receiver decided on — `400`, `401`, `404`, and friends — are final and are not retried.

**The run itself succeeds even when the delivery does not.** Check `ok` in the output to tell the two apart; the run only fails when the input is invalid (missing URL, non-`http(s)` URL, missing secret). If you want alerting on failed deliveries, monitor the dataset field rather than the run status.

### Cost estimation

One run is a single HTTP request and finishes in seconds, so it consumes a negligible fraction of a compute unit — well within the Apify free tier even at hourly frequency. The dominant cost is the endpoint you are calling, not this Actor.

### Tips

- Give each schedule its own input so one endpoint's payload change never affects another.
- Set `maxRetries` to `0` for non-idempotent endpoints; a retried POST is a second delivery from the receiver's point of view.
- Answer quickly and do the work asynchronously if the endpoint is slow — each attempt is abandoned after 120 seconds.
- Verify the bearer token on the receiving side with a constant-time comparison, and reject requests that do not carry it.

### FAQ and support

**Does it support HTTP methods other than POST?** No — the Actor always POSTs a JSON body. That keeps it predictable as a scheduled trigger.

**How does the receiver tell which schedule triggered a delivery?** Read `_apifyRun.scheduleId` from the body. It is present only when a schedule started the run, so a manual test run is distinguishable from a scheduled one.

**Is the secret HMAC-signed?** No. It is transmitted as a bearer token over TLS, so use an `https://` URL and treat the secret like any other credential.

**Where do I report problems?** Use the Issues tab of the Actor on Apify Console.

# Actor input Schema

## `url` (type: `string`):

Absolute http(s) URL the payload is POSTed to, for example the standby endpoint of another Actor. The URL is called exactly once per run (plus retries on transient failures).

## `payload` (type: `object`):

JSON object sent as the request body with Content-Type: application/json. Defaults to an empty object. Metadata about the run is added under the reserved key `_apifyRun`, including the ID of the schedule that triggered it.

## `secret` (type: `string`):

Shared secret used to authenticate the call. It is sent verbatim in the Authorization header as `Bearer <secret>`, so the receiver can reject unauthenticated requests.

## `maxRetries` (type: `integer`):

Number of extra attempts after the first one, used for network errors and retryable statuses (408, 429, 5xx). Set to 0 to call the URL exactly once. Retries back off exponentially.

## Actor input object example

```json
{
  "payload": {},
  "maxRetries": 3
}
```

# Actor output Schema

# 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 = {
    "payload": {}
};

// Run the Actor and wait for it to finish
const run = await client.actor("honzakirchner/schedule-standby-delivery").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 = { "payload": {} }

# Run the Actor and wait for it to finish
run = client.actor("honzakirchner/schedule-standby-delivery").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 '{
  "payload": {}
}' |
apify call honzakirchner/schedule-standby-delivery --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,honzakirchner/schedule-standby-delivery"
        }
    }
}

```

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/bfSXtFzvn6uHNiEtL/builds/Ee2tMFraBw1Lrh2jU/openapi.json
