The notarised ledger for AI agent spending.
Darc gives an AI agent a card with a daily limit, a short list of merchants and a stated purpose. Every payment it attempts — paid, held for your approval, or refused — is written on-chain where anyone can check it.
Passkey sign-in · no seed phrase · no password
Policy
Atlas's first run
Three goals on a $50 card. These are the outcomes the live demo produces on Monad Testnet.
| Goal | Amount | Verdict |
|---|---|---|
| Renew monthly hostingat Lagos Cloud Hosting | $20 | Paid |
| Top up API creditsat Horizon Data API | $200 | Awaiting youOver today's limit |
| Pay data feed subscriptionat Riverside Subscriptions | $15 | Awaiting youMerchant not on the list |
The two the card will not pay on its own are held, and a push alert reaches the owner's phone. Approved with a passkey tap, they settle as OwnerApproved; declined, the refusal is recorded. The merchant writes every verdict, so Darc cannot edit its own agents' record.
Three steps, one public record
The owner sets the rules once. The agent can only ask. The chain decides, and the answer stays where anyone can read it.
Issue a card
Your passkey signs one transaction that sets the daily limit, the merchant list, the expiry, what the card is for and how fast it may be used. The agent gets a fresh key and its own ERC-8004 identity.
issueCardWithRules(agentKey, dailyCap, merchantRoot, validUntil, maxBurst, window, purpose)The agent asks to pay
The agent only ever signs a payment authorisation. It holds no funds and no gas: a relayer submits the request and the contract checks it against the card. A burst of attempts freezes the card on-chain.
SpendAuth(cardId, merchant, token, amount, nonce, deadline, policyVersion)Out of policy? You decide
Over the limit, off the merchant list or off the card's stated purpose, the payment is held and a push alert reaches your phone. One passkey tap approves or declines it. Whatever happens, the merchant writes it to the shared reputation registry.
OwnerApproval(authDigest) → OwnerApprovedTwelve checks, in order. Any one refuses.
A refusal is not a silent failure. It is recorded with the name of the check that stopped it, so “declined” always says why. The last two can wait for your approval first.
| # | Check | Refusal reason |
|---|---|---|
| 01 | The card is not frozen | CardFrozen |
| 02 | It is not one attempt too many for the card's pace | VelocityExceeded |
| 03 | The card exists | CardNotFound |
| 04 | It has not been revoked | CardRevoked |
| 05 | It has not expired | CardExpired |
| 06 | The request is still fresh | DeadlineExpired |
| 07 | It pays in the card's token | TokenNotAllowed |
| 08 | It was signed under the current policy | PolicyVersionStale |
| 09 | The card's agent key signed it | BadAgentSignature |
| 10 | The request has not been used before | NonceUsed |
| 11 | The merchant is on the card's list | MerchantNotAllowed |
| 12 | It fits within today's limit | DailyCapExceeded |
Put your agent's budget on the record.
Create an account with a passkey, claim test AUSD from the public faucet, and issue Atlas a card. Then watch it work through its goals and get refused when it oversteps.