@mica/sdk (SDK contract v1)
    Preparing search index...

    Type Alias InvoiceActionOutcome

    InvoiceActionOutcome:
        | { invoices: Invoice[]; ok: true }
        | {
            ok: false;
            reason:
                | "unknown_invoice"
                | "not_open"
                | "expired"
                | "invalid_amount"
                | "same_player"
                | "payer_offline"
                | "recipient_offline"
                | "insufficient_funds"
                | "society_unavailable"
                | "debit_failed"
                | "credit_failed"
                | "stranded";
        }

    What paying or declining answers. On ok the list is the player's open invoices re-read after the change, so the store replaces itself rather than removing a row it hopes is gone. The money reasons are Payments' own, passed through so the app can say which.