Checkout abschließen und Zahlung mit der Booking API abwickeln
- Last verified
- Last verified 28. Sept. 2026
Mit dieser Anleitung machen Sie aus einem gefüllten Warenkorb eine bezahlte Bestellung, eine Reservierung oder eine Buchungsanfrage. Sie behandelt die Prüfungen vor dem Checkout, die rechtlichen Einwilligungen, die Übergabe an die gehostete Zahlungsseite, den Zahlungsstatus und die Bereitstellung der Tickets. Der Schnellstart für die Booking API zeigt den kürzesten Weg; diese Anleitung erklärt die Entscheidungen auf diesem Weg.
Bevor Sie beginnen
- Ein Warenkorb mit mindestens einer Position und sein Warenkorb-Token.
- Name, E-Mail-Adresse und Rechnungsadresse des Kunden.
Warenkorb vor dem Checkout prüfen
Lesen Sie den Warenkorb mit request(id: <cart token>) und werten Sie diese Felder aus. Eine Anfrage mit Warenkorb- oder Rechnungs-Token darf nur ein Feld auf oberster Ebene abfragen. Lesen Sie Warenkorb, rechtliche Dokumente und Shop deshalb in getrennten Anfragen.
| Feld | Bedeutung und Vorgehen |
|---|---|
checkoutPolicy.targetState | Bestimmt die Checkout-Mutation: BOOKED wird mit requestPaymentInitiate abgeschlossen, RESERVED mit requestReserve und REQUESTED mit requestRequest. |
checkoutPolicy.compatible und conflicts | Bei false entfernen Sie die Positionen aus conflicts oder schließen sie in einem eigenen Warenkorb ab. |
requiresShipping | Bei true braucht der Kunde eine Lieferadresse in einem Land aus shop.allowedShippingCountries. |
customFieldsCompletion.allRequiredComplete | Bei false erfassen Sie die erforderlichen Antworten vor dem Checkout über die Booking API. Falls Ihre Integration diese nicht erfassen kann, nutzen Sie stattdessen den gehosteten Shop für die Buchung. |
requestItems.requiresWithdrawalEarlyStartConsent | Bei true für eine Position holen Sie die unten beschriebene Einwilligung zum vorzeitigen Beginn ein. |
checkoutHold.secondsRemaining | Verbleibende Zeit, bis eine unbezahlte Bestellung storniert wird. Zeigen Sie sie an, bis die Zahlung erfolgreich ist. Der Countdown dient nur zur Orientierung; KORONA Event prüft den Checkout-Hold beim Absenden des Checkouts erneut. |
Wie Sie Buchungs- und Teilnehmerantworten vor dem Checkout erfassen und speichern, beschreibt Buchungs- und Teilnehmerangaben mit der Booking API erfassen.
customFieldsCompletion zählt die Fragen, die vor der Zahlung beantwortet sein müssen. Ob der Checkout möglich ist, entscheidet nur allRequiredComplete: allComplete ist auch dann false, wenn optionale Fragen offen sind.
requestItems enthält auch Positionen, die der Kunde aus dem Warenkorb entfernt hat. Lesen Sie requestItems(discarded: [false]), um nur die aktuellen Positionen zu erhalten.
Die Adresse eines Angebots im gehosteten Shop besteht aus der Domain des Shops, dem zweistelligen Sprachcode und shopSlug.slugTranslated des Angebots, zum Beispiel https://tickets.example.com/de/fuehrung.
Zulässigkeit von Zahlungsmethoden
Ein Warenkorb-Token gewährt Zugriff auf diesen Warenkorb; er berechtigt jedoch nicht zur Nutzung jeder Zahlungsmethode. KORONA Event prüft die Berechtigung bei der Erstellung oder Änderung des Warenkorbs sowie erneut vor Abschluss des Bestellvorgangs. Eine zuvor gespeicherte Zahlungsmethode kann abgelehnt werden, wenn ihre Berechtigung inzwischen widerrufen wurde.
Die Zahlung auf Rechnung muss durch die geltende Checkout-Richtlinie des Angebots oder Shops freigeschaltet sein. Bei Online-Käufen muss die Zahlung vor Ort durch diese Richtlinien oder die öffentlichen Einstellungen des Veranstaltungsortes für Zahlungen vor Ort freigeschaltet sein. Der unten beschriebene Ablauf für bisherige Kiosks erfordert stattdessen, dass der Veranstaltungsort Zahlungen vor Ort an stationären Verkaufspunkten erlaubt. Für Lieferscheine sind entsprechende Richtlinien sowie die Lieferscheinfunktion des Veranstaltungsortes erforderlich. Für Sammelrechnungen sind ein angemeldeter Ansprechpartner des Rechnungskunden, ein freigeschalteter Wiederverkäuferzugang sowie eine gültige Wiederverkäufervereinbarung erforderlich. Eine Kunden-ID im Payload ersetzt nicht die Anmeldung. Von Mitarbeitern genehmigte Kunden-Workflows können die Genehmigung für den unveränderten Vorgang enthalten; ein gewöhnliches Warenkorb-Token kann diese Genehmigung nicht erzeugen.
Leiten Sie die Berechtigung nicht aus einem gespeicherten paymentMethod, einem vom Client ausgewählten Verkaufskanal oder einem App-Header ab. Wenn der Bezahlvorgang paymentMethod: unauthorized zurückgibt, verwenden Sie eine zulässige Zahlungsmethode oder bitten Sie den Anbieter, die entsprechende Konfiguration zu überprüfen. Versuchen Sie es nicht erneut, indem Sie die Client-Identität oder das Token ändern. Behandeln Sie den abgelehnten Versuch als unvollständig: Er berechtigt weder zur Ticketauslieferung noch zu einer Zahlungsverpflichtung.
POS-Auswahl und Kompatibilität bisheriger Kiosks
Die Liste pos sowie numerische oder automatische Abfragen von pointOfSale erfordern einen authentifizierten Mitarbeiter oder API-Zugang mit Leseberechtigung für Verkaufspunkte. Als vorübergehende Kompatibilitätslösung akzeptiert pointOfSale eine genaue POS-UUID ohne Mitarbeiterzugang. POS-Zuordnungen in Preisregeln und Kontingenten erfordern ebenfalls die POS-Leseberechtigung. Öffentliche Shop-Käufe bleiben an den Online-Verkaufspunkt des Shops gebunden. Bei der Warenkorberstellung über einen bisherigen Kiosk muss die genaue UUID eines physischen Verkaufspunkts desselben Mandanten angegeben werden; POS-Nummern und die automatische Auswahl physischer Verkaufspunkte werden nicht unterstützt. Eine bekannte POS-UUID gilt nicht als Nachweis der Kiosk-Identität.
Kunden hinzufügen
Übermitteln Sie den Kunden mit requestUpdate, wie im Schnellstart gezeigt. Kennzeichnen Sie die Rechnungsadresse mit billing: true und, wenn der Warenkorb einen Versand erfordert, eine Lieferadresse mit shipping: true. Dieselbe Adresse kann beide Kennzeichnungen haben.
Rechtliche Einwilligungen einholen
Laden Sie mit legalDocuments(required: [true]) die Dokumente, denen Kunden zustimmen müssen. Die Liste ist seitenweise aufgeteilt: Solange pageInfo.hasNextPage true ist, fragen Sie die nächste Seite mit after gleich pageInfo.endCursor ab, damit Sie alle erforderlichen Dokumente anzeigen. Zeigen Sie für jedes Dokument ein Kontrollkästchen mit checkboxLabelTranslated an, oder mit nameTranslated, wenn keine Beschriftung hinterlegt ist. Zeigen Sie den Dokumenttext aus contentTranslated an; wenn isUrl den Wert true hat, ist der Inhalt ein Link auf das Dokument.
Senden Sie beim Checkout für jedes erforderliche Dokument eine Zustimmung. legalDocumentVersion muss dem publishedAt-Wert entsprechen, den der Kunde gesehen hat; verwenden Sie nie die aktuelle Uhrzeit. Ändert sich ein Dokument zwischen Anzeige und Checkout, schlägt der Checkout mit einem Fehler zu legalDocumentAcceptances fehl. Laden Sie die Dokumente dann neu und fragen Sie den Kunden erneut.
Einwilligung zum vorzeitigen Beginn einholen
Manche Leistungen dürfen nur verkauft werden, wenn der Kunde zustimmt, dass die Leistung vor Ablauf der gesetzlichen Widerrufsfrist beginnt. Wenn eine Position requiresWithdrawalEarlyStartConsent hat, zeigen Sie ein Kontrollkästchen mit Ihrem Einwilligungstext an und senden Sie das Ergebnis beim Checkout mit:
{
"withdrawalEarlyStartConsent": {
"accepted": true,
"requestItemIds": ["<cart line id>"],
"text": "I agree that the service starts before the withdrawal period ends."
}
}text muss genau der Text sein, den der Kunde gesehen hat. Senden Sie die Einwilligung erst, wenn der Kunde sie erteilt hat; die Zustimmung zu den rechtlichen Dokumenten gilt nicht als Einwilligung.
EU-Garantieinformationen für Waren prüfen
Wenn EU-Garantieinformationen für den Shop aktiviert sind und der Warenkorb Waren enthält, benötigt der öffentliche Checkout den Prüfwert (fingerprint) der Informationen, die dem Kunden angezeigt wurden. Das gilt auch im Warnmodus und für Waren ohne zusätzliche Herstellergarantie.
Rufen Sie die Garantieübersicht mit dem Warenkorb-Token und demselben Accept-Language-Header ab, den Sie beim Checkout verwenden:
query GoodsReview($id: IdOrNumberOrToken!) {
request(id: $id) {
euGoodsReview {
enabled
hasGoods
ready
fingerprint
information {
productId
name
state
brand
model
duration
labelUrl
statement
statementUrl
}
}
}
}Wenn enabled und hasGoods beide true sind:
- Zeigen Sie vor der endgültigen Bestellung den offiziellen Hinweis zur gesetzlichen Gewährleistung und die zurückgegebenen Produktinformationen an. Zeigen Sie für jedes Produkt mit dem Status
readydas GARAN-Label auslabelUrlan und machen Siestatementsowie die optionalestatementUrlzugänglich. Stellen Sie die Garantiebedingungen als reinen Text dar. - Wenn
readyin der Garantieübersichtfalseist, schließen Sie den Checkout nicht ab: Der Händler muss zuerst die Angaben zur erklärten Herstellergarantie vervollständigen. Im Warnmodus kannreadyauch bei einer leeren Listeinformationden Werttruehaben, weil unvollständige Garantien ausgeblendet werden. Der Hinweis und der Prüfwert sind trotzdem erforderlich. - Senden Sie den
fingerprintder angezeigten Übersicht alsinput.euGoodsReviewmitrequestPaymentInitiate, zusammen mit dem Warenkorb-Token und den übrigen erforderlichen Eingaben. Erzeugen Sie den Prüfwert nicht selbst. - Laden Sie die Übersicht nach Änderungen am Warenkorb, an der Sprache oder an den Garantieinformationen neu und zeigen Sie sie erneut an. Gibt der Checkout einen Fehler zu
euGoodsReviewzurück, laden Sie die Übersicht erneut und lassen Sie den Kunden die Informationen vor dem nächsten Versuch prüfen. Wiederholen Sie den Checkout nicht automatisch mit einem neu abgerufenen Prüfwert.
Wenn enabled oder hasGoods den Wert false hat, ist kein Prüfwert erforderlich. Dieselbe Eingabe gilt für requestReserve und requestRequest, wenn diese Vorgänge zur Checkout-Richtlinie des Warenkorbs passen.
Informationen zum Geltungsbereich des Shops, zum offiziellen Hinweis und zur Garantiekonfiguration finden Sie unter Informationen zur EU-Garantie für Waren.
Checkout abschließen
Rufen Sie requestPaymentInitiate mit dem Warenkorb-Token, den rechtlichen Zustimmungen und bei Bedarf der Einwilligung zum vorzeitigen Beginn sowie dem Prüfwert der EU-Garantieübersicht auf. Der Schnellstart zeigt die vollständige Mutation.
| Ergebnis | Vorgehen |
|---|---|
invoice.paymentState ist REQUIRES_PAYMENT | Leiten Sie den Kunden zu paymentLink weiter. |
invoice.paymentState ist PAID | Es ist nichts mehr zu zahlen, zum Beispiel bei einer kostenlosen Bestellung oder weil ein Gutschein den gesamten Betrag deckt. Die Bestellung ist abgeschlossen; leiten Sie nicht weiter, auch wenn paymentLink gesetzt ist. |
invoice ist null | Das Angebot wird vor Ort bezahlt. Die Bestellung ist gebucht, online wird nichts bezahlt. |
errors | Zeigen Sie messageTranslated an. Der Warenkorb bleibt unverändert; korrigieren Sie die Eingabe und versuchen Sie es erneut. |
Entscheiden Sie anhand von invoice.paymentState. Weder eine Rechnung noch ihre Nummer, der Status BOOKED oder ein paymentLink bedeuten, dass noch Geld fällig ist.
Reservieren oder eine Buchungsanfrage senden
Manche Angebote werden beim Checkout nicht bezahlt. Der Veranstalter legt das je Angebot fest, und checkoutPolicy.targetState zeigt, welche Mutation den Warenkorb abschließt:
RESERVED:requestReservehält die Plätze ohne Zahlung frei. Der Kunde erhält eine Reservierungs-E-Mail, und der Veranstalter meldet sich, um Zahlung oder Buchung zu vereinbaren.REQUESTED:requestRequestsendet die Bestellung als Buchungsanfrage an den Veranstalter. Gebucht oder bezahlt wird erst, wenn Mitarbeitende die Anfrage annehmen.
Beide Mutationen nehmen dieselben rechtlichen Zustimmungen und dieselbe Einwilligung zum vorzeitigen Beginn entgegen wie requestPaymentInitiate:
mutation ReserveCart($input: RequestReserveInput!) {
requestReserve(input: $input) {
request {
number
state
reservationExpiresAt
}
errors {
key
message
messageTranslated
}
}
}mutation SubmitInquiry($input: RequestRequestInput!) {
requestRequest(input: $input) {
request {
number
state
}
errors {
key
message
messageTranslated
}
}
}Bei Erfolg ist state gleich RESERVED oder REQUESTED. Zeigen Sie dem Kunden die Bestellnummer aus number und erklären Sie, dass sich der Veranstalter meldet. reservationExpiresAt ist der Zeitpunkt, zu dem eine unbezahlte Reservierung verfällt; das Feld ist leer, wenn der Veranstalter keine Reservierungsfrist festgelegt hat. Hat der Warenkorb einen anderen Zielstatus, schlägt die Mutation mit einem Fehler zu checkoutPolicy fehl.
Zahlung an die gehostete Zahlungsseite übergeben
paymentLink öffnet die für diese Rechnung konfigurierte gehostete Zahlungsseite in der Sprache, die in Ihrem Accept-Language-Header angegeben ist. Wenn die Zahlungsseite des Shops aktiviert ist, wird der durch X-Tenant-Domain identifizierte Shop verwendet. Die zurückgegebene URL verwendet möglicherweise die kanonische Domain dieses Shops anstelle des genauen Domain-Alias, den Sie angegeben haben. Verwenden Sie die zurückgegebene URL unverändert. Der Kunde wählt dort eine Zahlungsart und bezahlt. Die Seite ermöglicht erneute Zahlungsversuche, erfasst aber keine erforderlichen Buchungs- oder Teilnehmerantworten. Ist customFieldsCompletion.allRequiredComplete false, erfassen Sie diese vor dem Checkout wie in Buchungs- und Teilnehmerangaben mit der Booking API erfassen beschrieben. Falls Ihre Integration diese nicht erfassen kann, nutzen Sie stattdessen den gehosteten Online-Shop des Veranstalters für die Buchung.
Speichern Sie das Rechnungs-Token aus invoice.accessToken. Sie brauchen es, um die Zahlung zu verfolgen.
paymentLink enthält das Rechnungs-Token. Behandeln Sie den Link wie ein Passwort: Öffnen Sie ihn unverändert und halten Sie ihn aus Analysetools, Logs und geteilten URLs heraus.
Zahlung verfolgen
Lesen Sie die Rechnung mit dem Rechnungs-Token, zum Beispiel mit der Abfrage PaymentStatus aus dem Schnellstart. Fragen Sie den Status alle paar Sekunden ab, solange der Kunde bezahlt, und hören Sie auf, sobald die Zahlung endgültig ist.
| Feld | Bedeutung |
|---|---|
paymentState: PAID | Die Zahlung war erfolgreich. |
paymentState: REQUIRES_PAYMENT | Noch keine erfolgreiche Zahlung. payments listet die Versuche und ihren state. |
paymentIntentCreateError | Warum keine neue Zahlung starten kann: bereits bezahlt, bereits in Bearbeitung oder Bestellung storniert. |
payments.providerInitializationFailed | Der Zahlungsanbieter konnte diesen Versuch nicht starten. Der Kunde kann paymentLink erneut öffnen. |
request.state: CANCELED | Die Bestellung wurde storniert, zum Beispiel weil der Checkout-Hold vor der Zahlung abgelaufen ist. Legen Sie einen neuen Warenkorb an. |
Verlassen Sie sich auf die Rechnung und nicht darauf, dass der Kunde auf eine Seite zurückkehrt: Die Rückkehr vom Zahlungsanbieter beweist keine Zahlung, und Zahlungen können auch dann erfolgreich sein, wenn der Kunde den Browser schließt. Zeigen Sie keine Bestätigung an, solange die Zahlung aussteht oder fehlgeschlagen ist.
Tickets bereitstellen
Nach der Zahlung liefert request.shareablePublicTicketsUrl(format: PDF) einen Link zur Ticketseite des Kunden. Die Ticketaktivierung kann noch ausstehen, obwohl diese URL bereits vorhanden ist. Die Seite stellt die Tickets bereit, sobald die Aktivierung abgeschlossen ist. Verwenden Sie format: PKPASSES für Apple-Wallet-Pässe, sofern diese verfügbar sind.
Abgelaufenen Checkout-Hold behandeln
Erreicht checkoutHold.secondsRemaining vor der Zahlung null, storniert KORONA Event die Bestellung und gibt ihre Plätze frei. Rufen Sie requestCancelExpiredCheckoutHold mit dem Warenkorb-Token als requestId oder dem Rechnungs-Token als invoiceToken auf, um die Plätze sofort freizugeben, und bieten Sie dem Kunden danach einen neuen Warenkorb an. Ob der Checkout-Hold abgelaufen ist, entscheidet KORONA Event: Läuft er noch, schlägt der Aufruf mit checkoutHold not_expired fehl.
Fehlerbehebung
| Problem | Was Sie prüfen |
|---|---|
Der Checkout schlägt mit legalDocumentAcceptances fehl | Jedes erforderliche Dokument ist mit seinem aktuellen publishedAt als legalDocumentVersion zugestimmt. |
Eine Warenkorbänderung schlägt mit checkoutHold fehl | Der Checkout-Hold ist abgelaufen und die Bestellung wurde storniert. Legen Sie einen neuen Warenkorb an. |
| Nach dem Checkout fehlt eine Antwort | Lesen Sie den Warenkorb mit seinem Token, bevor Sie es erneut versuchen. Ist state gleich BOOKED, war der Checkout bereits erfolgreich; das Rechnungs-Token steht in invoices { accessToken }. |
Eine Anfrage mit Token schlägt mit single top level field fehl | Die Anfrage fragt mehr als ein Feld auf oberster Ebene ab. Senden Sie jedes Feld in einer eigenen Anfrage. |
Der Checkout schlägt mit checkoutPolicy fehl | Die Mutation passt nicht zu checkoutPolicy.targetState, oder der Warenkorb mischt Angebote mit unterschiedlichem Zielstatus. |