Reconcile collections and deposits

Match the invoice payments Wingspan collects to the deposits that reach your bank, book fees and payouts in your ledger, and handle returns, refunds, and credits.

When a client pays an invoice through Wingspan, two things happen at different times. First, Wingspan collects the money from your client, and the payment shows up on the invoice. Later, Wingspan pays your proceeds out to your bank in a batch, net of any fees charged to you. That batch is a payout, and it's what appears on your bank statement. Reconciling means tying each deposit back to the invoice payments it contains.

How the money moves

StepWhat you seeWebhook
Your client's payment startsA new entry in the invoice's payments[], status: Pending. The invoice moves to PaymentInTransit.InvoicePayment.Initiated, Invoice.PaymentInTransit
The payment clearsThe entry moves to Completed and gets events.completedAt.InvoicePayment.Completed
The invoice is paidThe invoice moves to Paid.Invoice.Paid
Wingspan's bank processes the depositThe invoice gets events.depositedAt.Invoice.DepositConfirmed
Wingspan pays out your proceedsA Receivables payout, with one transfer for each deposit to your bankNone. Read the payout.

A payment can still fail or come back. A failed attempt moves to Failed (InvoicePayment.Failed, Invoice.PaymentFailed). A bank return after the payment cleared moves the entry to Returned (InvoicePayment.Returned, Invoice.Returned), even after DepositConfirmed. See Paid vs DepositConfirmed for what each signal promises.

Subscribe to the payment events

Create one subscription for the invoice and payment events with Create a webhook subscription:

curl -X POST https://api.wingspan.app/v3/platform/webhooks \
  -H "Authorization: Bearer $WINGSPAN_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "url": "https://hooks.northwindstaffing.example.com/wingspan",
    "subscribedEvents": ["Invoice.*", "InvoicePayment.*"],
    "scope": { "type": "Account", "id": "Qm4xT8vLp2RzW6nYc0aBd3", "shouldIncludeDescendants": true },
    "description": "Receivables reconciliation"
  }'

Each event carries an ID, not a copy of the record. For an Invoice.* event, data.id is the invoice. For an InvoicePayment.* event, data.id is the payment entry and parent.id is the invoice. Read the invoice to get the current state, because events can arrive out of order. Deliveries can repeat, so record each event id and skip ones you've seen. If your endpoint was down, catch up from the event log, which keeps 30 days.

Book each payment

When an entry reaches Completed, post it to your ledger. Debit a Wingspan clearing account and credit the client's receivable. Use the entry's id as the key in your ledger so a repeated event doesn't post twice.

// GET /v3/payments/invoices/Iv7Hn2Qx5Rt8Kw3Lp6Zb9D (trimmed)
{
  "id": "Iv7Hn2Qx5Rt8Kw3Lp6Zb9D",
  "externalId": "INV-2026-0098",
  "status": "Paid",
  "amount": 1200.00,
  "payments": [
    {
      "id": "Pm8Wn2Kq5Rx1Tz7Lb4Hv6C",
      "method": "Card",
      "status": "Completed",
      "amount": 1200.00,
      "currency": "USD",
      "fundsMovementId": "Fm2Lq8Vz5Kt1Wn6Rb3Hx9P",
      "events": { "initiatedAt": "2026-10-14T16:20:05Z", "completedAt": "2026-10-14T16:20:41Z" }
    }
  ],
  "fees": {
    "chargedToPayer": 0.00,
    "chargedToPayee": 34.80,
    "items": [{ "type": "Card", "chargedTo": "Payee", "amount": 34.80 }]
  },
  "amountDetails": {
    "paid": 1200.00,
    "fees": -34.80,
    "deductions": 0.00,
    "payouts": -1165.20,
    "refunds": 0.00
  }
}

amountDetails is the settled cash for the invoice. Money in is positive, and everything that leaves is negative, so the five fields add up to zero:

FieldWhat it holds
paidEverything collected from your client, including any fee your client paid
feesFees charged to you or your client, net of any fee returned by a refund
deductionsDeductions and tax withholding taken from your proceeds
payoutsWhat Wingspan paid out to you
refundsSettled refunds to your client

amount stays the invoice amount you billed. When your client pays a card fee, paid is higher than amount. fees.items[] breaks the fees down by type (Card, Processing, Late, InstantPayout) and by who paid (chargedTo). Book fees charged to you as an expense out of clearing. amountDetails is left out while anything on the invoice is still settling, so wait for it before you book fees and payouts.

