Let any wallet or exchange pay into your Arc contract.
Wallets and exchanges can only send USDC to an address. Your vault, escrow or checkout needs its deposit function called. Doorstep gives each payer an address that does that for them, or sends the money back.
Live on Arc mainnetOpen source, MITNot audited yet
Press Replay to watch a payment go through, or select any part to read what it does.
A normal send can't call your contract.
On Arc, USDC is the native coin, and every wallet and exchange can send it to an address. But many contracts, such as pull-based vaults and escrows, only credit money that comes in through their own deposit function. A plain transfer either fails or arrives without crediting anyone.
Sending straight to the contract Not credited
- Wallet or exchange sends 25 USDC to the vault's address.
- The vault expects
deposit(amount, to), not a plain transfer. - The transfer fails, or the money sits in the contract with nobody credited.
This happened on Arc mainnet on 2 October 2026: a wallet payment into an onramp's escrow failed, and the team funded it from a backend script instead (GitHub issue #48).
Sending to a Doorstep address Credited
- Wallet or exchange sends 25 USDC to the payer's Doorstep address.
- Doorstep calls
deposit(amount, payer)on the vault for them. - The payer is credited. If the call fails, the money goes back to the refund wallet.
Your contract stays as it is. The payer uses the Send button they already know.
Four steps, and only the first one is yours.
Describe the payment
Choose the contract, who gets credited, the refund wallet, a minimum or exact amount, a fee limit, a deadline and a reference.
Get its address
Doorstep calculates the address from those instructions. Nothing is deployed when it's created, and anyone can recompute it.
The payer sends USDC
From any wallet or exchange on the Arc network, as a native send or an ERC-20 transfer. The same address can be paid again.
Delivered or returned
A delivery bot calls your contract, usually within seconds. If the call fails or the deadline passes, the money goes back to the refund wallet.
The address is the instructions.
Change any field and watch the address change. Your browser computes it here with the Doorstep SDK, the same way the contract does on Arc mainnet.
- target
- 0x3da5F9d36d1AE8769A9460a7788a21c8041C7bB3
- call
- deposit(amount, beneficiary)
- beneficiary
- refundTo
- minimum
- keeperFeeCap
- expiry
- reference
The target is the demo savings vault and the wallets are samples nobody owns, so don't send money to this address. To make a real one for your own wallet, use the payment link tool.
Running on Arc mainnet today.
These are the latest payments delivered or returned by the Doorstep contract, read directly from the chain when you open this section. Each one links to the Arc explorer.
- Doorstep contract
- 0x56BD0FEfdaAF9d053a74107E6dDb9de19D306229
- Demo savings vault
- 0x3da5F9d36d1AE8769A9460a7788a21c8041C7bB3
- Network
- Arc mainnet, chain id 5042
- Contract tests
- 32 pass under Arc's rules; also run against live mainnet state
- SDK tests
- 15 offline, plus end-to-end runs on a local Arc node
- Tried on mainnet
- Wallet send, ERC-20 transfer, reused address, deadline refund, early cancel, automatic delivery. See each transaction
One function call, or one HTTPS request.
Use the JavaScript SDK inside your app, or the hosted API from any backend.
- SDK. Builds addresses offline, describes them in plain words, makes pay links, watches status, and can deliver or cancel.
- API. Creates and registers an address, tracks invoices including part payments, and signs webhooks with HMAC-SHA256, retried for two hours. Needs an API key.
- AI agents. An MCP server gives agents three tools: create an address, check one (including whether a link someone sent really pays who it claims), and deliver. There's no tool that can send money anywhere else.
- Your contract. Anything with
deposit(uint256 amount, address to)that pulls withtransferFrom, which includes ERC-4626 vaults. Other functions work through a custom call.
import { createDoorstep } from 'doorstep-arc'; const ds = createDoorstep(); // Arc mainnet const invoice = ds.depositIntent({ into: '0xYourVault', // deposit(amount, to) beneficiary: customer, // who gets credited refundTo: customer, // if it can't be delivered minimum: '25', expires: '7d', reference: 'inv-1042', }); ds.depositAddress(invoice); // show it, or a QR code ds.toLink(invoice, { amount: '25' }); // a ready pay page ds.watch(invoice, (e) => { // waiting, landed, bounced if (e.type === 'landed') markPaid('inv-1042'); });
curl -X POST https://api.arcdoorstep.duckdns.org/v1/addresses \ -H "Authorization: Bearer $DOORSTEP_KEY" \ -H "content-type: application/json" \ -d '{ "into": "0xYourVault", "beneficiary": "0xCustomer", "refundTo": "0xCustomer", "amount": "25", "reference": "inv-1042", "webhookUrl": "https://yourapp.com/hooks/doorstep" }' # 201 Created { "address": "0x…", "payLink": "https://…/app/#i=…", "registered": true, "invoice": { "state": "unpaid", "remaining": "25" } }
// Doorstep POSTs to your webhookUrl when a payment is delivered or returned import crypto from 'node:crypto'; app.post('/hooks/doorstep', express.raw({ type: '*/*' }), (req, res) => { const ts = req.get('x-doorstep-timestamp'); const expected = 'v1=' + crypto .createHmac('sha256', process.env.DOORSTEP_WEBHOOK_SECRET) .update(`${ts}.${req.body}`).digest('hex'); if (req.get('x-doorstep-signature') !== expected) return res.sendStatus(401); const event = JSON.parse(req.body); // { type: 'payment.delivered', data: { reference: 'inv-1042', amount: '24.996', txUrl } } if (event.type === 'payment.delivered') markPaid(event.data.reference); res.sendStatus(200); });
# Let an AI agent take payments, without being able to redirect them claude mcp add doorstep -- node doorstep/agent/server.mjs # Tools: create_payment_address, check_payment, deliver_payment # Operator limits: allowed contracts, fee cap, longest deadline DOORSTEP_ALLOWED_TARGETS=0xYourVault DOORSTEP_MAX_FEE=0.02 DOORSTEP_MAX_DAYS=90 > Make a 25 USDC invoice into 0xYourVault for 0xCustomer, refunds to 0xCustomer, reference inv-1042. > Before I pay this link, check it really credits me. { "address": "0x…", "matchesExpectations": false, "mismatches": ["credits 0x000…dEaD, not 0xYou…"] }
It works because of how Arc handles USDC.
- Gas is paid in USDC
- The delivery bot is repaid in the coin it spent, by simple arithmetic: no price feed and no swaps. Each address caps what delivery may cost.
- One balance, two ways in
- A native send and an ERC-20 transfer both add to the same USDC balance, so one delivery handles either.
- Addresses that can be paid again
- A tiny contract is created at the address and removed in the same transaction, so the address is empty afterwards and works for the next payment, even from exchanges that send with a fixed gas limit.
- Fees under a cent
- Small payments are still worth delivering, and the payer doesn't need any gas beyond the send itself.
Where the money can go, and what can still go wrong.
Two destinations only
A payment can be deposited into the contract named in its instructions, or returned to its refund wallet. Doorstep keeps no balance between transactions, and the delivery bot only receives its capped fee.
Instructions can't be swapped
The address is computed from the instructions, so a different contract, beneficiary or refund wallet gives a different address. Pay pages recompute it before showing it.
If your contract refuses it
The deposit call fails, nothing is credited, and the payment goes back to the refund wallet in the same transaction.
If the delivery bot is down
Payments wait at their address. Anyone, including the payer, can deliver from the pay page, or run their own bot. After the deadline, delivery returns the money instead.
If the refund wallet can't receive
If USDC's blocklist blocks the refund wallet, the money stays at the address rather than going anywhere else.
Check before you send
Only USDC on Arc can be delivered or returned; other tokens sent to an address are stuck. Payers should check the contract, beneficiary and refund wallet on the pay page first.
Doorstep is new. The contract, tests and mainnet transactions are public, but there has been no independent security audit. Use small amounts.
Questions people ask.
What problem does Doorstep solve?
Wallets and exchanges can only send money to an address. Many Arc contracts only accept money through a deposit function. Doorstep gives each payer an address that calls that function for them.
Does the payer need a special wallet?
No. Any wallet or exchange that can send USDC on the Arc network works. The payer chooses Arc, pastes the address or scans the QR code, and sends.
What happens if the delivery bot is offline?
The money waits at the address. Anyone can deliver it with one click on the pay page, and the network fee comes out of the payment. Anyone can also run a bot; the code is in the repository.
Can an address be used more than once?
Yes. After each delivery the address is empty again, and later payments are delivered the same way until its deadline.
What if only part of an invoice is paid?
With an exact amount or a minimum, smaller payments wait at the address until the total is reached. The pay page shows how much has arrived and how much is missing. The refund wallet can cancel in the meantime.
Who pays the delivery fee?
It comes out of the payment: the network fee for the delivery, usually under $0.01 and never more than the limit in the instructions. There's no Doorstep fee.
Can the refund wallet cancel?
Yes. Before a payment is delivered, the refund wallet can take it back in full, with no delivery fee.
What happens after the deadline?
The address stops delivering. The next delivery attempt returns whatever is there to the refund wallet.
Is Doorstep audited?
Not yet. The contract is open source with 32 tests that also run against live mainnet state, and every flow has been used on mainnet. An audit would come first with grant funding.
Which contracts are supported?
Any contract whose deposit function takes the amount and pulls USDC with transferFrom. deposit(uint256 amount, address to) works out of the box, including ERC-4626 vaults. For other functions, the SDK lets you say where the amount goes in the call.
How do I run my own delivery bot?
Give it a wallet with a little USDC for gas, point it at an Arc RPC, and start it. It is repaid from each delivery. The steps are in the keeper guide.
See a payment find its way in.
Get your own Doorstep address on Arc mainnet, send a few cents of USDC from any wallet, and watch it arrive in a savings vault you can withdraw from.