Invoice lifecycle

Every V3 invoice status, the action calls that move an invoice between them, when you can edit, and which webhooks you can subscribe to.

This page explains each status an invoice can be in, which call or event moves it there, and what
you can still change at each step.

Why status changes are action calls

You never change an invoice's status with PATCH. Each change is its own POST
(/send, /void, /pay, and so on). That way the API knows what happened, not only the result,
and records who did it and when in events and actors. PATCH only edits fields.

Statuses

Created corresponds to V1's Draft, and Opened to V1's Open.

StatusMeaningHow it gets there
CreatedThe invoice exists but hasn't been sent. You can edit or delete it.POST /v3/payments/invoices
OpenedSent to the payer and waiting for payment.POST .../send
OverdueThe dueDate passed without payment.Wingspan, automatically
PendingPayment can't go ahead yet because a condition isn't met, such as outstanding eligibility requirements on the engagement.Wingspan
DisputedThe invoice is under dispute by the payee or the payer.Wingspan, when a dispute is recorded
PaymentInTransitA payment has been started and is being processed.POST .../pay, or a payer payment
PartiallyPaidPart of the amount has been paid.Wingspan, as payments post
PaidWingspan's system has marked the invoice paid.Wingspan
PaidOffPlatformPayment happened outside Wingspan and was recorded.POST .../pay-off-platform
ReturnedThe payment rail returned the payment.Wingspan, from the bank or provider
PartiallyRefundedPart of the payment was refunded.POST .../refund with an amount
RefundedThe full payment was refunded.POST .../refund
CancelledThe invoice was voided.POST .../void
stateDiagram-v2
    [*] --> Created
    Created --> Opened: send
    Created --> [*]: DELETE
    Opened --> Overdue: due date passes
    Opened --> PaymentInTransit: pay
    Overdue --> PaymentInTransit: pay
    Opened --> PaidOffPlatform: pay-off-platform
    Overdue --> PaidOffPlatform: pay-off-platform
    Opened --> Cancelled: void
    Overdue --> Cancelled: void
    PaymentInTransit --> Paid
    PaymentInTransit --> PartiallyPaid
    PaymentInTransit --> Returned
    Paid --> Refunded: refund
    Paid --> PartiallyRefunded: refund (partial)

The diagram shows the common paths. Wingspan can also move an invoice between states on its own,
for example when a payment fails and can be retried.

Actions

CallWho uses itAllowed whenNotes
PATCH /v3/payments/invoices/{invoiceId}PayeeCreated or OpenedOmitted fields stay the same. Send null to clear a nullable field. Splits can't be changed after sending.
DELETE /v3/payments/invoices/{invoiceId}PayeeCreated onlyReturns 204. On any other status it returns 409. Use void instead.
POST .../sendPayeeCreatedMoves to Opened and emails the payer.
POST .../remindPayeeOpened or OverdueEmails a payment reminder.
POST .../voidPayeeAfter sendingCancels a sent invoice. A reason field isn't supported yet and returns 422.
POST .../acceptPayeeOpened or OverdueFor an obligation the payer created: confirms you agree with the amount and terms before payment starts. Sets payeeReviewStatus: Accepted.
POST .../disputePayeeOpened or OverdueRecords your dispute and sets payeeReviewStatus: Disputed. Requires a non-empty reason. Retrying with the same reason returns the existing dispute unchanged. A different reason on an existing dispute returns 409.
POST .../payPayee or linked payerOpened or OverdueCollects payment. See Collect payment.
POST .../pay-off-platformPayeeUnpaidRecords a full payment made outside Wingspan and marks the invoice PaidOffPlatform.
POST .../refundPayeePaid and depositedFull refund, or partial with amount. See Refunds and returns.

All paths are under /v3/payments/invoices/{invoiceId}.

Errors you'll see on transitions

Status and codeCause
409 InvalidStateTransitionThe invoice is in the wrong status for this action, for example accept on a disputed invoice.
409 EligibilityBlockedsend, remind, or pay-off-platform on an engagement whose payment eligibility requirements aren't complete. The detailCode is payments.EngagementNotPaymentsEligible. See Requirements and eligibility.
409 ResourceConflictA duplicate externalId on create.
409 (other)DELETE on an invoice that isn't Created, or a pay-off-platform retry with different payment details.
412 PreconditionFailedpay with an If-Match value that no longer matches the invoice. Read the invoice again and retry with the new ETag.

Branch on code. detailCode is there to help you debug and may change. See
Errors.

Review and approval run separately from status

Two more fields track workflow that sits beside status:

  • payerApprovalStatus (Pending, PreApproved, Approved, Declined) is the payer's approval
    of the obligation. The payer manages it from its side as a payable. See
    Payable lifecycle and statuses.
  • payeeReviewStatus (Pending, Accepted, Disputed, Resubmitted) is your review as the
    payee, set by accept and dispute.

Neither one moves money by itself.

Webhooks

These invoice events are published and you can subscribe to them:

EventFires when
Invoice.PaymentInTransitA payment has been started.
Invoice.PaidWingspan's system marked the invoice paid.
Invoice.DepositConfirmedWingspan's originating bank or provider reported its final processed status for the payment.
Invoice.PaymentFailedA payment attempt failed. The invoice can be paid again.
Invoice.ReturnedThe payment was returned by the rail.
InvoicePayment.Initiated, .Processing, .Completed, .Failed, .Returned, .CancelledEach collection attempt moves through its own status.

Invoice.Paid and Invoice.DepositConfirmed are different signals. Paid is Wingspan's internal
state. DepositConfirmed means Wingspan's originating bank or provider reported its terminal
processed state. It doesn't mean the recipient's bank received the money, that funds are available,
or that the payment can't be returned, so an Invoice.Returned can still follow. See
Paid vs DepositConfirmed.

Events for Created, Opened, Overdue, Cancelled, Disputed, Refunded, and
PaidOffPlatform aren't available to subscribe to yet. To track those changes, read the invoice
with GET /v3/payments/invoices/{invoiceId}, or list invoices with a status filter such as
GET /v3/payments/invoices?filter[status][eq]=Overdue.

Webhook delivery is best effort and can send duplicates. Dedupe on the event id, and recover
anything you missed from the event log. See Webhooks overview
and Recover missed events.

Related pages


Did this page help you?