ワークフローとトリガー
一連のツール呼び出しを保存し、接続したアプリや公開データの出来事に応じて動かします。
ワークフローを定義する
ワークフローはslug(英小文字で始まる、英小文字・数字・アンダースコアの2〜40文字。作成時に必須)、title、description、inputSchema、1〜20個のstepsを持ちます。各ステップは{ id, tool, arguments, provider? }です。argumentsでは、{"$input": "topic"}で実行時の入力を、{"$step": "search", "path": "/results/0/url"}で前のステップの出力の値を参照します。
{
"slug": "research_brief",
"title": "Research brief",
"description": "Search the web for a topic and read the top result.",
"inputSchema": {
"type": "object",
"properties": { "topic": { "type": "string" } },
"required": ["topic"]
},
"steps": [
{ "id": "search", "tool": "web_search",
"arguments": { "query": { "$input": "topic" } } },
{ "id": "read", "tool": "scrape_page",
"arguments": { "url": { "$step": "search", "path": "/results/0/url" } } }
]
}POST /v1/workflowsで保存します。保存のたびに新しいバージョンになり、新しい50件を残します。
ワークフローを実行する
inputs、予算のmaximumChargeMicros、Idempotency-Keyを付けて実行を始めます。各ステップは、予算の残りの範囲で順に見積もられ、購入されます。
curl "$RELVO_API_URL/v1/workflows" \
-H "Authorization: Bearer $RELVO_API_KEY" \
-H "Content-Type: application/json" \
--data @workflow.json
curl "$RELVO_API_URL/v1/workflows/research_brief/runs" \
-H "Authorization: Bearer $RELVO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: research-brief-001" \
--data '{"inputs":{"topic":"content marketing"},"maximumChargeMicros":200000}'予算に収まらなくなったステップで、実行はplatform_workflow_budget_exceededで止まり、それまでのステップは請求されたままです。実行はGET /v1/workflow-runs/{id}で読み、POST /v1/workflow-runs/{id}/cancelでキャンセルします。1プロジェクトのワークフローは50個まで、同時に動く実行は10件までです。
トリガー
ポーリングのトリガーは、接続したアプリの読み取り操作を1m・5m(既定)・15m・1hごとに実行し、新しい項目ごとにaddedを、結果が1つなら変わったときにchangedを出します。Webhookのトリガーはgithub.pushなどの種別を使い、Relvoが接続を通してWebhookを登録します。初回のポーリングは基準を取るだけでイベントを出しません。
{
"kind": "poll",
"tool": "github__issues_list_for_repo",
"arguments": { "owner": "octo", "repo": "app" },
"connectionId": "CONNECTION_ID",
"interval": "5m",
"destinations": [{ "kind": "webhook", "url": "https://YOUR_SERVER/relvo/events" }]
}curl "$RELVO_API_URL/v1/triggers" \
-H "Authorization: Bearer $RELVO_API_KEY" \
-H "Content-Type: application/json" \
--data @trigger.jsonGET /v1/trigger-types?app=githubは、そのアプリのWebhook種別とポーリングできる操作を返します。トリガーは作成したAPIキーとして動き、そのキーを取り消すとトリガーも止まります。
公開データを見張る
監視は、共有の公開データを読む1ステップのツールを、スケジュール(15m・1h・1d、または5項目のcron。間隔は15分以上)で実行し直し、変わったところだけを出します。アプリではトリガーの中に並びます。
POST /v1/monitors/quoteで料金を確認し、見積もりのchargeCeilingMicros以上のmaximumChargeMicrosPerRunを付けてPOST /v1/monitorsで作成します。無料枠を使い切った後も動かし続けるなら、さらに300 microsを足します。監視は、削除するまで実行のたびに請求されます。残高・支出上限・その上限額で1回分を払えない間は一時停止し、払えるようになると自動で再開します。料金が上限額を超えたとき、プロジェクトの「ツールの実行」でそのツールが許可されなくなったとき、作成した人がプロジェクトにアクセスできなくなったときも一時停止し、この場合はPOST /v1/monitors/{id}/resumeで再開します。作成に使ったキーを取り消しても止まりません。
届け先
届け先は、作成時か、後からPOST /v1/triggers/{id}/destinationsで5つまで追加できます。
webhook
イベントごとに、署名付きのJSONをHTTPSのURLにPOSTします。
workflow
イベントごとにワークフローを1回実行します。イベントは入力eventに入り、maximumChargeMicrosが1回の予算です。
slack / discord
新しいイベント最大10件の要約とアプリへのリンクを、受信WebhookのURLに送ります。
email
チームメンバーに要約を送ります。アプリからだけ追加できます。届かなかった配信(408・429・5xx・通信エラー)は、合計6回まで送ります。再試行の間隔は30秒から倍々に延び、最長8分です。429のRetry-Afterには最大1時間まで従います。その他の4xxはすぐに失敗にします。同じ配信が2回届くことがあるため、Relvo-Deliveryで重複を除いてください。
Webhookの署名を検証する
Webhookの配信にはRelvo-Signature: t=<unix seconds>,v1=<hex>ヘッダーとRelvo-DeliveryのIDが付きます。v1は<t>.<raw body>のHMAC-SHA256で、鍵は届け先の署名シークレットです。シークレットは届け先を追加したときに1回だけ返ります。タイムスタンプを確認し、署名は定数時間で比較してください。
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody is the request body exactly as received, before JSON parsing.
export function verifyRelvoSignature(header, rawBody, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(",").map(part => part.split("=", 2)));
const timestamp = Number(parts.t);
const age = Math.abs(Date.now() / 1000 - timestamp);
if (!Number.isInteger(timestamp) || age > toleranceSeconds) return false;
const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest();
const received = Buffer.from(parts.v1 ?? "", "hex");
return received.length === expected.length && timingSafeEqual(received, expected);
}イベント・料金・上限
GET /v1/triggers/{id}/eventsとGET /v1/trigger-eventsは、afterより後のイベントを古い順に返します。次はnextAfterをafterに渡します。afterを付けないと最新のイベントが返り、after=0で保存中の最も古いイベントから読めます。イベントは30日間、1トリガー10,000件まで保存します。
ポーリングは1回ごとに1回のツール呼び出しで、プランの無料枠に数え、使い切った後は300 microsです。Webhookの受信は無料、メールは受信者1人あたり900 micros、ワークフローの届け先はステップごとに請求されます。トリガーは1プロジェクト50件・1チーム100件まで、監視は1プロジェクト25件までです。
エンドポイント
GET /v1/workflows · tools:read
ワークフローの一覧
POST /v1/workflows · tools:execute
新しいワークフローを保存
GET /v1/workflows/{slug} · tools:read
ワークフローを1つ読む
POST /v1/workflows/{slug}/update · tools:execute
新しいバージョンとして置き換える(expectedVersionを送る)
POST /v1/workflows/{slug}/delete · tools:execute
削除する
POST /v1/workflows/{slug}/runs · tools:execute
実行を開始
GET /v1/workflow-runs/{id} · executions:read
実行を1つ読む
POST /v1/workflow-runs/{id}/cancel · tools:execute
実行をキャンセル
GET /v1/trigger-types?app={app} · tools:read
アプリのWebhook種別とポーリングできる操作
GET /v1/triggers · executions:read
トリガーの一覧
POST /v1/triggers · tools:execute
トリガーを作成
POST /v1/triggers/{id}/update · tools:execute
有効化・無効化・名前の変更
POST /v1/triggers/{id}/delete · tools:execute
削除する
POST /v1/triggers/{id}/destinations · tools:execute
届け先を追加
GET /v1/triggers/{id}/events · executions:read
1つのトリガーのイベント
GET /v1/trigger-events · executions:read
全トリガーのイベント
POST /v1/monitors/quote · tools:read
作成せずに料金を見積もる
GET /v1/monitors · executions:read
監視の一覧
POST /v1/monitors · tools:execute
監視を作成
POST /v1/monitors/{id}/resume · tools:execute
一時停止した監視を再開
POST /v1/monitors/{id}/delete · tools:execute
削除する
GET /v1/monitor-events · executions:read
全監視のイベントこれらはHTTP APIの/v1以下にあり、同じキーとスコープを使います。