Brighty invoice pay
Skill razz-team/brighty-agent-toolkit/skills/brighty-invoice-pay
Pay a single supplier invoice from a PDF, image, or pasted text via Brighty: extract recipient name, IBAN/BIC or on-chain address, amount, currency, and reference; show the user a one-screen confirmation with the resolved fields and source account; then create a single-transfer payout and commit. Use when the user shares one invoice (file, screenshot, email body, or describes one) and asks to pay it. For batch payroll or multi-recipient CSV/Excel runs, use brighty-payouts instead. Triggers: invoice, pay this invoice, pay supplier, vendor bill, AWS bill, Stripe invoice, attached PDF, IBAN payment, wire this, pay from screenshot.From its SKILL.md
npx -y skills add razz-team/brighty-agent-toolkit --skill brighty-invoice-payAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
10.4 KB, as published. Nobody here has run it
Brighty Invoice Pay
End-to-end pipeline to pay a single invoice from a document or pasted bank
details. This skill does not introduce new MCP tools — it orchestrates the
existing payout tools (brighty_list_accounts, brighty_create_payout,
brighty_create_external_transfer, brighty_get_payout,
brighty_start_payout) around an extraction + explicit confirmation step
so the user always sees the final field map before any money moves.
Activate this skill when the user shares one invoice (PDF, image,
screenshot, forwarded email, or pasted text) and asks to pay it. For
multi-recipient CSV/Excel runs use brighty-payouts instead — that skill
is built around batches.
Tools used
This skill calls only existing tools; it does not register new ones.
brighty_list_accounts(banking) — pick the source account when the user did not name one. Filter the returned array client-side bybalance.currencyto match the invoice (the API has no currency query param).brighty_create_payout(payouts) — open aCREATEDcontainer with a descriptivename, e.g. "Pay AWS invoice 4321". Capture the returnedidANDcreatedAt— both are required by every follow-up call.brighty_create_external_transfer(payouts) — add the single transfer.beneficiary.kind: "FIAT"for IBAN/BIC/account-number rails;beneficiary.kind: "CRYPTO"for on-chain addresses. PasspayoutCreatedAt(the value captured above) — the Brighty API rejects without it.brighty_get_payout(payouts) — re-fetch the payout immediately before the confirmation step so the user sees what Brighty stored. PasspayoutId+createdAt.brighty_start_payout(payouts) — final commit. PasspayoutId+createdAt. Runs the local preflight balance check; surface itsshortfallsverbatim if it fails. Returns{ ok: true }on success.
Reference material
references/INVOICE_FIELDS.md— exact list of fields to extract from the invoice and how each maps ontobrighty_create_external_transferarguments.references/CONFIRMATION_TEMPLATE.md— the shape of the message to show the user before callingbrighty_start_payout. Do not skip it.
The pipeline
Five steps, in order. Do not re-order or skip steps 3 and 4 — they are how the user catches OCR mistakes before money moves.
1. Extract fields from the invoice
Read the invoice (PDF, image, pasted text). Pull out, at minimum:
recipientName— full legal name of the supplieriban(preferred) oraccountNumber— recipient accountbic/swiftCode— required for SWIFT, often required for SEPAamount— total due, as a decimal string (do not cast to a number)currency— ISO-4217 code on the invoice (EUR,USD,GBP,CHF, …)reference— invoice number or supplier-supplied reference stringbeneficiaryAddress— postal address of the supplier when present; required for many SWIFT corridorsdueDate— informational only; surface to the user but do not act on it
For crypto invoices (rare for B2B — usually a wallet address pasted in an email):
address— on-chain destinationnetwork—BTC,ETH,TRX, etc. (maps totransferNetworkId)currency— asset ticker (BTC,ETH,USDT, …)amount— decimal stringmemo— destination tag for chains that route by memo (XRP, XLM)
See references/INVOICE_FIELDS.md for the exact field list, mapping to
tool arguments, and what to do when something is missing or ambiguous.
2. Pick the source account
If the user named an account, use it. Otherwise:
- Call
brighty_list_accounts(no currency filter exists; you'll get them all). Filter the result client-side bybalance.currency ===invoice currency. - If exactly one matching
CURRENTaccount is returned, propose it. - If multiple match, ask the user. Never pick silently when ambiguous.
- If none match (no account in the invoice currency), stop and tell the
user. Do not auto-FX — that requires the
brighty-payoutsskill'sbrighty_transfer_intent+brighty_transfer_ownflow first, and the user must consent to the rate.
3. Show the user the proposed transfer (pre-payout confirmation)
Before creating any Brighty objects, show the user a single message with
all extracted fields, the source account, and the resolved amount. See
references/CONFIRMATION_TEMPLATE.md for the exact shape.
Wait for an explicit "yes / go ahead / confirm". Do not infer consent from silence or from earlier "pay this" instructions — the user must confirm after seeing the resolved fields.
If the user corrects a field, update it and re-show the full block. Do not proceed on a partial diff.
4. Create the payout, add the transfer, re-confirm
Only after step 3:
brighty_create_payoutwith a descriptivename, e.g."Pay <supplier> invoice <reference>". Capture bothid(aspayoutId) andcreatedAt(aspayoutCreatedAt).brighty_create_external_transferwith the extracted fields:payoutIdfrom step 1payoutCreatedAtfrom step 1 (the API rejects without this)sourceAccountIdfrom step 2amount: { amount: "<decimal-string>", currency: "<ISO>" }beneficiaryperkindreference(the invoice number) Capture the returnedidempotencyKey— keep it for any retry.
brighty_get_payoutwithpayoutId+createdAt. Show the user the storedpayout.totalTransfers(must be 1),payout.totalAmount, and the recipient line as Brighty echoed it back. This catches the "I sent the wrong IBAN" class of mistake before commit.
5. Commit
After the user re-confirms on the post-create view from step 4.3, call
brighty_start_payout with payoutId + createdAt.
- On success, the tool returns
{ ok: true }(the API itself returns 204). Report success to the user with the payout id. - On a blocked preflight (MCP error result with body
{ ok: false, error: "PreflightFailed", message, shortfalls: [...] }), surface the per-accountshortfallslist verbatim and stop. Do not retry withskipPreflight: trueunless the user explicitly says so in writing — losing the per-account shortfall report on a single-transfer invoice is rarely worth the risk. - On a Brighty API error, surface
description(the human text) verbatim.
Critical patterns
Always extract, then confirm, then create. The biggest failure mode is an OCR mistake on an IBAN or amount that the user only sees after Brighty has already initiated the transfer. The two confirmation steps (pre-create and post-create) are the controls — do not collapse them.
Never paraphrase amounts or IBANs in the confirmation. Show them
character-for-character as extracted. Group IBAN digits in fours for
readability but do not change the digits. Show amount as a decimal
string verbatim — never Number() it.
One invoice = one payout = one transfer. If the user pastes two
invoices in the same message, treat them as two separate runs. Do not
batch them into a single payout from this skill — that is what
brighty-payouts is for, and the user has not asked for batch semantics.
Use the invoice number as reference. Suppliers reconcile by it. If
the invoice has no number, ask the user for one rather than inventing
text.
Important behaviours
- Money is
{ amount: string, currency: string }. Treatamountas a decimal string. Strip thousands separators ("1,234.56"→"1234.56") before sending; never cast to a number. - Trim whitespace from IBANs (
"DE89 3704 0044 …"→"DE89370400…") before sending; the schema does not auto-strip. brighty_create_external_transferdiscriminates onbeneficiary.kind.FIATrequiresbeneficiaryNameplus at leastibanoraccountNumber.CRYPTOrequiresaccountNumber(the on-chain address) andtransferNetworkId.memois required on chains that route by memo. Alternatively, pass a savedbeneficiaryIdinstead of an inline beneficiary.- Set
beneficiary.isBusinessRecipient: truefor supplier invoices — they are by definition B2B. This helps the AML routing pick the right category. - The Brighty API requires
Idempotency-KeyonPOST /payouts/{id}/transfers/external— the tool generates a UUIDv4 per call when not supplied. Keep the returned key on retries. - The Brighty API also requires
createdAt(the payout's timestamp) as a query param onPOST /payouts/{id}/transfers/external,GET /payouts/{id}, andPOST /payouts/{id}/start. Always capturecreatedAtfrombrighty_create_payoutand pass it through. - Currency on the invoice must match the source account's
balance.currency. If they differ, stop and ask the user — do not auto-FX from this skill.
When NOT to use this skill
- Multi-recipient batch (CSV/Excel/payroll) →
brighty-payouts. - "Convert EUR to USD on my savings account" →
brighty-payouts'sbrighty_transfer_intent+brighty_transfer_ownflow. - Internal Brighty-to-Brighty transfer to a Brighty username →
brighty-payouts'sbrighty_create_internal_transferinside a payout. - Reading balances, opening accounts, inviting members →
brighty-banking. - Issuing or freezing cards →
brighty-cards.
Error handling
Brighty returns errors as { errorCode, name, description, params? }.
Surface description (the human text) verbatim — do not rephrase. On
401, instruct the user to set BRIGHTY_API_KEY or run brighty-mcp login.
A blocked preflight from brighty_start_payout arrives as an MCP error
result whose body is
{ ok: false, error: "PreflightFailed", message, shortfalls: [{ accountId, currency, required, available, shortfall }] }.
Show the shortfalls list to the user verbatim and stop. Top-up of the
source account is on them.