Components of a payable
Every field you send when you create a payable in the Wingspan V3 API, and the fields Wingspan returns on it.
This page lists the fields you send to create or update a payable, and the fields Wingspan returns so you can track and reconcile it. For the step-by-step flow, see Create a payable.
Create request fields
Send these to POST /v3/payments/payables. The body rejects unknown fields with 422.
| Field | Required | Type | What it does |
|---|---|---|---|
payeeId | One of payeeId or payeeEngagementId | string | Your Payee record for the person you're paying (called a collaborator in V1). Never an Account ID. Wingspan uses the payee's default engagement. |
payeeEngagementId | One of payeeId or payeeEngagementId | string | A specific PayeeEngagement to pay under. Send this instead of payeeId when the payee has more than one engagement with you. Sending both returns 422. |
currency | Yes | string | USD, CAD, CZK, EUR, GBP, INR, or PLN. Applies to every amount on the payable. |
dueDate | Yes | date | YYYY-MM-DD. |
lineItems | Yes, at least one | array | What you're paying for. See Line items. |
externalId | No | string | Your own ID for this payable, up to 255 characters. Echoed on every read and filterable. A duplicate under the same payer Account returns 409 ResourceConflict; create is never an upsert. |
payeeAccountId | No | string | A hint for the payee's Account. If you send it, it must match the Account Wingspan resolves from the Payee, or the request fails with 422. |
splits | No | array | Pay part of this payable on to other payees. See Splits. |
notes | No | string | Notes shown on the payable. |
metadata | No | object | Up to 50 string key-value pairs. Keys up to 40 characters, values up to 500. |
quickbooks | No | object | Links the payable to a QuickBooks Online bill created outside Wingspan. See QuickBooks Online. |
Two fields appear in the schema but aren't supported on create yet: payPeriodId and sourceWorkLogIds. Sending either returns 422. To create a payable from logged work, approve a work log instead.
You don't send amount or status. Wingspan computes amount from the line items, and every new payable starts in Created. To change status, use the action endpoints described in Payable lifecycle and statuses.
V1 fields such as collaboratorId, creditFeeHandling, acceptedPaymentMethods, lateFeeHandling, notificationPreferences, labels, and status on create don't exist on the V3 payable. See Migrating from V1.
Line items
Each entry in lineItems describes one thing you're paying for.
| Field | Type | What it does |
|---|---|---|
description | string | The line's title. |
detail | string | A secondary line shown under the description. |
lineItemType | string | Services, Expense, Reimbursement, Bonus, Commission, or Custom. Replaces V1's reimbursableExpense flag. |
totalCost | number | The line total. Send totalCost, or quantity and unitCost, not both. |
quantity | number | Number of units, such as hours. |
unitCost | number | Price per unit. Replaces V1's costPerUnit. |
unit | string | Unit label, such as hours or each. |
discount | object | percentage (0 to 100) or amount, not both, plus an optional description. Sending both returns 422 with ConflictingFields. |
accounting | object | Accounting dimensions stored and returned as sent: glAccountCode, class, location, project, item, taxCode. |
splits | array | Per-line splits. You can't use per-line splits and payable-level splits on the same payable. |
metadata | object | String key-value pairs for this line. |
Amounts are plain decimal numbers in the payable's currency, such as 1840.00. Never send cents as integers. An amount with more decimal places than the currency allows returns 422.
{
"payeeId": "q7Lm2VxR9tKd4WnB8sHc1Z",
"currency": "USD",
"dueDate": "2026-10-09",
"externalId": "NW-AP-20431",
"notes": "September route coverage",
"lineItems": [
{
"description": "Route coverage, September",
"lineItemType": "Services",
"quantity": 40,
"unitCost": 46.00,
"unit": "hours",
"accounting": { "glAccountCode": "6100", "project": "NW-ROUTES" }
},
{
"description": "Fuel reimbursement",
"lineItemType": "Reimbursement",
"totalCost": 112.50
}
],
"metadata": { "region": "west" }
}Splits
A split sends a fixed part of the payable on to another payee. Use it when you pay one party and part of that payment belongs to someone they work with. Each split needs:
| Field | Required | What it does |
|---|---|---|
payeeId | Yes | The Payee record of the person receiving the split. |
payeeEngagementId | Yes | The engagement the split is paid under. |
amount | Yes | The fixed amount owed to this payee. |
currency | Yes | Must equal the payable's currency. |
description, externalId, metadata | No | For your records. |
The total of the splits can't exceed the payable amount (or the line amount, for per-line splits). When you open the payable, Wingspan creates a child payable for each split and fills in splits[].payableId. Child payables carry parentInvoiceId, so you can list them with filter[parentInvoiceId][eq].
Two limits apply today. Paying a payable with splits directly to a Payee that hasn't linked a Wingspan Account returns 422, and recording an off-platform payment on a payable with splits returns 409.
Response fields you'll use
The response includes everything you sent, plus these fields.
| Field | What it tells you |
|---|---|
id | The payable's ID. |
accountId | Your payer Account, which owns the payable. |
payerId, payeeId | The relationship records for each side. |
payeeAccountId, payerAccountId | The resolved Accounts, or null until resolved. A Payee with no linked Account keeps payeeAccountId as null and can still be paid. |
payeeEngagementId | The engagement the payable is paid under. |
status | The payment lifecycle status. See Payable lifecycle and statuses. |
pendingStatusReason | Why a Pending payable is held, such as MemberPayoutMethodNotSelected. null in every other status. See Find incomplete payables. |
payerApprovalStatus | Your approval decision: Pending, PreApproved, Approved, or Declined. |
payeeReviewStatus | The payee's review: Pending, Accepted, Disputed, or Resubmitted. |
amount | The contractual amount, computed from the line items. |
invoiceNumber | The payee-issued invoice number, for AP reconciliation. |
scheduledPaymentDate | A date you've chosen for payment to start, if set. |
fees | Always present. chargedToPayer, chargedToPayee, and items[] (each with type, chargedTo, and amount). |
amountDetails | The settled breakdown: paid, fees, deductions, payouts, refunds. Omitted until settled activity is complete. |
payments[] | Each collection attempt, with status, method, amount, and statusReason for failed or returned attempts. |
payouts[] | Each payout leg to the payee, with status and a masked destination. |
refunds[] | Each refund, with status and amount. |
payrollRunId | The payroll run that selected this payable, if any. |
recurringPayableId | The recurring payable that generated it, if any. |
parentInvoiceId | The parent document, when this payable was created from a split. |
deductionIds | Deductions applied to this payable. |
events | Timestamps for each transition, such as createdAt, openedAt, paymentInTransitAt, paidAt, depositConfirmedAt, cancelledAt, refundedAt, paidOffPlatformAt. A missing key means the transition hasn't happened. |
actors | Who triggered each transition, such as createdBy, openedBy, paidBy. |
Read responses also carry an ETag header. Send it back as If-Match when you update, open, accept, or reject the payable. See Concurrency and ETags.
Expanding related resources
On GET /v3/payments/payables/{payableId} you can inline related resources with expand: payer, payee, attachments, and splits.payee. For example, ?expand=payee&expand=attachments. An unsupported value returns 422. Expansion isn't available on list results.
Attachments
Files are uploaded once to the vault, then attached by ID. Upload the file with /v3/compliance/vault-files (see Files and documents), then attach it:
curl -X POST "https://api.wingspan.app/v3/payments/payables/Hb4Xk9Qw2Rt7Vn1Mz8Pc3L/attachments" \
-H "Authorization: Bearer $WINGSPAN_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "memberFileId": "Vf5Rk2Xw9Lq3Tm7Zn1Pb4D", "caption": "Signed timesheet" }'Attaching a private file gives the payee ongoing read access to it, and detaching doesn't take that access away. Don't attach anything the payee shouldn't keep. List attachments with GET /v3/payments/payables/{payableId}/attachments and remove one with DELETE /v3/payments/payables/{payableId}/attachments/{attachmentId}.
The payable PDF
Once a payable is opened, GET /v3/payments/payables/{payableId}/pdf returns a 302 redirect to a short-lived signed URL for the PDF. A payable that hasn't been opened returns 404. To share the PDF with someone outside Wingspan, create a link with POST /v3/payments/payables/{payableId}/secure-links. expiresIn must be 1 to 300 seconds, and notes isn't supported.
Related pages
Updated 10 days ago