← Files WingspanARCHIVED FILE
skills/creating-draft-payables/SKILL.md
10.3 KB · Oct 5, 2026 · 18:24 UTC
--- name: creating-draft-payables description: Create draft payables — new payment obligations to contractors — in Wingspan. Nothing is paid. Use for "log a payment", "pay [name] $500 for [work]", "record these payments", "add these payments to the [engagement] engagement", "create payables", "log 12 hours at $85 for [name]", "bill this month's work". Writes to the company's Wingspan account, so it always previews first. --- # Creating draft payables The shared rules for every call — ids, paging, previewing a write, what the tools cannot do — are in the `using-wingspan-tools` skill. Apply them here. A **payable** is one payment owed to one contractor — the row on the Payables screen in the Wingspan app. An **engagement** is the named working arrangement a payment is filed under. A **line item** is one priced line inside a payment. `create_payables` records payments against contractors' engagements. **It writes to the company's account, and everything it creates is a draft.** ## Always preview first 1. Call `create_payables` with the rows and no `mode`. It defaults to `mode: "preview"`, which writes nothing: it resolves each contractor and engagement, checks every amount and date, totals it up, and reports exactly what applying would do. 2. Show that preview to the user in full — the per-row amounts, the total, the engagement each payment lands on, every warning, and every row that cannot be created. 3. Wait for the user to say yes. An earlier "log these payments" is not consent to write; the preview is the thing being consented to. 4. Call again with `mode: "apply"`, a `requestId` you have not used before, the matching preview's `confirmationToken` unchanged, and the **same rows and the same `ref` values** you previewed. Retrying an apply with the same `requestId` and the same refs returns the result of the original writes; nothing new is created. That is the only safe way to retry. A genuinely new attempt gets a new `requestId`. ## Arguments | Argument | What it does | | --- | --- | | `payments` | The rows. At least one, at most 50 per call. | | `engagement` | An engagement, by name or id, for every row. Omit it and Wingspan uses each contractor's default engagement. A row's own `engagement` overrides it. | | `dueDate` | Default due date for every row, as `YYYY-MM-DD`. Required unless every row sets its own. | | `currency` | Currency for every row. Defaults to US dollars. | | `mode` | `preview` (the default, writes nothing) or `apply`. | | `confirmationToken` | Required with `apply`; copy it verbatim from the matching preview. If it expires or arguments change, preview again. | | `requestId` | Required with `apply`. An id of your own, up to 64 printable characters with no spaces. | | `accountId` | Write into one child account of an organization instead of the signed-in account. Only when the user names one; `who_am_i` lists them. | Each row in `payments`: | Field | What it does | | --- | --- | | `contractor` | **Required.** Their email, your external id for them, or their contractor id. | | `ref` | Your label for this row, echoed in the result. Up to 48 printable characters, no spaces and no colon. Defaults to `row-1`, `row-2` and so on. | | `referenceId` | Your own id for this payable, stored on it and searchable afterwards with `search_payables`' `referenceId` filter. One per payable — two cannot share one. | | `engagement` | The engagement for this row, by name or id. Overrides the top-level one. | | `amount` | A flat amount in dollars, for example `1200.50`. | | `quantity` | Units worked, for example hours. Goes with `unitCost`. | | `unitCost` | Amount per unit, in dollars. Goes with `quantity`. | | `unit` | What a unit is: `"Hour"`, `"Unit"`, or a label of your own. Defaults to `"Unit"`. | | `description` | What the work was. Shown as the line item's title. | | `detail` | Longer detail underneath the line item. | | `dueDate` | Due date for this row, as `YYYY-MM-DD`. Overrides the top-level one. | | `notes` | A note on the payment itself. The contractor can see it. | | `lineItems` | Several priced lines instead of the single-line fields above. | Each entry in `lineItems` takes `description`, `amount`, `quantity`, `unitCost`, `unit` and `detail`, with the same meanings. **`ref` and `referenceId` are different things.** `ref` is a label for this call: it comes back in the result, it is what the retry key is built from, and it is gone once the call is done. `referenceId` is stored on the payable itself and is how the user finds that payment again later. A row can carry both, and they do not have to match. Because no two payables can share a `referenceId`, reusing one is refused rather than attached to a second payment — which also means a genuine retry of an apply is safe, but re-sending the same `referenceId` under a *new* `requestId` is not. ## Amounts **Amounts are in dollars.** `1200.50` is one thousand two hundred dollars and fifty cents. Never send cents. **Price a line one way or the other, never both.** Either a flat `amount`, or `quantity` together with `unitCost` — twelve hours at eighty-five dollars is `quantity: 12, unitCost: 85, unit: "Hour"`. Sending both is refused rather than guessed at, because it means the amount was expressed twice. A rate-priced line needs both halves: `quantity` on its own, or `unitCost` on its own, is refused. **Use the single-line fields or `lineItems`, never both on one row.** Same reason. **Every amount has to be greater than zero.** A flat `amount` of zero, a `unitCost` of zero and a `quantity` of zero are each refused. A payment for nothing is never what the user meant. **A flat `amount` cannot be more precise than the currency.** US dollars are paid to two decimal places, so `10.999` is refused. Round the figure with the user rather than picking one for them. A per-unit `unitCost` may be finer than that — half a cent across a thousand units is a real way to price work — and Wingspan does the multiplication. **A due date is required**, either on every row or once at the top level, and it is a calendar date: `YYYY-MM-DD`, no time and no timezone. ## Engagements The engagement decides which working arrangement the payment belongs to, and **it is fixed the moment the payment is created.** There is no way to move a payment to a different engagement afterwards — not from here, and not in the app. Getting it wrong means cancelling the payment and creating a new one. So when the engagement matters, confirm it with the user before applying. The contractor must already be assigned to the engagement you name. If they are not, the row fails and the preview lists which engagements they *are* assigned to. Assigning them is app work; the `onboarding-contractors` skill covers doing it for a new contractor. Omit the engagement entirely and Wingspan files the payment under the contractor's default engagement. The preview says when that is happening, so show it — a user who cares which engagement a payment lands on needs to see that they did not name one. **This tool creates new payment obligations. It never moves existing ones.** A payable's engagement is fixed when it is created, and no tool here edits a payable. So "add these payments to an engagement" is ambiguous: if the user means payments that already exist in Wingspan, that cannot be done from here, and previewing a creation would propose duplicate obligations. Before calling the tool, settle which one the user means. If they mean existing records, check with `search_payables` and say the engagement cannot be changed. If they mean new drafts, proceed. When the phrasing is "log", "record" or "add" a payment that has already been paid outside Wingspan, ask as well: a draft payable is a new obligation that Wingspan will expect to pay, not a record of money already sent. ## Everything created here is a draft A payment created by this tool sits at draft. The contractor cannot see it and no payment is scheduled. Say this to the user every time, because "log a payment" often means "and pay it" in their head. What happens next: `open_payables` releases the draft, which is what shows it to the contractor, and that is the one step available here. Approving it, and the payroll run that funds and pays it, happen in the Wingspan app. Paying is also protected by an extra identity challenge, so it cannot be reached from here under any circumstances. ## The warning that matters most **Eligibility is checked when a payment is opened, not when it is created.** A draft against a contractor with outstanding requirements is created happily and may then fail to open, if any of those requirements blocks eligibility. Whether a given outstanding requirement blocks depends on where it was attached, which these tools do not read, so say "may not open" rather than "cannot open". The preview flags the situation — "onboarding requirements are incomplete, so this payable cannot be opened or paid until they are" — and that warning must reach the user, not be dropped as noise. Use `get_contractor` to say what is outstanding; the `finding-contractors` skill covers reading it. The preview also warns when a contractor's assignment to the named engagement is not active yet. ## Batches Fifty rows is the hard limit for one call; over that, the tool refuses and names the limit. Each batch is its own attempt and needs its own `requestId`. One bad row never stops the others — each row reports its own outcome by `ref`. ## Where payments come from besides this tool An invoice is not a payable. A payable is the payer's record of what it owes one contractor. An invoice is a bill, and either side can raise one: a contractor billing the company, or the company billing its own client. Payables can originate from either kind of invoice as well as from payroll, and all of them show up in `search_payables` alongside anything created here — the `checking-payments` skill covers reading them. A payable that came from an invoice is owned by Wingspan and cannot be edited here. ## Finish these in the Wingspan app - Approving a draft, scheduling it, cancelling it and paying it. Releasing it so the contractor can see it is `open_payables`, not app work. - Starting a payroll run, and funding sources. - Moving a payment to a different engagement — impossible; cancel and recreate. - Invoices, payment splits, deductions and accounting integrations. - Creating engagements, and assigning a contractor to one.
SHA-256: f62f6059ca746ceb355aaa1efca72b11285c788edfafa4a2c38c31b022d63439