Logocowtic
Öffentliche API

Veranstaltung absagen

Veranstaltung über die öffentliche API absagen und zahls.ch-Zahlungen optional erstatten

Eine Absage über die API macht genau dasselbe wie das Dashboard: die Veranstaltung wird auf CANCELLED gesetzt, ihre offenen und abgeschlossenen Bestellungen werden storniert, Kontingente werden freigegeben und ausgegebene Tickets entwertet. Die Rückerstattung des Geldes ist eine getrennte, ausdrückliche Entscheidung.

Rückerstattungen nur auf Wunsch

refund ist standardmässig false. Eine Anfrage ohne Body oder mit "refund": false sagt die Veranstaltung ab und bewegt kein Geld. Nur "refund": true stellt Rückerstattungen in die Warteschlange.

Authentifizierung und Scopes

Alle drei Operationen nutzen denselben Organisations-API-Schlüssel wie der Rest der API — siehe Authentifizierung.

OperationMethode und PfadScope
Veranstaltung absagenPOST /events/{eventId}/cancelevents:cancel
Rückerstattungsstatus lesenGET /events/{eventId}/refundsevents:read
Fehlgeschlagene Rückerstattungen erneut versuchenPOST /events/{eventId}/refunds/retryevents:cancel

Ein Schlüssel erreicht nur Veranstaltungen der eigenen Organisation. Eine fremde Veranstaltung antwortet mit 404, nie mit 403, damit sich keine Veranstaltungs-IDs erraten lassen.

Veranstaltung absagen

Idempotency-Key ist Pflicht, siehe Retries und Idempotenz weiter unten.

curl -X POST https://api.cowtic.com/api/v1/events/evt_2f8a/cancel \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{ "refund": true }'
{
  "eventId": "evt_2f8a",
  "status": "CANCELLED",
  "cancelledOrderIds": ["ord_91c", "ord_44b", "ord_07e"],
  "failedOrderIds": [],
  "refunds": {
    "queued": 2,
    "queuedOrderIds": ["ord_91c", "ord_44b"],
    "skipped": {
      "refundable": 0,
      "cancelled_earlier": 1,
      "unpaid": 3,
      "free": 1,
      "manual_payment": 0,
      "refunded": 0,
      "refund_pending": 0,
      "refund_failed": 0,
      "refund_unknown": 0,
      "refund_unsupported": 0
    }
  },
  "refundStatusUrl": "/api/v1/events/evt_2f8a/refunds"
}
FeldBedeutung
cancelledOrderIdsBestellungen, die diese Anfrage storniert hat. Bei einer Wiederholung leer — sie waren bereits storniert.
failedOrderIdsBestellungen, die nicht storniert werden konnten. Sie behalten ihre Tickets und werden nie erstattet: zeigen Sie sie einer Person an.
refundsnull, wenn refund false war. Sonst das, was diese Anfrage an die Rückerstattungs-Warteschlange übergeben hat.
refunds.queuedOrderIdsBestellungen, deren Rückerstattung jetzt in der Warteschlange steht.
refunds.skippedÜbergangene Bestellungen, gezählt nach Eignung.
refundStatusUrlPfad auf diesem API-Host, unter dem Sie das Ergebnis pro Bestellung abfragen.

Ohne Rückerstattung ist der Aufruf kürzer:

curl -X POST https://api.cowtic.com/api/v1/events/evt_2f8a/cancel \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Idempotency-Key: 4f1d0f8c-7a1e-4d51-9a1b-0d1f0b2d9a77"
{
  "eventId": "evt_2f8a",
  "status": "CANCELLED",
  "cancelledOrderIds": ["ord_91c", "ord_44b", "ord_07e"],
  "failedOrderIds": [],
  "refunds": null,
  "refundStatusUrl": "/api/v1/events/evt_2f8a/refunds"
}

Rückerstattungen laufen asynchron

POST /events/{eventId}/cancel antwortet, sobald die Bestellungen storniert und die Rückerstattungen eingereiht sind. Danach schickt ein Hintergrund-Worker jede Rückerstattung an zahls.ch. Ein 200 bedeutet eingereiht, nicht erstattet — das Ergebnis lesen Sie unter refundStatusUrl.

Welche Bestellungen erstattet werden

