Bird für Craft CMS

Verwendung

Der normale Weg

Eine Bestellung wird bezahlt. Commerce feuert sein Event, Bird stellt einen Job in die Warteschlange, und der Job baut ein Payload und legt einen Beleg in Moneybird an. Eine Zeile geht in Birds Belegtabelle, eine Zahlung wird auf der Rechnung erfasst, und das Moneybird-Panel im Bestellbildschirm füllt sich.

Sobald das Plugin eingerichtet ist, müssen Sie dafür nichts tun.

Der Bestellbildschirm

Jede Commerce-Bestellung bekommt ein Moneybird-Panel:

  • was gebucht wurde, mit einem Link nach Moneybird
  • die umsatzsteuerliche Behandlung und die USt-IdNr., die Bird aus der Adresse gelesen hat
  • An Moneybird senden — jetzt buchen, was der Trigger auch sagt
  • Rückerstattungen gutschreiben (Pro) — noch nicht gutgeschriebene Rückerstattungstransaktionen gutschreiben
  • Rechnungsvorschau — das exakte JSON, ohne es zu senden

Die Vorschau führt dieselbe Invoices::buildPayload() aus wie der Push. Es gibt genau eine Stelle im Code, an der aus einer Bestellung Moneybird-JSON wird, und die Vorschau ist sie — was Ihnen vor dem Buchen angezeigt wird, ist also Byte für Byte das, was gebucht wird, samt Steuersatz-IDs, und genau dort sitzen die Fehler.

Wie die Steuerlogik entscheidet

SituationBehandlungVerwendeter Satz
Kunde in Ihrem HeimatlandInlandDer zugeordnete Prozentsatz
EU-Unternehmen, zum Land passende USt-IdNr., keine Steuer berechnetReverse ChargeIhr Satz für btw verlegd
EU-Verbraucher, OSS an (Pro)OSSDer Satz dieses Landes
EU-Verbraucher, OSS ausHeimatsatzDer zugeordnete Prozentsatz
Außerhalb der EUAusfuhrIhr Ausfuhrsatz

Commerce entscheidet, was berechnet wird; Bird entscheidet, wo es gebucht wird. Die Steuer-Engine von Commerce kennt Ihre Zonen, Ihre Sätze und Ihre USt-IdNr.-Prüfungen bereits. Das hier noch einmal herzuleiten gäbe Ihrem Shop zwei Antworten, die auseinanderdriften — und die, die der Kunde tatsächlich gezahlt hat, ist die von Commerce.

Beachten Sie die dritte Spalte der Reverse-Charge-Zeile. Reverse Charge ist eine Aussage darüber, was berechnet wurde, nicht darüber, was hätte berechnet werden können. Eine USt-IdNr. auf einer Bestellung, die trotzdem 21% gezahlt hat, ist ein Shop, in dem die USt-IdNr.-Prüfung von Commerce nie eingeschaltet wurde — und es als Reverse Charge zu buchen würde die Erklärung um genau das mindern, was der Kunde gezahlt hat. Bird bucht, was passiert ist.

Backfill

Bestellungen, die bei der Installation von Bird bereits bezahlt waren, bleiben unangetastet, bis Sie danach fragen.

php craft bird/sync/backfill --since=2026-01-01 --dry-run
php craft bird/sync/backfill --since=2026-01-01 --limit=250

--dry-run meldet jede Bestellung, die gebucht würde, und unter welcher Behandlung, ohne etwas zu senden. Führen Sie das zuerst aus. --limit steht standardmäßig auf 100, damit ein Backfill nicht von selbst in das Rate Limit läuft.

Rückerstattungen (Pro)

Eine Rückerstattungstransaktion aus Commerce wird zu einer Moneybird-Gutschrift, eine je Transaktion, zu dem Satz, mit dem die Steuer draufkam. Gutschriften werden über den Hash der Rückerstattungstransaktion geschlüsselt, dieselbe Rückerstattung zweimal gutzuschreiben ist also nicht möglich — der eindeutige Index auf (Bestellung, Art, Quelle) weist es ab.

php craft bird/sync/refunds 1042

Oder klicken Sie bei der Bestellung auf Rückerstattungen gutschreiben.

Der Webhook (Pro)

Bird sendet Rechnungen; in Moneybird werden sie bezahlt — einem Bankfeed zugeordnet oder von Hand abgehakt. Ohne den Webhook ist die Vorstellung Ihrer Website von „bezahlt“ das, was der Zahlungsanbieter beim Checkout gesagt hat, und das verfehlt jede Überweisung.

php craft bird/webhooks/install
php craft bird/webhooks/info
php craft bird/webhooks/remove

