Skip to main content
A supplier ships goods and issues an invoice due in 90 days, but needs cash now — not in 90 days. An invoice financing marketplace lets an investor buy that receivable at a discount, front the supplier the cash immediately, and collect the full face value when the debtor eventually pays. This tutorial builds that flow around InvoiceToken’s own PENDING → FUNDED → REPAID / DEFAULTED lifecycle.

What you’ll build

  • An endpoint that tokenizes a supplier’s invoice as an InvoiceToken
  • A funding endpoint that mints the invoice token to the investor and marks it FUNDED
  • A settlement endpoint that marks the invoice REPAID or DEFAULTED once the debtor’s payment window closes
  • A nightly job that flags overdue invoices before they’re marked in default

Prerequisites

  • Node.js 18+
  • A Stellar testnet account and secret key (S...), funded via the Stellar Friendbot
  • npm install @ankarachain/sdk express node-cron

1

Scaffold the project

src/config.ts
2

Tokenize the invoice

A supplier submits an invoice; you deploy an InvoiceToken representing it. Deployed tokens start in the base AssetStatus.DRAFT state, which the SDK’s invoice lifecycle methods below drive forward. The same deployInvoice() call works unchanged on EVM — see Deploy a Token for that variant.
src/routes.ts
3

Fund the invoice

The investor pays the supplier the discounted amount off-chain (bank transfer), and in exchange receives the full-face-value invoice token. Mint it to them and flip the invoice to FUNDED in one call:
src/routes.ts (continued)
markFunded() moves the token from PENDING to the base AssetStatus.ACTIVE. Only call it once the investor’s discounted payment to the supplier has actually cleared — there’s no on-chain check tying the mint to a real payment, so that guarantee is your platform’s responsibility.
4

Settle on repayment or default

When the debtor pays the supplier the full face value at maturity, mark the invoice repaid — this moves it to AssetStatus.REDEEMED. If the debtor doesn’t pay, mark it defaulted with a reason instead:
src/routes.ts (continued)
5

Flag overdue invoices nightly

src/jobs/flagOverdue.ts
isOverdue() returns true once dueDate has passed while the invoice is still PENDING or FUNDED — it does not automatically mark the invoice defaulted. Keep that decision (and the human review it usually needs) in your own backend, and call markDefaulted() explicitly.

Going further

  • Milestone-based funding instead of a single lump-sum mint — e.g. releasing a first tranche on shipment confirmation and the rest on delivery — is exactly what MilestoneEscrow is built for. See the Diaspora Construction Escrow tutorial for the full escrow lifecycle applied to tranche payments.
  • Secondary market: since InvoiceToken is a standard fungible token, an investor holding a FUNDED invoice can transfer it to another investor before maturity — no extra SDK call needed.

Next steps

AssetRegistry

Full reference for markFunded, markRepaid, markDefaulted, isOverdue.

Asset Templates

The full InvoiceMetadata schema and InvoiceStatus lifecycle.

TokenFactory

Full reference for deployInvoice.

Diaspora Construction Escrow

A tranche-based alternative funding model using MilestoneEscrow.