Nur Bestellungen, die tatsächlich über zahls.ch bezahlt und noch nicht erstattet wurden. Jede andere Bestellung erscheint mit ihrem Grund unter refunds.skipped:

EignungBedeutung
refundableAbgeschlossene Bestellung mit eingezogener zahls.ch-Zahlung. Wird eingereiht.
cancelled_earlierVor der Veranstaltung storniert, Zahlung weiterhin eingezogen. Wird nie automatisch erstattet — sie kann bereits von Hand erstattet worden sein. Erstatten Sie sie bei Bedarf über die Bestellung im Dashboard.
unpaidCheckout nie abgeschlossen. Nichts zu erstatten.
freeGratis oder vollständig rabattiert. Nichts zu erstatten.
manual_paymentAusserhalb von zahls.ch als bezahlt markiert. Erstatten Sie über den Kanal, der das Geld entgegengenommen hat.
refundedBereits erstattet.
refund_pendingEine Rückerstattung ist bereits eingereiht oder unterwegs.
refund_failedzahls.ch hat die Rückerstattung abgelehnt. Erneut versuchbar.
refund_unknownzahls.ch hat nie geantwortet, die Rückerstattung kann ausgeführt worden sein oder nicht. Wird nie automatisch wiederholt — prüfen Sie zuerst die Transaktion auf zahls.ch.
refund_unsupportedDie Zahlungsart lässt sich über zahls.ch nicht erstatten.

Retries und Idempotenz

Idempotency-Key ist bei POST /events/{eventId}/cancel und POST /events/{eventId}/refunds/retry erforderlich; fehlt der Header, antwortet die API mit 400.

  • Dieselbe Anfrage mit demselben Schlüssel und demselben Body liefert die gespeicherte Antwort und führt nichts erneut aus. Die Wiederholung trägt Idempotency-Replayed: true.
  • Derselbe Schlüssel mit anderem Body ergibt 409.
  • Nutzen Sie einen neuen Schlüssel für einen wirklich neuen Versuch, etwa nachdem Sie Ihre zahls.ch-Verbindung repariert haben.

Die Operation ist auch mit neuem Schlüssel gefahrlos wiederholbar: eine bereits abgesagte Veranstaltung wird nicht erneut abgesagt, eine bereits stornierte Bestellung bleibt unangetastet, und ein bereits angelegter Rückerstattungssatz wird nie dupliziert — keine Bestellung wird zweimal erstattet. Die allgemeinen Regeln stehen unter Idempotenz.

Rückerstattungsstatus lesen

curl https://api.cowtic.com/api/v1/events/evt_2f8a/refunds \
  -H "X-Api-Key: YOUR_API_KEY"
{
  "eventStatus": "CANCELLED",
  "total": 2,
  "counts": { "PENDING": 0, "SUCCEEDED": 1, "FAILED": 1, "UNSUPPORTED": 0 },
  "stalePending": 0,
  "unknownOutcome": 0,
  "refundedAmount": 50,
  "currency": "CHF",
  "refunds": [
    {
      "id": "prf_7d1",
      "orderId": "ord_91c",
      "orderStatus": "CANCELLED",
      "customer": { "name": "Ada Guest", "email": "guest@example.com" },
      "status": "SUCCEEDED",
      "currency": "CHF",
      "paidAmount": 50,
      "requestedAmount": 50,
      "refundedAmount": 50,
      "failureReason": null,
      "attempts": 1,
      "lastAttemptAt": "2026-09-14T09:12:04.881Z",
      "updatedAt": "2026-09-14T09:12:05.102Z",
      "stale": false,
      "outcomeUnknown": false,
      "providerTransactionId": "5012345",
      "providerRefundId": "9001"
    },
    {
      "id": "prf_7d2",
      "orderId": "ord_44b",
      "orderStatus": "CANCELLED",
      "customer": { "name": "Blaise Guest", "email": "blaise@example.com" },
      "status": "FAILED",
      "currency": "CHF",
      "paidAmount": 12.5,
      "requestedAmount": 12.5,
      "refundedAmount": 0,
      "failureReason": "Refund limit reached for this account",
      "attempts": 1,
      "lastAttemptAt": "2026-09-14T09:12:04.902Z",
      "updatedAt": "2026-09-14T09:12:04.960Z",
      "stale": false,
      "outcomeUnknown": false,
      "providerTransactionId": "5012346",
      "providerRefundId": null
    }
  ]
}
FeldBedeutung
countsRückerstattungssätze nach Status. PENDING heisst eingereiht oder unterwegs.
stalePendingPENDING-Sätze, die seit einer Weile kein Worker angefasst hat. Ein erneuter Versuch nimmt sie mit.
unknownOutcomeRückerstattungen, die zahls.ch nie bestätigt hat. Prüfen Sie die Transaktion auf zahls.ch, bevor Sie es erneut versuchen.
refundedAmount / paidAmountBeträge in der Währung der Bestellung, nicht in kleinsten Einheiten.
failureReasonDie Meldung von zahls.ch. Nur Anbietertext — Zugangsdaten sind nie enthalten.
providerTransactionId / providerRefundIdzahls.ch-Referenzen für den Abgleich.

