{
  "openapi": "3.1.0",
  "info": {
    "title": "cronservices API",
    "version": "1.1.0",
    "summary": "Schedule HTTP requests and chains of requests, transforms, and built-in steps with cron (any time zone), or once at a timestamp.",
    "description": "Jobs are called \"alarms\" and steps \"nodes\". Guide for agents: https://cron.services/agents.md",
    "contact": {
      "email": "support@cron.services"
    }
  },
  "externalDocs": {
    "url": "https://cron.services/docs",
    "description": "cronservices docs"
  },
  "servers": [
    {
      "url": "https://api.cron.services"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "paths": {
    "/alarms": {
      "get": {
        "operationId": "listJobs",
        "summary": "List jobs",
        "description": "Every job on the account, newest first. Call this before creating a job to avoid duplicates.",
        "responses": {
          "200": {
            "description": "Jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Job"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createJob",
        "summary": "Create a job",
        "description": "Send `cron` to repeat on a schedule, or `run_at` to fire once at that time.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JobInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not valid JSON for this request (code invalid_json)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "A plan limit is reached (code plan_limit)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields (code validation_failed); see `fields`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alarms/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getJob",
        "summary": "Get a job",
        "responses": {
          "200": {
            "description": "The job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "404": {
            "description": "No such job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateJob",
        "summary": "Replace a job",
        "description": "Send the full job, not a patch. Get it, change what you need, and send it back.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JobInput"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Updated"
          },
          "400": {
            "description": "Not valid JSON for this request (code invalid_json)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields (code validation_failed); see `fields`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteJob",
        "summary": "Delete a job",
        "description": "Also deletes its run history.",
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "description": "No such job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alarms/{id}/run": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "runJob",
        "summary": "Run a job now",
        "description": "Runs the job outside its schedule, waits for it to finish, and returns the run. Works on paused jobs; doesn’t move next_fire_at. Use it to verify a new job.",
        "responses": {
          "200": {
            "description": "The finished run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Run"
                }
              }
            }
          },
          "404": {
            "description": "No such job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/alarms/{id}/runs": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "page_size",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 0,
            "maximum": 500,
            "default": 100
          }
        },
        {
          "name": "page_token",
          "in": "query",
          "schema": {
            "type": "string"
          },
          "description": "next_page_token from the previous page."
        }
      ],
      "get": {
        "operationId": "listRuns",
        "summary": "List a job’s runs",
        "description": "Newest first.",
        "responses": {
          "200": {
            "description": "Runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Run"
                      }
                    },
                    "next_page_token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/credentials": {
      "get": {
        "operationId": "listCredentials",
        "summary": "List credentials",
        "description": "Secrets are never returned; each credential has last4 instead.",
        "responses": {
          "200": {
            "description": "Credentials",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Credential"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createCredential",
        "summary": "Create a credential",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Credential"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not valid JSON for this request (code invalid_json)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields (code validation_failed); see `fields`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/credentials/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "updateCredential",
        "summary": "Replace a credential",
        "description": "An empty secret keeps the stored one. The kind can’t change.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Credential"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Updated"
          },
          "400": {
            "description": "Not valid JSON for this request (code invalid_json)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such credential",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields (code validation_failed); see `fields`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteCredential",
        "summary": "Delete a credential",
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "409": {
            "description": "A job still uses it (code failed_precondition)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "health",
        "summary": "Health check",
        "security": [],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from Settings → API keys."
      }
    },
    "schemas": {
      "Job": {
        "type": "object",
        "description": "Fields that are empty or unset are left out.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "maxLength": 80,
            "description": "Human-readable name. Use a stable, unique name so you can find the job again."
          },
          "cron": {
            "type": "object",
            "required": [
              "expression"
            ],
            "properties": {
              "expression": {
                "type": "string",
                "description": "5-field cron: minute hour day-of-month month day-of-week. Supports L, LW, 15W in day-of-month and MON#1, FRI#L in day-of-week.",
                "examples": [
                  "0 9 * * 1-5"
                ]
              },
              "time_zone": {
                "type": "string",
                "default": "UTC",
                "description": "IANA time zone the expression is read in, e.g. America/New_York. Daylight saving is handled."
              }
            }
          },
          "run_at": {
            "type": "string",
            "format": "date-time",
            "description": "One-time job: ISO 8601 timestamp with an offset, in the future and within a year. The job fires once, then switches itself off.",
            "examples": [
              "2026-12-01T09:00:00-05:00"
            ]
          },
          "nodes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/Node"
            }
          },
          "enabled": {
            "type": "boolean",
            "default": true,
            "description": "false pauses the job."
          },
          "next_fire_at": {
            "type": "string",
            "format": "date-time",
            "description": "Absent once a one-time job has fired."
          },
          "last_fired_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_status_code": {
            "type": "integer",
            "description": "0 means the request could not be sent (DNS, TLS, timeout)."
          },
          "complete_time": {
            "type": "string",
            "format": "date-time",
            "description": "When a one-time job fired."
          },
          "create_time": {
            "type": "string",
            "format": "date-time"
          },
          "update_time": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "JobInput": {
        "type": "object",
        "description": "Send exactly one of `cron` (repeating job) and `run_at` (one-time job).",
        "required": [
          "nodes"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 80,
            "description": "Human-readable name. Use a stable, unique name so you can find the job again."
          },
          "cron": {
            "type": "object",
            "required": [
              "expression"
            ],
            "properties": {
              "expression": {
                "type": "string",
                "description": "5-field cron: minute hour day-of-month month day-of-week. Supports L, LW, 15W in day-of-month and MON#1, FRI#L in day-of-week.",
                "examples": [
                  "0 9 * * 1-5"
                ]
              },
              "time_zone": {
                "type": "string",
                "default": "UTC",
                "description": "IANA time zone the expression is read in, e.g. America/New_York. Daylight saving is handled."
              }
            }
          },
          "run_at": {
            "type": "string",
            "format": "date-time",
            "description": "One-time job: ISO 8601 timestamp with an offset, in the future and within a year. The job fires once, then switches itself off.",
            "examples": [
              "2026-12-01T09:00:00-05:00"
            ]
          },
          "nodes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/Node"
            }
          },
          "enabled": {
            "type": "boolean",
            "default": true,
            "description": "false pauses the job."
          }
        }
      },
      "Node": {
        "type": "object",
        "description": "One step. Set id and exactly one kind: request, transform, or a built-in step. Each step receives the previous step’s output as $; the first gets null. A non-2xx response stops the job.",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,64}$",
            "description": "Unique within the job, e.g. \"fetch\"."
          },
          "name": {
            "type": "string",
            "maxLength": 80,
            "description": "Optional label shown in run history."
          },
          "request": {
            "type": "object",
            "description": "Send an HTTP request. Output: the response body, parsed as JSON when it parses.",
            "required": [
              "endpoint"
            ],
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "GET",
                  "POST",
                  "PUT",
                  "PATCH",
                  "DELETE",
                  "HTTP_METHOD_GET",
                  "HTTP_METHOD_POST",
                  "HTTP_METHOD_PUT",
                  "HTTP_METHOD_PATCH",
                  "HTTP_METHOD_DELETE"
                ],
                "default": "POST",
                "description": "Responses use the HTTP_METHOD_ form; requests accept either."
              },
              "endpoint": {
                "type": "string",
                "description": "Full http(s) URL. May contain {{ }} placeholders.",
                "examples": [
                  "https://api.example.com/v1/sync"
                ]
              },
              "credential_id": {
                "type": "string",
                "description": "Optional id of a bearer_token, basic_auth or api_key_header credential, sent as its header."
              },
              "headers": {
                "type": "array",
                "maxItems": 50,
                "items": {
                  "type": "object",
                  "required": [
                    "name"
                  ],
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Header name, e.g. \"X-Source\"."
                    },
                    "value": {
                      "type": "string",
                      "description": "Header value. May contain {{ }} placeholders."
                    }
                  }
                }
              },
              "body": {
                "type": "string",
                "description": "Sent with POST, PUT, PATCH, DELETE. A body starting with { or [ is a JSON template sent as application/json; anything else is plain text with {{ }} interpolation."
              }
            }
          },
          "transform": {
            "type": "object",
            "description": "Reshape the previous step’s output without a request. Output: the rendered template.",
            "required": [
              "template"
            ],
            "properties": {
              "template": {
                "type": "string",
                "description": "JSON template rendered against the previous step’s output ($).",
                "examples": [
                  "{ \"count\": \"{{ $.length }}\", \"lines\": { \"{{#each $}}\": \"{{ $.title }}\" } }"
                ]
              }
            }
          },
          "slack_send_message": {
            "type": "object",
            "description": "Send a Slack message. Sends POST to the incoming webhook URL with {\"text\": …}.",
            "required": [
              "webhook_url",
              "text"
            ],
            "properties": {
              "webhook_url": {
                "type": "string",
                "description": "An incoming webhook URL, https://hooks.slack.com/services/…, from a Slack app with Incoming Webhooks turned on."
              },
              "text": {
                "type": "string",
                "description": "Slack mrkdwn: *bold*, _italic_, <https://example.com|a link>. Up to 40,000 characters. May contain {{ }} placeholders."
              }
            }
          },
          "slack_channel_history": {
            "type": "object",
            "description": "Read a Slack channel. Sends GET https://slack.com/api/conversations.history.",
            "required": [
              "credential_id",
              "channel"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a bot token (xoxb-…) with channels:history, groups:history or im:history."
              },
              "channel": {
                "type": "string",
                "description": "A channel, private group or DM id, such as C0123456789."
              },
              "limit": {
                "type": "integer",
                "description": "1 to 100. Omit for Slack’s default of 100."
              }
            }
          },
          "discord_send_message": {
            "type": "object",
            "description": "Send a Discord message. Sends POST to the webhook URL with ?wait=true.",
            "required": [
              "webhook_url",
              "content"
            ],
            "properties": {
              "webhook_url": {
                "type": "string",
                "description": "A channel webhook, https://discord.com/api/webhooks/<id>/<token>. Channel settings → Integrations → Webhooks."
              },
              "content": {
                "type": "string",
                "description": "Discord markdown, up to 2,000 characters. May contain {{ }} placeholders."
              },
              "username": {
                "type": "string",
                "description": "Overrides the webhook’s name. May contain {{ }} placeholders."
              },
              "avatar_url": {
                "type": "string",
                "description": "Overrides the webhook’s avatar. May contain {{ }} placeholders."
              }
            }
          },
          "teams_post_message": {
            "type": "object",
            "description": "Post a Microsoft Teams message. Sends POST to the Workflows webhook URL with an Adaptive Card holding the text.",
            "required": [
              "webhook_url",
              "text"
            ],
            "properties": {
              "webhook_url": {
                "type": "string",
                "description": "A Teams Workflows (\"Post to a channel when a webhook request is received\") URL on logic.azure.com, or a legacy webhook.office.com connector URL."
              },
              "text": {
                "type": "string",
                "description": "Up to 4,000 characters. Adaptive Card text supports simple markdown. May contain {{ }} placeholders."
              }
            }
          },
          "google_chat_send_message": {
            "type": "object",
            "description": "Send a Google Chat message. Sends POST to the space’s incoming webhook URL with {\"text\": …}.",
            "required": [
              "webhook_url",
              "text"
            ],
            "properties": {
              "webhook_url": {
                "type": "string",
                "description": "A space webhook, https://chat.googleapis.com/v1/spaces/…. Space → Apps & integrations → Webhooks."
              },
              "text": {
                "type": "string",
                "description": "Up to 4,096 characters. *bold*, _italic_, <https://example.com|link>. May contain {{ }} placeholders."
              }
            }
          },
          "mattermost_send_message": {
            "type": "object",
            "description": "Send a Mattermost message. Sends POST to the incoming webhook URL with {\"text\": …}.",
            "required": [
              "webhook_url",
              "text"
            ],
            "properties": {
              "webhook_url": {
                "type": "string",
                "description": "An incoming webhook, https://<your server>/hooks/<id>."
              },
              "text": {
                "type": "string",
                "description": "Markdown, up to 16,383 characters. May contain {{ }} placeholders."
              },
              "username": {
                "type": "string",
                "description": "Overrides the webhook’s name, if the server allows it."
              }
            }
          },
          "telegram_send_message": {
            "type": "object",
            "description": "Send a Telegram message. Sends POST https://api.telegram.org/bot<token>/sendMessage.",
            "required": [
              "credential_id",
              "chat_id",
              "text"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a telegram_bot credential holding the token from BotFather."
              },
              "chat_id": {
                "type": "string",
                "description": "A numeric chat id (negative for groups), a @channelusername, or a placeholder."
              },
              "text": {
                "type": "string",
                "description": "Up to 4,096 characters. May contain {{ }} placeholders."
              }
            }
          },
          "ntfy_publish": {
            "type": "object",
            "description": "Publish an ntfy notification. Sends POST to the ntfy server (default https://ntfy.sh) with the topic and message as JSON.",
            "required": [
              "topic",
              "message"
            ],
            "properties": {
              "server": {
                "type": "string",
                "description": "Your ntfy server. Omit for https://ntfy.sh."
              },
              "topic": {
                "type": "string",
                "description": "Letters, digits, _ and -, up to 64 characters. Anyone who knows a public topic can read it, so pick a hard-to-guess name."
              },
              "message": {
                "type": "string",
                "description": "Up to 4,096 characters. May contain {{ }} placeholders."
              },
              "title": {
                "type": "string",
                "description": "Up to 256 characters. May contain {{ }} placeholders."
              },
              "priority": {
                "type": "integer",
                "description": "1 (min) to 5 (urgent). Omit for the default, 3."
              },
              "tags": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Up to 10 tags. Tags that match an emoji short code, like warning, show as that emoji."
              },
              "click": {
                "type": "string",
                "description": "A URL opened when the notification is tapped. May contain {{ }} placeholders."
              },
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding an ntfy access token, for protected topics."
              }
            }
          },
          "pushover_send_notification": {
            "type": "object",
            "description": "Send a Pushover notification. Sends POST https://api.pushover.net/1/messages.json.",
            "required": [
              "credential_id",
              "user_key",
              "message"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a pushover credential holding your application’s API token."
              },
              "user_key": {
                "type": "string",
                "description": "The user or group key, 30 letters and digits."
              },
              "message": {
                "type": "string",
                "description": "Up to 1,024 characters. May contain {{ }} placeholders."
              },
              "title": {
                "type": "string",
                "description": "Up to 250 characters. May contain {{ }} placeholders."
              },
              "url": {
                "type": "string",
                "description": "Opened when the notification is tapped. May contain {{ }} placeholders."
              },
              "priority": {
                "type": "integer",
                "description": "-2 (lowest) to 1 (high). 0 is normal."
              }
            }
          },
          "gotify_send_message": {
            "type": "object",
            "description": "Send a Gotify message. Sends POST <server>/message with header X-Gotify-Key.",
            "required": [
              "credential_id",
              "message"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a gotify credential holding your server URL and an application token."
              },
              "message": {
                "type": "string",
                "description": "Up to 4,096 characters. May contain {{ }} placeholders."
              },
              "title": {
                "type": "string",
                "description": "Optional. May contain {{ }} placeholders."
              },
              "priority": {
                "type": "integer",
                "description": "0 (default) to 10."
              }
            }
          },
          "pushbullet_push_note": {
            "type": "object",
            "description": "Push a Pushbullet note. Sends POST https://api.pushbullet.com/v2/pushes with {\"type\": \"note\", …}.",
            "required": [
              "credential_id",
              "body"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a Pushbullet access token."
              },
              "title": {
                "type": "string",
                "description": "Optional. May contain {{ }} placeholders."
              },
              "body": {
                "type": "string",
                "description": "The note, up to 4,096 characters. May contain {{ }} placeholders."
              }
            }
          },
          "smtp_send_email": {
            "type": "object",
            "description": "Send an email from your mailbox. Sends A plain-text email through your own SMTP server, over TLS or STARTTLS.",
            "required": [
              "credential_id",
              "to",
              "subject",
              "text"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a smtp credential holding your mail server, username, password and from address."
              },
              "to": {
                "type": "string",
                "description": "One recipient address. May contain {{ }} placeholders."
              },
              "subject": {
                "type": "string",
                "description": "One line, up to 998 characters. May contain {{ }} placeholders."
              },
              "text": {
                "type": "string",
                "description": "Plain text, up to 40,000 characters. May contain {{ }} placeholders."
              }
            }
          },
          "resend_send_email": {
            "type": "object",
            "description": "Send an email with Resend. Sends POST https://api.resend.com/emails.",
            "required": [
              "credential_id",
              "from",
              "to",
              "subject",
              "text"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a Resend API key (re_…)."
              },
              "from": {
                "type": "string",
                "description": "The sender address, on a domain verified with Resend. May contain {{ }} placeholders."
              },
              "from_name": {
                "type": "string",
                "description": "Shown with the address, as \"Name <from>\". May contain {{ }} placeholders."
              },
              "to": {
                "type": "string",
                "description": "The recipient address. May contain {{ }} placeholders."
              },
              "subject": {
                "type": "string",
                "description": "Up to 998 characters. May contain {{ }} placeholders."
              },
              "text": {
                "type": "string",
                "description": "Plain text, up to 40,000 characters. May contain {{ }} placeholders."
              }
            }
          },
          "sendgrid_send_email": {
            "type": "object",
            "description": "Send an email with SendGrid. Sends POST https://api.sendgrid.com/v3/mail/send.",
            "required": [
              "credential_id",
              "from",
              "to",
              "subject",
              "text"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a SendGrid API key (SG.…)."
              },
              "from": {
                "type": "string",
                "description": "The sender address, on a domain verified with SendGrid. May contain {{ }} placeholders."
              },
              "from_name": {
                "type": "string",
                "description": "Shown with the address, as \"Name <from>\". May contain {{ }} placeholders."
              },
              "to": {
                "type": "string",
                "description": "The recipient address. May contain {{ }} placeholders."
              },
              "subject": {
                "type": "string",
                "description": "Up to 998 characters. May contain {{ }} placeholders."
              },
              "text": {
                "type": "string",
                "description": "Plain text, up to 40,000 characters. May contain {{ }} placeholders."
              }
            }
          },
          "twilio_send_sms": {
            "type": "object",
            "description": "Send an SMS with Twilio. Sends POST https://api.twilio.com/2010-04-01/Accounts/<sid>/Messages.json with HTTP Basic auth.",
            "required": [
              "credential_id",
              "to",
              "from",
              "body"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a twilio credential holding your account SID and auth token."
              },
              "to": {
                "type": "string",
                "description": "An E.164 number such as +15551234567, or a placeholder. May contain {{ }} placeholders."
              },
              "from": {
                "type": "string",
                "description": "One of your Twilio numbers in E.164, or a messaging service SID (MG…). May contain {{ }} placeholders."
              },
              "body": {
                "type": "string",
                "description": "Up to 1,600 characters. Longer texts are sent as several segments. May contain {{ }} placeholders."
              }
            }
          },
          "pagerduty_trigger_incident": {
            "type": "object",
            "description": "Trigger a PagerDuty incident. Sends POST https://events.pagerduty.com/v2/enqueue (Events API v2).",
            "required": [
              "credential_id",
              "summary",
              "source",
              "severity"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a pagerduty_routing_key credential holding the service’s integration key."
              },
              "summary": {
                "type": "string",
                "description": "What happened, up to 1,024 characters. May contain {{ }} placeholders."
              },
              "source": {
                "type": "string",
                "description": "The system it came from, such as a host name. May contain {{ }} placeholders."
              },
              "severity": {
                "type": "string",
                "description": "critical, error, warning or info."
              },
              "dedup_key": {
                "type": "string",
                "description": "Groups repeat triggers into one incident. May contain {{ }} placeholders."
              }
            }
          },
          "pagerduty_list_on_calls": {
            "type": "object",
            "description": "Read who’s on call in PagerDuty. Sends GET https://api.pagerduty.com/oncalls with header Authorization: Token token=….",
            "required": [
              "credential_id"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a pagerduty_api_key credential holding a REST API key that can read on-calls."
              },
              "escalation_policy": {
                "type": "string",
                "description": "A policy id such as PABC123. Omit for every policy the key can see."
              },
              "limit": {
                "type": "integer",
                "description": "1 to 100. Omit for PagerDuty’s default of 25."
              }
            }
          },
          "opsgenie_create_alert": {
            "type": "object",
            "description": "Create an Opsgenie alert. Sends POST https://api.opsgenie.com/v2/alerts (or the EU host) with header Authorization: GenieKey ….",
            "required": [
              "credential_id",
              "message"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a opsgenie credential holding an API integration key and its region."
              },
              "message": {
                "type": "string",
                "description": "Up to 130 characters. May contain {{ }} placeholders."
              },
              "description": {
                "type": "string",
                "description": "Up to 15,000 characters. May contain {{ }} placeholders."
              },
              "priority": {
                "type": "string",
                "description": "P1 (highest) to P5. Omit for Opsgenie’s default."
              }
            }
          },
          "datadog_post_event": {
            "type": "object",
            "description": "Post a Datadog event. Sends POST https://api.<site>/api/v1/events with header DD-API-KEY.",
            "required": [
              "credential_id",
              "title",
              "text"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a datadog credential holding an API key and your Datadog site."
              },
              "title": {
                "type": "string",
                "description": "Up to 100 characters. May contain {{ }} placeholders."
              },
              "text": {
                "type": "string",
                "description": "Up to 4,000 characters. May contain {{ }} placeholders."
              },
              "alert_type": {
                "type": "string",
                "description": "error, warning, info or success. Omit for info."
              }
            }
          },
          "healthchecks_ping": {
            "type": "object",
            "description": "Ping a Healthchecks check. Sends POST the ping URL, or <ping_url>/fail or /start.",
            "required": [
              "ping_url"
            ],
            "properties": {
              "ping_url": {
                "type": "string",
                "description": "The check’s ping URL, ending in its UUID, on hc-ping.com or your own server."
              },
              "signal": {
                "type": "string",
                "description": "Omit to report success. fail reports a failure and start starts a timer."
              },
              "body": {
                "type": "string",
                "description": "A log line stored with the ping, up to 10,000 characters. May contain {{ }} placeholders."
              }
            }
          },
          "github_create_issue": {
            "type": "object",
            "description": "Open a GitHub issue. Sends POST https://api.github.com/repos/<owner>/<repo>/issues.",
            "required": [
              "credential_id",
              "owner",
              "repo",
              "title"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a GitHub token that can create issues."
              },
              "owner": {
                "type": "string",
                "description": "The user or organization."
              },
              "repo": {
                "type": "string",
                "description": "The repository name."
              },
              "title": {
                "type": "string",
                "description": "Up to 256 characters. May contain {{ }} placeholders."
              },
              "body": {
                "type": "string",
                "description": "Markdown, up to 65,536 characters. May contain {{ }} placeholders."
              }
            }
          },
          "github_list_pull_requests": {
            "type": "object",
            "description": "List GitHub pull requests. Sends GET https://api.github.com/repos/<owner>/<repo>/pulls.",
            "required": [
              "credential_id",
              "owner",
              "repo",
              "state"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a GitHub token that can read the repository."
              },
              "owner": {
                "type": "string",
                "description": "The user or organization."
              },
              "repo": {
                "type": "string",
                "description": "The repository name."
              },
              "state": {
                "type": "string",
                "description": "open, closed or all."
              },
              "per_page": {
                "type": "integer",
                "description": "1 to 100. Omit for GitHub’s default of 30."
              }
            }
          },
          "ifttt_trigger": {
            "type": "object",
            "description": "Run an IFTTT applet. Sends POST https://maker.ifttt.com/trigger/<event>/json/with/key/<key>.",
            "required": [
              "event",
              "credential_id",
              "value1"
            ],
            "properties": {
              "event": {
                "type": "string",
                "description": "The event name in the applet’s webhook trigger."
              },
              "credential_id": {
                "type": "string",
                "description": "The id of a ifttt credential holding your Webhooks service key."
              },
              "value1": {
                "type": "string",
                "description": "Up to 4,096 characters. May contain {{ }} placeholders."
              },
              "value2": {
                "type": "string",
                "description": "Optional. May contain {{ }} placeholders."
              },
              "value3": {
                "type": "string",
                "description": "Optional. May contain {{ }} placeholders."
              }
            }
          },
          "stripe_list_subscriptions": {
            "type": "object",
            "description": "List Stripe subscriptions. Sends GET https://api.stripe.com/v1/subscriptions.",
            "required": [
              "credential_id"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a Stripe secret or restricted key (sk_… or rk_…) that can read subscriptions."
              },
              "status": {
                "type": "string",
                "description": "active, past_due, unpaid, canceled, incomplete, trialing or all. Omit for Stripe’s default (everything but canceled)."
              },
              "limit": {
                "type": "integer",
                "description": "1 to 100. Omit for Stripe’s default of 10."
              }
            }
          },
          "stripe_list_customers": {
            "type": "object",
            "description": "List Stripe customers. Sends GET https://api.stripe.com/v1/customers.",
            "required": [
              "credential_id"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a Stripe key that can read customers."
              },
              "limit": {
                "type": "integer",
                "description": "1 to 100. Omit for Stripe’s default of 10."
              }
            }
          },
          "stripe_retrieve_balance": {
            "type": "object",
            "description": "Read your Stripe balance. Sends GET https://api.stripe.com/v1/balance.",
            "required": [
              "credential_id"
            ],
            "properties": {
              "credential_id": {
                "type": "string",
                "description": "The id of a bearer_token credential holding a Stripe key that can read the balance."
              }
            }
          },
          "open_meteo_forecast": {
            "type": "object",
            "description": "Get a weather forecast from Open-Meteo. Sends GET https://api.open-meteo.com/v1/forecast for current conditions and a 3-day daily forecast. No API key.",
            "required": [
              "latitude",
              "longitude"
            ],
            "properties": {
              "latitude": {
                "type": "string",
                "description": "Decimal degrees, -90 to 90, such as \"45.52\"."
              },
              "longitude": {
                "type": "string",
                "description": "Decimal degrees, -180 to 180, such as \"-122.68\"."
              },
              "units": {
                "type": "string",
                "description": "Omit or metric for °C, km/h and mm. imperial for °F, mph and inches."
              }
            }
          },
          "frankfurter_latest": {
            "type": "object",
            "description": "Get an exchange rate from Frankfurter. Sends GET https://api.frankfurter.app/latest (European Central Bank reference rates). No API key.",
            "required": [
              "from",
              "to"
            ],
            "properties": {
              "from": {
                "type": "string",
                "description": "An ISO 4217 code, such as USD."
              },
              "to": {
                "type": "string",
                "description": "The ISO 4217 code to convert to, such as EUR."
              }
            }
          }
        }
      },
      "Run": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "alarm_id": {
            "type": "string",
            "format": "uuid"
          },
          "trigger": {
            "type": "string",
            "enum": [
              "RUN_TRIGGER_SCHEDULE",
              "RUN_TRIGGER_MANUAL"
            ]
          },
          "fire_time": {
            "type": "string",
            "format": "date-time"
          },
          "duration": {
            "type": "string",
            "examples": [
              "0.412s"
            ]
          },
          "status_code": {
            "type": "integer",
            "description": "The last request’s status. 0 means it could not be sent."
          },
          "failed_node_id": {
            "type": "string",
            "description": "The step that stopped the run. Absent when it succeeded."
          },
          "error_message": {
            "type": "string",
            "description": "Why the run failed. Absent when it succeeded."
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "RUN_STEP_STATUS_SUCCEEDED",
                    "RUN_STEP_STATUS_FAILED",
                    "RUN_STEP_STATUS_SKIPPED"
                  ]
                },
                "status_code": {
                  "type": "integer"
                },
                "duration": {
                  "type": "string"
                },
                "error_message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Credential": {
        "type": "object",
        "description": "A saved secret. Set name and exactly one kind, e.g. {\"name\": \"GitHub\", \"bearer_token\": {\"token\": \"ghp_…\"}}. Secret fields are write-only; reads return last4 instead. See the docs for every kind’s fields.",
        "required": [
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "maxLength": 80
          },
          "bearer_token": {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "basic_auth": {
            "type": "object",
            "properties": {
              "username": {
                "type": "string"
              },
              "password": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "api_key_header": {
            "type": "object",
            "properties": {
              "header": {
                "type": "string"
              },
              "value": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "smtp": {
            "type": "object",
            "properties": {
              "host": {
                "type": "string"
              },
              "port": {
                "type": "integer",
                "enum": [
                  25,
                  465,
                  587,
                  2525
                ]
              },
              "security": {
                "type": "string",
                "enum": [
                  "tls",
                  "starttls"
                ]
              },
              "username": {
                "type": "string"
              },
              "password": {
                "type": "string",
                "writeOnly": true
              },
              "from_address": {
                "type": "string"
              },
              "from_name": {
                "type": "string"
              }
            }
          },
          "twilio": {
            "type": "object",
            "properties": {
              "account_sid": {
                "type": "string"
              },
              "auth_token": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "telegram_bot": {
            "type": "object",
            "properties": {
              "bot_token": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "pushover": {
            "type": "object",
            "properties": {
              "api_token": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "gotify": {
            "type": "object",
            "properties": {
              "server": {
                "type": "string"
              },
              "token": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "pagerduty_routing_key": {
            "type": "object",
            "properties": {
              "routing_key": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "pagerduty_api_key": {
            "type": "object",
            "properties": {
              "api_key": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "opsgenie": {
            "type": "object",
            "properties": {
              "region": {
                "type": "string"
              },
              "api_key": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "datadog": {
            "type": "object",
            "properties": {
              "site": {
                "type": "string"
              },
              "api_key": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "ifttt": {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "writeOnly": true
              }
            }
          },
          "last4": {
            "type": "string",
            "readOnly": true
          },
          "create_time": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "examples": [
              "validation_failed",
              "invalid_json",
              "not_found",
              "unauthenticated",
              "plan_limit"
            ]
          },
          "message": {
            "type": "string"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Per-field messages on 422, keyed by path, e.g. {\"alarm.cron.expression\": \"…\", \"alarm.nodes[1].transform.template\": \"…\"}."
          }
        }
      }
    }
  }
}