Match payouts to your bank deposits

Wingspan groups the money it collects for you into payouts. List your receivables payouts with List payouts:

curl -s -g "https://api.wingspan.app/v3/payments/payouts?filter[balanceType][anyOf][]=Receivables&page[size]=50" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"
// (trimmed)
{
  "data": [
    {
      "id": "Po5Vk2Lq8Wn3Tz6Rb1Hc9M",
      "balanceType": "Receivables",
      "projectionState": "Reconciled",
      "status": "Completed",
      "period": { "start": "2026-10-14", "end": "2026-10-14" },
      "amountDetails": { "gross": 4085.20, "fees": 0.00, "taxWithholding": 0.00, "deductions": 0.00, "disbursed": -4085.20 },
      "transfers": [
        {
          "id": "Tr7Nq3Kx9Lw2Vb5Zm8Pc4D",
          "purpose": "Disbursement",
          "amount": 4085.20,
          "status": "Sent",
          "destination": { "type": "ExternalBankAccount", "institutionName": "First Harbor Bank", "mask": "4421" },
          "events": { "sentAt": "2026-10-15T13:05:00Z" }
        }
      ]
    }
  ],
  "pagination": { "nextPageToken": "" }
}

Each transfer is one deposit. Match it to your bank line by amount, the date in events.sentAt, and the account in destination.mask. A transfer is Sent when Wingspan's bank has processed it. If the bank sends it back, it moves to Failed with failureType: Returned. Check that projectionState is Reconciled before you use the amounts. The deposit amount is abs(amountDetails.disbursed).

To see which invoices are in a payout, list its items with collection=Payout:

curl -s "https://api.wingspan.app/v3/payments/payouts/Po5Vk2Lq8Wn3Tz6Rb1Hc9M/items?collection=Payout" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

Each item has sourceType: Invoice, the invoice ID in sourceId, its amount, and the fundsMovementId of the collection. You can also go from the invoice. Its payouts[].payoutId names the payout each part of an invoice was paid out in. The FutureDebit collection lists amounts that come out of a later payout, such as a payment returned after it was paid out, so a deposit can be net of an earlier return.

When a deposit matches, write your bank transaction ID onto the payout with PATCH /v3/payments/payouts/{payoutId}. Send externalId or metadata with the payout's ETag in If-Match. Then filter on filter[externalId][eq] to find it again. In your ledger, record each deposit as a transfer from the Wingspan clearing account to your bank account. Once the payments, fees, and deposits are all booked, the clearing account is back to zero.

Backfill and month-end checks

To list everything paid in a period, search your invoice rows by paid date. Search rows are a summary, so read each invoice for its payments[]:

curl -s -g "https://api.wingspan.app/v3/search/invoice-rows?filter[events.paidAt][gte]=2026-10-01T00:00:00Z&filter[events.paidAt][lt]=2026-11-01T00:00:00Z&filter[status][noneOf][]=Cancelled&sort[paidAt]=asc&page[size]=100&page[mode]=materialized" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

page[mode]=materialized pages through a fixed snapshot, so rows don't shift while you read. The response summary has the count and amountTotal for the whole period, which is a quick check against your ledger. See Search.

For a month-end check, compare the paid totals from amountDetails with the deposits from your Receivables payouts plus the fees and deductions charged to you. A gap usually means a payment that's still settling or a return that comes out of a later payout.

Returns, refunds, credits, and off-platform payments

Returns

On InvoicePayment.Returned, reverse the payment you booked. The entry's statusReason says why, such as InsufficientFunds. The invoice moves to Returned while a balance is due, and your client can pay again.

Refunds

Read the invoice's refunds[] to follow a refund. When it's Completed, book it out of clearing and back against the client. Settled refunds show in amountDetails.refunds. See Refund an invoice.

Credits

A credit lowers what your client owes without moving money, so it never appears in payments[] or amountDetails. The invoice shows it in creditIds and creditedAmount. Book it as a credit memo. See Credits.

Off-platform payments

A check or wire you recorded with pay-off-platform is an entry with method: OffPlatform. Wingspan never held that money, so it's never in a payout. Match it to your own deposit of the check.

Related pages


Did this page help you?