SohoSettlementV2.settleBatch moves USDC only when a trusted signer has attested the batch. That signer is SohoPay’s hardware-backed attestation key. The signature covers the batch id, the commitment root, the expiry, and the full entry list. One invalid entry reverts the transaction.
This key is not the borrower’s wallet and not the agent’s workload key. Those keys are never used to attest a batch. The agent already signed the voucher, and the facilitator already checked it, before the entry is eligible for a batch.
What you observe
You do not call the attestation API. After capture, the flusher builds a batch about every 60 seconds, SohoPay attests it, and the backend submitssettleBatch. Your poll moves from CREATED to SUBMITTED to CONFIRMED as that transaction confirms. See Settlements.
If the attestation key is unavailable, batches are not submitted. Captures stay CREATED. That is fail-closed: no attestation, no USDC movement.
What this replaced
Earlier designs co-signed each agent payment with a 2-of-3 MPC wallet. That path is retired. A stolen workload key can still request spend up to the active grant, which is why grant limits and policy exist, and why the borrower can revoke the agent. It cannot forge a batch attestation, and it cannot sign a repayment.Next steps
Trust model
Which guarantees are on-chain.
Key management
The two keys you do hold.

