Guard-API

Der Agent schlägt vor; COLVO entscheidet, führt genau einmal aus und verifiziert. Drei Endpunkte decken das ab: vorschlagen, lesen, entscheiden.

Direkt aus dem Code geschrieben · aktualisiert am 26 Sept. 2026 · Fehlt etwas oder ist etwas falsch? Schreib uns

Eine Operation vorschlagen

POST /v1/operations – Agenten- oder Backend-Schlüssel oder Sitzung (Editor+). Antwortet sofort mit 202 und der Entscheidung; Ausführung und Verifizierung laufen asynchron weiter.

POST /v1/operations
Authorization: Bearer cak_…
Idempotency-Key: ticket_4711:refund
Content-Type: application/json

{ "mandate_id": "…", "source_request_id": "ticket_4711",
  "action": "refund.create",
  "parameters": { "payment_id": "pi_01", "amount_minor": 5000, "currency": "eur", "reason": "duplicate charge" },
  "context": { "user_message": "…", "agent_reply": "…", "retrieved": ["…"] } }

Aktionen und Parameter

actionParameter
refund.createeines von payment_id | invoice_id | charge_id (ältere Zahlungen aus der Zeit vor PaymentIntents), amount_minor (Ganzzahl > 0), currency (3 Buchstaben), reason?
subscription.cancelsubscription_id, mode: period_end (Standard) | immediate
subscription.pausesubscription_id, resumes_at? (Datum oder Datum mit Uhrzeit; fehlt es = kein Enddatum), behavior: void (Standard) | keep_as_draft. Die Abrechnung stoppt, der Zugang bleibt.
subscription.resumesubscription_id – hebt die Pause auf; ist das Abonnement nicht pausiert, wird nichts gesendet.
subscription.change_plansubscription_id, price_id, at: now (Standard, anteilig verrechnet) | period_end (geplant; der aktuelle Tarif bleibt bis zum Enddatum).
coupon.applysubscription_id, coupon_id. Nie zusätzlich zu einem bestehenden Rabatt: In diesem Fall schlägt die Operation fehl, bevor etwas gesendet wird.
order.cancelNur Shopify. order_id (#1042, numerische ID oder gid), refund (Standard false: bei true wird der verbleibende Betrag der Bestellung im selben Schritt erstattet), restock (Standard true), reason: customer (Standard) | fraud | inventory | declined | other. COLVO liest die Bestellung zuerst: eine bereits stornierte Bestellung → DENY, eine nicht lesbare Bestellung → HOLD; mit Erstattung gelten die Limits für den erstattungsfähigen Betrag.
subscription.cancel_undosubscription_id – entfernt eine geplante Kündigung. Ein beendetes Abonnement lässt sich nicht wiederherstellen: Die Operation schlägt fehl, bevor etwas gesendet wird.

Mandatslimits für Pausen: max_pause_days (Standard 30; länger → DENY) und pause_open_ended: never | review (Standard) | allow für eine Pause ohne Enddatum. Die Verifizierung liest das Abonnement zurück: pause_collection gesetzt (oder entfernt), cancel_at_period_end nach einer Rücknahme false und das Abonnement weiterhin aktiv mit Zugang.

Tarifwechsel und Gutscheine: allowed_price_ids, change_plan_at (now / period_end), auto_allow_proration_up_to_minor (ein Wechsel, der heute mehr berechnet → REVIEW; Gutschriften brauchen nie eine Prüfung), max_proration_minor (mehr → DENY) und allowed_coupons. Bei einem Wechsel „now“ lässt sich COLVO vor der Entscheidung vom Provider eine Vorschau der Belastung geben; ist sie nicht lesbar, lautet die Entscheidung HOLD. Die Verifizierung prüft den neuen Preis (oder den geplanten Wechsel) und den Gutschein am Abonnement.

Bei Shopify übernimmt die Bestellung die Rolle der Zahlung: refund.create erhält die Bestellung in payment_id und erstattet Geld darauf (nichts wird wieder eingelagert, die Bestellung bleibt offen). Abonnement-Aktionen werden auf einer Shopify-Verbindung abgelehnt.

Idempotenz

  • Senden Sie bei jedem Vorschlag Idempotency-Key. Derselbe Schlüssel mit demselben Body liefert die ursprüngliche Operation zurück (200); derselbe Schlüssel mit anderem Body wird mit 409 idempotency_key_reused abgelehnt.
  • Unabhängig vom Header leitet COLVO aus Mandat + Aktion + Ziel einen Business-Schlüssel ab; ein zweiter Vorschlag mit derselben Wirkung wird mit 409 business_key_conflict abgelehnt. Ein Wiederholungsversuch verdoppelt nie eine Erstattung.

Antwort

{
  "operation_id": "…", "project_id": "…", "mandate_id": "…",
  "action": "refund.create", "parameters": { … }, "source_request_id": "ticket_4711", "business_key": "…",
  "decision": "REVIEW",
  "decision_reasons": ["amount 5000 above auto-allow 2000 (within max 5000)"],
  "guardrail_hits": [{ "rail": "pii_input", "stage": "input", "action": "REDACT", "advisory": false, "reason": "email redacted" }],
  "exec_state": "NOT_SENT", "verify_state": "NOT_DUE",
  "provider_id": null,
  "approval": { "approval_id": "…", "digest": "sha256:…", "expires_at": "…", "decision": "PENDING" },
  "policy_version": "policy-v1", "mandate_version": 1, "evidence_count": 3, "last_error": null,
  "created_at": "…", "updated_at": "…"
}

Entscheidungen

  • ALLOW – sofort zur Ausführung eingereiht.
  • REVIEW – wartet auf einen Menschen; approval enthält den Digest, den dieser signieren muss.
  • HOLD – kann jetzt nicht sicher ausgeführt werden (Zustand nicht lesbar, Limit überschritten, Projekt pausiert). Später erneut vorschlagen.
  • DENY – Richtlinienverstoß; es passiert nichts. Die Gründe werden explizit genannt.

Lebenszyklus

exec_state: NOT_SENT → QUEUED → SENDING → ACKNOWLEDGED | PROVIDER_REVIEW | FAILED | UNKNOWN | CANCELED_BEFORE_SEND. verify_state: NOT_DUE → PENDING → VERIFIED | MISMATCH | UNVERIFIABLE. MISMATCH und UNVERIFIABLE eröffnen einen Vorfall und lösen Alerts aus.

Eine Operation lesen

GET /v1/operations/{id} – beliebiger Schlüssel oder Sitzung. Gleiche Form wie oben, aktualisiert. Fragen Sie sie nach einem REVIEW ab, um das Ergebnis zu erfahren, oder abonnieren Sie Alerts.

Freigeben oder ablehnen

POST /v1/operations/{id}/decision – nur Sitzung (Editor+). Die prüfende Person signiert den exakten Digest; ein veralteter Digest wird abgelehnt (409 digest_mismatch), ebenso eine abgelaufene Freigabe (409 approval_expired).

{ "decision": "approve", "approval_digest": "sha256:…", "rationale": "customer confirmed duplicate charge" }

Benachrichtigungen zu Freigaben

Ein REVIEW benachrichtigt die Personen, die entscheiden können: eine E-Mail an jeden Owner und Editor sowie einen Alert an jeden Alert-Kanal des Projekts, der approval.requested / approval.reminder / approval.expired abonniert hat (Slack, E-Mail, signierter Webhook). Das Freigabefenster ist das kürzere von 24 Stunden und dem Ablauf des Mandats. Bei 75 % des Fensters geht eine Erinnerung hinaus; am Ende wird eine nicht entschiedene Freigabe zu EXPIRED, die Operation zu CANCELED_BEFORE_SEND, und die Freigebenden werden informiert. E-Mails verlinken auf die Freigabe – die Entscheidung selbst erfolgt immer angemeldet, gegen den exakten Digest.

Kill-Switch

POST /v1/projects/{id}/pause mit { "reason": "…" } stoppt neue Schreibvorgänge: Neue Vorschläge erhalten HOLD, eingereihte Ausführungen warten. POST /v1/projects/{id}/unpause reiht zurückgehaltene Operationen erneut ein. Beides ist nur per Sitzung (Editor+) möglich und wird protokolliert.

Freischaltung

Vorschläge außerhalb eines Testversuchs erfordern die Guard-Funktion. Ohne sie antwortet die API mit 403 entitlement_required und einem Upgrade-Hinweis; die Konsole zeigt „Guard freischalten“. Siehe Preise.

Guard-API · Docs · COLVO