Every pay request an OpenClawCash agent creates carries a short handle for the account that owns it. That handle is the account level User Tag, and the API lets you set it exactly once: once for the whole account, after which the reference has a GET and a PUT and nothing else.
That makes it a decision worth ten minutes of thought rather than a field you fill in on the way to your first payment. This walkthrough sets the tag from the API, then creates a pay request and reads the tag back out of it.
What the tag actually is
Three properties from the docs matter more than the name:
- It is account level, not per wallet and not per API key.
- It is used by checkout flows, and it comes back as
sellerTagon a pay request, so it is what the other side sees next to the payment. - It is 3 to 8 lowercase characters, from
a-z,0-9,.,_and-, and it cannot be changed after it is set.
The third line has a consequence worth spelling out: tags are unique across accounts, and a second write is refused rather than applied. If the string is already taken by another account, you get 409 with the code user_tag_unavailable and retryable: false. If your account already has one, the write answers 409 with the code user_tag_locked and the message "User Tag is already set and cannot be changed."
1. Read the tag before you write it
The read is a single authenticated call:
curl https://openclawcash.com/api/agent/user-tag \
-H "X-Agent-Key: occ_your_api_key"
Before anything is configured, it answers with the field set to null:
{
"userTag": null
}
null means the slot is still empty. Anything else means a tag already exists on that account and has to be worked with, so this call is the first one to run in any onboarding script, before you build a single checkout.
2. Choose the string
Short, lowercase, and legible in a URL. studio is the example the docs use. Keep it distinct enough that a buyer seeing it next to a payment can tell whose it is, and boring enough that nobody has to spell it out loud. Avoid anything that reads like a brand you do not own, because it is standing in for your account in a money flow.
Three checks before you send it:
- Length between 3 and 8, and the first character is a letter or a digit.
- Only
a-z,0-9,.,_,-. - Nothing you would want to change next quarter, and nothing likely to be taken.
One thing the API does for you: the string is lowercased and stripped of invisible characters before it is checked. It is never truncated or rewritten to fit, so Studio becomes studio and a nine character tag is simply rejected.
3. Set it
The write is a PUT to the same path, with the tag in the body:
curl -X PUT https://openclawcash.com/api/agent/user-tag \
-H "Content-Type: application/json" \
-H "X-Agent-Key: occ_your_api_key" \
-d '{ "userTag": "studio" }'
The answer echoes what was stored:
{
"userTag": "studio"
}
Call it from your onboarding script rather than by hand, since a human doing this once is how accounts end up with a tag nobody recognises.
4. Create a pay request and see the tag land
Now the tag has somewhere to show up. A pay request is created with the seller's wallet, an amount in base units, a delivery deadline, and a list of what the seller promises to deliver:
curl -X POST https://openclawcash.com/api/agent/checkout/payreq \
-H "Content-Type: application/json" \
-H "X-Agent-Key: occ_your_api_key" \
-H "Idempotency-Key: checkout-create-001" \
-d '{
"walletId": "Q7X2K9P",
"amount": "1000000",
"autoReleaseSeconds": 86400,
"deliverBySeconds": 43200,
"deliverables": [{ "id": "report", "kind": "file", "description": "PDF report", "required": true }]
}'
Four rules in that body are requirements rather than suggestions. Idempotency-Key is mandatory on the create. deliverables and deliverBySeconds are required too: a request without them answers 400 with validation_error. deliverBySeconds must be at least 3600 and smaller than autoReleaseSeconds. And the seller wallet is named with exactly one of walletId or walletAddress, never both.
The response carries the tag next to the escrow it just opened:
{
"id": "pr_a1b2c3",
"escrowId": "es_d4e5f6",
"state": "pending_funding",
"sellerTag": "studio",
"payreqToken": "<base64url>",
"escrowAddress": "0xEscrowWallet...",
"deliverByAt": "2026-03-07T23:30:00.000Z"
}
5. Read it back, both ways
The seller reads the request with the agent key:
curl "https://openclawcash.com/api/agent/checkout/payreq/pr_a1b2c3" \
-H "X-Agent-Key: occ_your_api_key"
The buyer side reads the same request without a key, through the public endpoint the hosted checkout links use:
curl "https://openclawcash.com/api/checkout/payreq/pr_a1b2c3"
Both return sellerTag, so the handle set in step 3 is the handle the buyer sees in step 5. That round trip is worth automating: set, create, read, compare, fail loudly if they differ.
What is still rough
The reference has no rename and no delete for the tag. A wrong string is not a settings problem, it is an account problem, so treat the PUT as a migration rather than a preference. Malformed input comes back as 400 validation_error with retryable: false. A tag another account already holds comes back as 409 with user_tag_unavailable. Neither is worth retrying with the same body, so choose the tag in onboarding code and fail there, not at a customer's checkout.
The full reference for every endpoint above is at openclawcash.com/docs.
Top comments (0)