Fragen Sie diesen Endpunkt ab, bis counts.PENDING bei 0 liegt. Wenige Sekunden Abstand genügen; beachten Sie die Rate Limits.

Fehlgeschlagene Rückerstattungen erneut versuchen

Reiht die Sätze der Veranstaltung mit FAILED, UNSUPPORTED und liegen gebliebene Sätze erneut ein. Die Veranstaltung muss bereits abgesagt sein, sonst antwortet der Aufruf mit 400 und dem Detail EVENT_NOT_CANCELLED.

curl -X POST https://api.cowtic.com/api/v1/events/evt_2f8a/refunds/retry \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Idempotency-Key: 9a3cbe44-2f9d-4f9e-8b4f-3c2d1a7b5e60"
{
  "queued": 1,
  "queuedOrderIds": ["ord_44b"],
  "skipped": {
    "refundable": 0,
    "cancelled_earlier": 0,
    "unpaid": 0,
    "free": 0,
    "manual_payment": 0,
    "refunded": 1,
    "refund_pending": 0,
    "refund_failed": 0,
    "refund_unknown": 0,
    "refund_unsupported": 0
  },
  "refundStatusUrl": "/api/v1/events/evt_2f8a/refunds"
}

Sätze unter refund_unknown bleiben bewusst aussen vor: zahls.ch kann sie bereits ausgeführt haben, deshalb muss eine Person nachsehen, bevor sie erneut gesendet werden.

Fehler

Statustype-EndungdetailWas zu tun ist
400validation-errorrefund ist kein BooleanSenden Sie true oder false, oder lassen Sie den Body weg
400bad-requestIdempotency-Key header is required for this endpointHeader ergänzen
400bad-requestEVENT_NOT_CANCELLEDVeranstaltung absagen, bevor Sie ihre Rückerstattungen erneut versuchen
401unauthorizedAPI-Schlüssel fehlt oder ist ungültigSchlüssel prüfen
403forbiddenAPI key lacks scope events:cancelScope vergeben oder Schlüssel damit rotieren
404not-foundEVENT_NOT_FOUNDDie Veranstaltung gibt es in dieser Organisation nicht
409idempotency-conflictSchlüssel mit anderem Body wiederverwendetNeuen Schlüssel nutzen
503service-unavailableEVENT_PAYMENT_CREDENTIALS_REQUIREDzahls.ch im Dashboard verbinden oder ohne refund absagen

Scheitert eine Anfrage an Validierung, Berechtigung oder der zahls.ch-Prüfung, wird nichts abgesagt. Fehler einzelner Bestellungen sind keine Fehlerantworten: sie stehen in failedOrderIds und im Rückerstattungsstatus. Das gemeinsame Format beschreibt Fehler.

Mit dem SDK

import { Cowtic } from "@cowtic/sdk";

const cowtic = new Cowtic({ apiKey: process.env.COWTIC_API_KEY! });

const { data: cancellation } = await cowtic.events.cancel("evt_2f8a", { refund: true });
console.log(cancellation.refunds?.queuedOrderIds);

const { data: status } = await cowtic.events.refunds("evt_2f8a");
if (status.counts.FAILED > 0) {
  await cowtic.events.retryRefunds("evt_2f8a");
}

Das SDK erzeugt pro Aufruf einen Idempotency-Key; mit { idempotencyKey } geben Sie einen eigenen mit, damit eine Wiederholung die erste Antwort liefert.

On this page