FurlPay Docs
Open App
  • Services & Availability
  • Quickstart
  • For AI Agents
  • Monorepo
  • API Routes
  • Authenticationupdated
  • Webhook Eventsupdated
  • Error Codesupdated
  • Rate Limitsnew
  • Configuration & Setupnew
  • Merchant Paymentsnew
  • Payroll & Payoutsnew
  • Agentic Payments (x402)updated
  • Agent Trust & Mandates (TAP)updated
  • CCTP Cross-Chainupdated
  • LI.FI Swapsupdated
  • FurlPay Travels (Travel MCP)updated
  • Solana Actions & Blinks
  • Settlement Workspacenew
  • FURL Tokennew
  • Claude Connectorupdated
  • AI Assistants
  • Circlenew
  • Ramp Providersnew
  • Telegram Mini Appnew
  • Stripe Crypto
  • Persona KYC
  • Regulatory status
  • Screening & Casesnew
  • Security Postureupdated
  • Signing & WebAuthnupdated
  • Help Center
  • Getting Started
  • KYC Verification
  • Passkeys & Biometrics
  • Privacy & Data Protection
  • Transaction Statuses
  • Gasless Transfers
  • Deposits & Withdrawals
  • Managing Virtual Cards
  • Freezing & Unfreezing Cards
  • Declined Transactions
  • SDK & API Support
  • x402 Monetization Basics
  • Booking Travel
  • Travel Refunds & Cancellations

Resources

  • Changelog
  • System Status
  • OpenAPI Spec
  • Community
  • GitHub
Docs/Payments/Payroll & Payouts

Payments

Contractor payroll and payouts

Payroll lets an employer keep a contractor roster, draft a monthly pay run in USDC and authorise each line from their own wallet. FurlPay screens recipients, issues the data to sign and reads the result back from the chain. Payroll is non-custodial: FurlPay never holds the payroll funds and never signs the transfer.

Status: implemented, execution blocked by an external dependency

Rosters, drafts, screening, signing and contractor self-service are implemented and tested. On-chain execution needs a reviewed FurlPayRouter contract deployed on the run's network and its address configured. No router address is configured in production, so production cannot issue a signable pay run. The router contract has not been independently audited.

Contractor roster

Each contractor record holds a name, email, optional role, two-letter country code, payout network, payout wallet address and a default amount in USDC.

  • Networks: Arbitrum, Arc, Base and Polygon. Payout addresses are EVM addresses.
  • CSV import: validation is all-or-nothing. Any invalid row imports nothing and every error is listed. Emails already on the roster are skipped, never overwritten.
  • Recipients come from the roster. A pay run can only pay addresses the employer saved beforehand, never an address supplied in the run request.

Contractor self-service

  • The employer sends an invitation: a single-use link valid for seven days. Only a hash of the token is stored, and the token travels in the URL fragment so it does not reach server logs.
  • The contractor accepts while signed in with the same email as the roster entry. That links their account.
  • The contractor sets their own payout address by signing a registration message with that address (EIP-191). The address is screened first; a flagged address or a screening outage keeps the current address.
  • Once a contractor has linked their account, their identity and the address their wallet proved can no longer be changed by the employer.

A pay run, step by step

1. Draft and screen

A run names a cycle (YYYY-MM), one network and 1 to 100 roster lines. Creating it screens every recipient. If any recipient is flagged, or could not be screened, the whole run is blocked until the employer cancels it or excludes those recipients with a written note. Excluded recipients are recorded, never cleared.

2. Submit

Submitting turns the draft into one payment intent per line, with EIP-712 data for the employer's wallet. Exactly one request can move a draft forward. In production this step is refused when no router address is configured for the network.

3. Sign

The employer signs each line. The server checks every signature off-chain the same way the router will: the EIP-712 digest must recover to the payer, and malleable signatures are refused, so a stored signature is one the router can execute.

4. Execute and record

The employer's wallet submits the batch to the router. The transaction hash the browser reports is treated only as a pointer. A line is marked executed only after the server re-reads the receipt and finds a PaymentExecuted event from the configured router whose payment ID, payer, recipient, amount, fee and nonce match what was signed, at the network's required depth, in a block that is still canonical. A partially executed run stays submitted; it is never reported as paid.

ParameterTypeDescription
draftrequiredstatusSaved and screened; nothing issued to sign.
blockedrequiredstatusAt least one recipient was flagged or could not be screened.
submittingrequiredstatusIntents are being issued.
submittedrequiredstatusIntents issued; lines are being signed or executed.
completedrequiredstatusEvery line was found executed on-chain.
cancelledrequiredstatusCancelled by the employer.

Fees

  • Collected on-chain: 35 basis points per line, rounded down, paid by the employer on top of the line.
  • Quoted only: a batch minimum of 1.50 USDC and a seat fee of 19 USDC per active contractor, once per month. Billing is not connected, so these are recorded as quotes and charge nobody.

Tax records

An employer can record that they hold a payee-signed W-9 or W-8BEN. This is a record, not an e-signature system. The tax ID, legal name and address are encrypted at rest; only the last four characters of the tax ID are stored in the clear, and no API response decrypts them.

The tax summary is a 1099-NEC threshold watch for US contractors, totalling what was sent in submitted runs per calendar year. It cannot confirm what settled, it files nothing with any tax authority, and it is not tax advice.

Reconciliation

A scheduled job checks that every executed line's fee is journaled exactly once, re-reads recently executed lines from the chain, and reports runs that have been partially executed for more than a day. Findings become alerts. Nothing is corrected automatically: reversing a journal is an operator decision.

API

MethodPathDescription
GET / POST / PATCH/api/payouts/payroll/contractorsList, add or update roster entries
POST/api/payouts/payroll/contractors/importCSV roster import, all-or-nothing
POST/api/payouts/payroll/contractors/{id}/inviteCreate a seven-day single-use invitation
POST/api/payouts/payroll/contractors/{id}/taxRecord a W-9 or W-8BEN the employer holds
POST/api/payouts/payroll/inviteContractor side: preview or accept an invitation
GET / PATCH/api/payouts/payroll/meContractor side: own profiles; set the payout address with a signature
GET / POST / PATCH/api/payouts/payroll/batchesList runs; create a draft; submit, sign, cancel, reissue, exclude unscreened, record execution
GET/api/payouts/payroll/tax-summary?year=1099-NEC threshold watch
GET / POST/api/payouts/payrollSaved roster; run payroll for a roster in the request body

All routes require a signed-in session and are rate limited per account. The contractor invitation page is /payroll/join.

Setup

  • Supabase configured, with migrations 0042_payroll_and_merchant_extensions, 0044_payroll_contractor_self_service and 0048_payroll_exclusions_and_fee_ledger applied.
  • A router address per network: FURLPAY_ROUTER_ADDRESS_ARBITRUM, _ARC, _BASE, _POLYGON. The unsuffixed FURLPAY_ROUTER_ADDRESS is read for Arbitrum only; a router is never assumed to exist at the same address on another network.
  • FURLPAY_TAX_ENCRYPTION_KEY for sealed tax records.
  • Node endpoints for each payroll network.
  • The merchant-reconcile scheduled job, which also runs payroll reconciliation.

Not offered

FurlPay does not issue bank accounts, generate tax forms, file tax returns or pay contractors in local currency. Payroll moves USDC from the employer's wallet to contractor wallets and nothing else.
Did this page help?
Edit this page on GitHub

← Previous

Merchant Payments

Next →

Agentic Payments (x402)