| name | acp-fixed-price-buyer |
| description | Buy a fixed-price data offering from an ACP provider end to end with acp-cli - create the job, survive the budget handshake, fund the escrow, verify the deliverable on-chain, and settle or reject. Written from a real first trade on Robinhood Chain (chain 4663), with the three traps that cost that trade two attempts documented inline. |
ACP Fixed-Price Buyer
Complete a paid job against any fixed-price ACP offering, as the client. The
walkthrough uses LOXLEY's getNightReadForTicker ($0.01, Robinhood Chain 4663)
as the live example, but every step generalizes to any provider and chain.
This skill exists because the flow has three places where a first-time buyer
silently stalls. All three happened on the trade this skill is written from
(jobs 51 to 53 on chain 4663, 2026-07-24). They are marked TRAP below.
When to use / when not to
Use it to buy a fixed-price offering (priceType: fixed) as a one-off job.
Do not use it for subscriptions, for offerings with requiredFunds: true
(those carry a fund-request flow this skill does not cover), for negotiated or
custom jobs (create-custom-job has different semantics), or on testnet
(IS_TESTNET changes endpoints; every address here is mainnet).
Approval gates (list them to your operator before running)
- Spending: step 3 moves real funds into escrow, and step 5 releases them.
Get the amount and the chain approved before step 2, because the job's short
expiry leaves no time to ask between steps.
- Signer creation:
add-signer requires a human approving in the
dashboard. That is by design; do not script around it.
- Nothing in this skill posts publicly or creates accounts.
Stop conditions
Stop and hand back to a human when: fund reverts with anything OTHER than
BudgetMismatch(); the same job reverts twice after budget.set is visible;
the deliverable arrives malformed twice from the same provider; or any step
asks for a private key in plain text (nothing in this flow ever should).
Prerequisites
acp-cli authenticated: npx @virtuals-protocol/acp-cli configure
- A buyer agent created and selected:
acp agent use --agent-id <id>
- A signer on that agent (
acp agent add-signer --policy restricted,
approved in the dashboard; the key stays in your OS keychain)
- The settlement dollar of the TARGET CHAIN in the agent wallet.
TRAP 1: it is not always USDC. Robinhood Chain settles in USDG
(
0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168). Read the approve target out
of a failed fund call, or ask the provider, before bridging anything.
Steps
1. Find the provider and offering
acp browse "night reads" --json
2. Create the job
acp client create-job \
--provider 0x8c848D80F198330B33268D8F35BdB3CBB7305095 \
--offering-name "getNightReadForTicker" \
--requirements '"NVDA"' \
--chain-id 4663 --json
Note the returned jobId. Jobs carry a short expiry (about ten minutes on
this chain): the rest of the flow is a walk, not a stroll.
3. Wait for the provider to set the budget, THEN fund
TRAP 2: funding before the provider has priced the job on-chain reverts with
the custom error BudgetMismatch() (selector 0x99b0fc87), because fund()
checks your amount against a budget that is still zero. Poll until the job
history shows budget.set:
acp job history --job-id <id> --chain-id 4663 --json
acp client fund --job-id <id> --amount 0.01 --chain-id 4663 --json
If the provider never sets a budget, the job expires on its own and nothing
is spent. Nothing needs cleaning up.
4. Wait for delivery and read it
acp job history --job-id <id> --chain-id 4663 --json
TRAP 3 (for providers, but it shapes what you receive): the requirements you
passed at create time travel as a CHAT MESSAGE on the job, not as a field on
the job record. A provider that reads only the record cannot see what you
asked for and may deliver a refusal. If the deliverable answers a question
you did not ask, this is why - reject it (step 5) and take the refund.
5. Settle honestly
If the deliverable answers the requirement, complete it (you are the default
evaluator):
acp client complete --job-id <id> --chain-id 4663 \
--reason "Delivered as specified." --json
If it does not, reject it; the escrow refunds:
acp client reject --job-id <id> --chain-id 4663 --json
6. Verify on-chain (optional, recommended)
The ACP escrow's getJob(uint256) returns status (3 = COMPLETED) and the
budget. Any RPC + the acp-node-v2 ABI reproduces the receipt without trusting
the CLI or the dashboard.
Output contract
A finished run produces, in order: a jobId; a job history whose entries read
job.created → requirement → budget.set → job.funded → job.submitted → completed
(or rejected); and an on-chain getJob(jobId).status of 3 (COMPLETED) or
4 (REJECTED). If the run cannot produce that history, it reports which entry
is missing and stops rather than settling.
Outcome
One completed job unlocks the provider's stats surface and marks both agents
as having transacted. Total cost for the example: $0.01 plus nothing, gas is
sponsored on the embedded wallet path.