Payments
How a single job gets quoted, paid, and settled, and what happens to your money when one fails.
Every job is quoted before it runs, in the currency you think in, and nothing settles until the work is done. Your agent puts the number in front of you and pays only if you approve, or automatically inside limits you set. A job that fails is not charged. A long job charges in steps, each quoted the same way, so you never commit to more than the next step.
A caller is whoever pays for a job: you, through the agent running dvm on your behalf. This page is about that side of the counter.
What a quote tells you
dvm quote asks a provider what a specific piece of work will cost, before anything is committed.
upfront.amount and upfront.currency are the number to put in front of your user. It is stated in real money, dollars or whatever the provider prices in, not in a crypto unit you would have to convert for them.
How to read it depends on shape:
shape | What the number is |
|---|---|
fixed | The price. That is what the job costs. |
rate | A commitment collected with the request, plus metered billing on what gets measured: minutes transcribed, pages rendered, bytes stored. The quote carries the rate and, when the provider sets one, a ceiling. |
When a quote sets a ceiling, it is a real bound, not an estimate: the final charge can land under it and never above it. A provider is not required to set one; scribe, the only rate-shaped DVM in the first-party catalog today, does.
Two more fields matter. expiresAt says how long the price holds. description is the provider's own plain-English summary of what it is about to do, which is usually the sentence to relay alongside the number.
Sats in a quote are advisory
--human renders an advisory satoshi figure next to the price, converted at the current rate. It is there for orientation, not for arithmetic. The binding amount is fixed later, at the payment handshake, and a rate that moved in between moves the sats with it. Quote in the fiat number; treat the sats line as a gloss.
What refundable does not mean
Every quote carries payment.refundable, a per-rail map, and it is false on every rail today. That is permanent and expected: it answers "can this rail send value backwards?", and none of them can. Cashu proofs commit when the provider receives them, and Tempo and Base are final settlement.
It is not the answer to "am I out the money if this job fails". That answer is below, and it is a better one.
Two ways to pay
Every paid job uses one of two customer modes. Per-call payment pays the job that is running now; it is the universal path and the right default for first contact or one-off work. Prepaid credit funds a small balance once and draws later jobs from it; it is the repeat-use path when one provider offers credit and the caller chooses it.
Cashu, Lightning, x402, and Tempo describe how money funds those modes, not extra products a user must choose among. Stablecoin prepaid credit reuses one balance across top-ups by default, while x402 exact authorizations and Tempo charges remain available for individual calls. A builder can also admit those one-payment methods into credit, but only by taking on manual responsibility for returning whatever goes unspent. Funding and wallets cover how that balance actually works.
The handshake
Paying is a turn in the conversation rather than a separate step. No account exists, so there is nothing to log into and no key to have been issued in advance.
- Your agent posts the job with no payment attached.
- The provider answers
402 Payment Required, with a challenge for each payment method it accepts and, where it offers one, a menu for prepaying a balance instead. - Your agent picks a method it can actually settle, settles it, and retries the same request carrying the credential.
- The provider verifies the credential, records the money, draws the job's cost against it, and runs the work.
A provider your agent has never contacted before is exactly one paid request away. That is the whole onboarding.
Paying up front, and paying mid-job
Most jobs are paid once, at submission. The upfront amount doubles as the spam gate, which is why it exists even on jobs that are otherwise metered, and on a fixed-price job it is simply the price.
Longer jobs can ask again while running. When that happens the response carries next_action of type pay, and the job stays alive waiting for it. Approve with dvm pay <job-id>, then resume the same job with dvm messages <job-id>. Do not re-submit the request: the job is still open, and a fresh submit creates a second job and a second charge.
Two flags bound this without you watching:
--max-payments <n>caps how many separate payments one job may ask for. The default is 5, and0means free jobs only.--max-increment <amount>caps how large any single one of them may be.
Both are per-job. The caps that bound a day or a month live on the budgets page.
Which rail actually pays
Your agent picks from the intersection of what the provider accepts and what you hold, and the choice is per job. You do not configure a preference for it to follow, though dvm wallet set-default-rail exists if you want one.
A connected Lightning wallet does not pay jobs directly. It funds the things that do. That distinction and the four funding paths are on the wallets page.
One thing can surprise you: the same job can cost slightly different amounts on different rails. A price quoted in dollars converts to a whole number of satoshis by rounding up, so on a sub-cent job that rounding is visible. A one-cent job might settle at eleven satoshis, about 7% over, while the stablecoin caller is asked for exactly one cent. The dollar figure is the advertised price; the satoshi figure is that price plus whatever the rounding adds.
If a job fails
A charge is a two-phase hold. It is placed when the job is accepted, settled into a real debit when the job completes, and released when the job fails, is cancelled, or is reaped after its worker dies.
So a failed job is never charged. That is arithmetic in a ledger rather than an operation on a payment rail, which is why it holds identically on every rail, including the ones that cannot send value backwards.
The harder question is what you can then do with the released money, and the answer turns on whether the provider authenticates callers:
| At a provider that... | The release lands on | And you can |
|---|---|---|
| does not authenticate callers | a shared anonymous identity | nothing. There is no key to claim it with, so in practice the payment is gone. |
| authenticates callers | your own key | spend it on your next job there. Your receipt names the balance it sits on. |
| authenticates and offers prepaid credit | your own key, and advertised | spend it, top it up, or take it back out as money. |
Four of the five first-party DVMs sit in the bottom row: cast, narrate, scrape, and scribe all require signed requests and advertise a funding menu, so a failed job's money lands on your own balance and can be drained back out. discover sits in the top row, because its search is free and it authenticates nobody.
This is the reason refundable: false is not the answer to the failure question. The rail never reverses; the ledger is what makes you whole. Credits covers the balance itself.
If the connection drops after paying
A definite failure is not the only way a job can go sideways. The provider can accept the paid job and hand back a job id, and then your agent's own connection can drop, or time out, before it learns how that job ended. The money is out and the job exists, you just have not heard which way it went. This is not the same as a failed job: nothing has failed, you just have not heard back yet.
dvm request tries once to poll the provider before giving up, in case the job actually finished while the connection was closing. If that poll also comes up empty, the response reports status: "paid-timeout" with next_action of type poll, rather than guessing at an outcome.
The rule is the same one that governs a mid-job payment: check, do not resubmit. Run dvm status <job-id> to pick the job back up. If it completed, you get the result and nothing further is charged. If it is still running, you keep polling. Resubmitting the original request starts a second job and a second charge on top of the one already in flight.
A connection can also drop earlier than that, during the paid submit itself, before any job id ever comes back. That is a narrower case specific to ecash: dvm wallet show tries to resume it automatically the next time you run it, and so does the next paid dvm request. dvm wallet submissions shows what is still unresolved.
When a price cannot be stated
Rails priced in dollars need a Bitcoin exchange rate to quote in satoshis, and that rate comes from an outside provider. If it is unreachable, a running DVM keeps quoting off the last rate it saw. A DVM refuses outright in two cases: it has never seen a rate at all, having started up during an outage, or it reads a shared rate snapshot that the platform has itself marked too old to serve — which refuses even if that DVM quoted off a recent rate minutes ago.
That refusal is a 503 and not a 402, deliberately. Your payment is not the problem, and nothing was charged. It is marked retryable and carries text your agent can pass to you as it stands. A provider that can quote in satoshis keeps serving payable quotes right through such an outage.
Where to go next
- Budgets: every limit on what your agent can spend, and which of them it cannot raise.
- Credits: prepaid balances, and the full answer to what happens to money at a failed job.
- Wallets: where the money is and how it gets there.
dvmCLI reference: every field on a quote and a job response.