Webhook installieren registriert ihn und hinterlegt das Signaturgeheimnis, das Moneybird genau einmal zurückgibt, beim Anlegen. Jede Zustellung wird danach gegen den Header Moneybird-Signature geprüft — HMAC-SHA256 über {timestamp}.{roher Body}, in konstanter Zeit verglichen und abgelehnt, wenn der Zeitstempel mehr als fünf Minuten abweicht. Während einer Geheimnisrotation treten mehrere Signaturwerte auf, jeder Treffer zählt also.

Kein Geheimnis, keine Signatur oder ein veralteter Zeitstempel: keine Anfrage. Es scheitert geschlossen.

Bird abonniert die Events für bezahlt, überfällig und uneinbringlich, für beide Belegtypen. Setzen Sie Status bei bezahlt, wenn eine bezahlte Rechnung die Commerce-Bestellung umsetzen soll.

Twig

{% set document = craft.bird.documentForOrder(order) %}

{% if document and document.getIsBooked() %}
    <p>Rechnung {{ document.getLabel() }} — {{ document.getStateLabel() }}</p>

    {# Eine Capability-URL: nur dem Kunden zeigen, dem die Bestellung gehört. #}
    {% if document.publicUrl %}
        <a href="{{ document.publicUrl }}">Ihre Rechnung ansehen</a>
    {% endif %}
{% endif %}

{% set vat = craft.bird.vatTreatment(order) %}
{% if vat.reverseCharge %}
    <p>Steuerschuldnerschaft des Leistungsempfängers — {{ vat.vatNumber }}</p>
{% endif %}

craft.bird.documentsForOrder(order) gibt die Rechnung und jede Gutschrift zurück. craft.bird.invoiceUrl(order) ist eine Abkürzung zur öffentlichen URL, und craft.bird.isConfigured() gibt es, damit ein Template auf einer noch nicht eingerichteten Installation still bleiben kann.

Konsole

craft bird/sync/status                    # Verbindung, Edition, Belegzahlen
craft bird/sync/order 1042                # eine Bestellung buchen, per Referenz, Nummer oder ID
craft bird/sync/order 1042 --force        # erneut buchen, obwohl sie gebucht ist
craft bird/sync/backfill --since=2026-01-01 --dry-run --limit=100
craft bird/sync/retry --limit=100         # die fehlgeschlagenen Pushes mit verbleibenden Versuchen
craft bird/sync/refunds 1042              # die Rückerstattungen einer Bestellung gutschreiben

craft bird/inspect/preview 1042           # das exakte JSON, ohne zu senden
craft bird/inspect/tax-rates              # IDs für die Steuersatzzuordnung
craft bird/inspect/ledger-accounts
craft bird/inspect/financial-accounts
craft bird/inspect/workflows
craft bird/inspect/administrations

craft bird/webhooks/install
craft bird/webhooks/list
craft bird/webhooks/info
craft bird/webhooks/remove

craft bird/log/prune --days=30            # gehört in einen Cron
craft bird/log/clear

Es kann keinen Checkout aufhalten

Alles, was während des Checkouts läuft, scheitert offen. Jeder Trigger schluckt seine eigenen Fehler, und der Push läuft standardmäßig über die Warteschlange — eine Störung bei Moneybird, ein abgelaufenes Token oder ein Rate Limit können also nie der Grund sein, warum ein Kunde nicht zahlen konnte. Was Sie stattdessen bekommen, ist eine Belegzeile im Zustand failed, ein Grund dazu und bird/sync/retry.

Das Einzige, was geschlossen scheitert, ist ein nicht zugeordneter Steuersatz: Bird weist die Bestellung ab und nennt den fehlenden Prozentsatz. Diese Ablehnung passiert auf Birds Seite der Linie, nicht auf der des Checkouts.

Denselben Umsatz zweimal buchen

Geht nicht. {{%bird_documents}} ist eindeutig über (orderId, kind, sourceKey)sourceKey ist leer für die Rechnung und der Hash der Rückerstattungstransaktion für eine Gutschrift — und dieser Index ist die Garantie. Ein wiederholter Job, ein doppelt geklickter Button und ein Webhook, der die Warteschlange überholt, stoßen alle darauf.

Stirbt ein Push in der Lücke zwischen „Moneybird hat die Rechnung angelegt“ und „Bird hat die Zeile geschrieben“, sucht der nächste Versuch die Rechnung mit GET /sales_invoices/find_by_reference/{reference}.json und übernimmt sie, statt eine zweite zu buchen.


Bird ist ein unabhängiges Plugin. Es steht in keiner Verbindung zu Moneybird und wird von Moneybird weder unterstützt noch gesponsert. „Moneybird“ ist eine Marke des jeweiligen Rechteinhabers.