Skip to content

Compose an attach

POST
/v1/attach-templates
curl --request POST \
--url https://api.digirare.com/v1/attach-templates \
--header 'Content-Type: application/json' \
--header 'x-session-token: <x-session-token>' \
--data '{ "utxo_owner": "example", "asset_source": "example", "asset": "example", "fee_rate": 1, "exclude": [ { "txid": "example", "vout": 1 } ], "in_flight": [ { "asset": "example", "quantity_raw": "example", "asset_utxo": { "txid": "example", "vout": 1 } } ], "funding": [ { "txid": "example", "vout": 1, "value_sats": 1, "script_pub_key_hex": "example" } ] }'

Composes and independently verifies one one-unit attach for the client leg runner. Nothing is stored or reserved: the browser signs, broadcasts, and keeps its own leg state, and the marketplace learns about the asset UTXO when Counterparty indexes it. Explicit funding lets a leg name a disjoint coin or the previous leg’s unconfirmed change.

Media typeapplication/json
object
utxo_owner
required

Mainnet P2TR or P2WPKH address. The SIGNING capability: every signature is verified by reconstructing a BIP-143/BIP-341 witness sighash.

string
asset_source

Counterparty address whose balance is attached when a listing is prepared. P2PKH, P2WPKH, or P2TR: these spend families are supported by the attach verifier. The source owns input 0 and may differ from seller, which owns the modern asset UTXO and signs the listing.

string
asset
required

Canonical compact Counterparty key. A subasset uses its A ID; asset_longname is display metadata.

string
fee_rate
number
>= 0.1 <= 500
exclude

Coins server selection must skip: inputs the caller already committed in earlier legs that chain data cannot yet show as spent.

Array<object>
<= 200 items
object
txid
required
string
/^[0-9a-f]{64}$/
vout
required
integer
in_flight

The caller’s own attaches from this source that may still be moving units, as asset and raw units each one moves (the XCP protocol fee under XCP). A signed attach names its asset_utxo and stays declared until it is FINALITY_DEPTH deep: the server skips entries whose asset UTXO its balance projection currently shows attached (already out of the detached balance) and counts the rest, so an attach a reorg un-parsed counts again. Entries without asset_utxo always count. Only ever subtracted from the held balance, so the server refuses composing units those attaches already use.

Array<object>
<= 800 items
object
asset
required

Canonical compact Counterparty key. A subasset uses its A ID; asset_longname is display metadata.

string
quantity_raw
required
string
/^[0-9]{1,30}$/
asset_utxo
object
txid
required
string
/^[0-9a-f]{64}$/
vout
required
integer
funding

Exact inputs this attach may spend. Supply script_pub_key_hex on every input to spend an unconfirmed parent’s change; omit it on all of them for confirmed coins.

Array<object>
>= 1 items <= 20 items
object
txid
required
string
/^[0-9a-f]{64}$/
vout
required
integer
value_sats
required
integer
>= 1 <= 9007199254740991
script_pub_key_hex
string
/^[0-9a-f]+$/
Examplegenerated
{
"utxo_owner": "example",
"asset_source": "example",
"asset": "example",
"fee_rate": 1,
"exclude": [
{
"txid": "example",
"vout": 1
}
],
"in_flight": [
{
"asset": "example",
"quantity_raw": "example",
"asset_utxo": {
"txid": "example",
"vout": 1
}
}
],
"funding": [
{
"txid": "example",
"vout": 1,
"value_sats": 1,
"script_pub_key_hex": "example"
}
]
}

One verified attach template, never stored

Media typeapplication/json
object
result
required
object
asset
required

Canonical compact Counterparty key. A subasset uses its A ID; asset_longname is display metadata.

string
quantity_raw
required
string
/^(0|[1-9][0-9]*)$/
utxo_owner
required

The address that will own the asset UTXO.

string
asset_source
required

Counterparty address whose balance is attached when a listing is prepared. P2PKH, P2WPKH, or P2TR: these spend families are supported by the attach verifier. The source owns input 0 and may differ from seller, which owns the modern asset UTXO and signs the listing.

string
fee_rate
required
number
>= 0.1 <= 500
attach
required
object
psbt_hex
required
string
/^[0-9a-f]+$/
signers
required
Array<object>
>= 1 items
object
address
required

Counterparty address whose balance is attached when a listing is prepared. P2PKH, P2WPKH, or P2TR: these spend families are supported by the attach verifier. The source owns input 0 and may differ from seller, which owns the modern asset UTXO and signs the listing.

string
inputs_to_sign
required
Array<integer>
>= 1 items unique items
sighash
required
Allowed value: ALL
expected_txid
required
string
/^[0-9a-f]{64}$/
txid_provisional
required

True when a legacy input makes the txid unknowable before signing; a chained leg must compose from the signed parent.

boolean
asset_utxo
required

Output 0 of the attach: the UTXO the unit lands on.

object
vout
required
integer
value_sats
required
integer
>= 1 <= 9007199254740991
funding_inputs
required
Array<object>
>= 1 items
object
txid
required
string
/^[0-9a-f]{64}$/
vout
required
integer
change
required
Any of:
object
txid
required
string
/^[0-9a-f]{64}$/
vout
required
integer
value_sats
required
integer
>= 1 <= 9007199254740991
script_pub_key_hex
required
string
/^[0-9a-f]+$/
fees
required
object
network
required
object
asset
required
Allowed value: BTC
amount_sats
required
integer
protocol
required
object
asset
required
Allowed value: XCP
amount_raw
required
string
/^(0|[1-9][0-9]*)$/
actual_amount_raw
One of:
string
/^(0|[1-9][0-9]*)$/
observed_block
integer | null
variable_until_confirmed
required
boolean
charged_at
string | null
platform
required
object
asset
required
Allowed value: BTC
amount_sats
required
integer
Example
{
"result": {
"attach": {
"sighash": "ALL"
},
"fees": {
"network": {
"asset": "BTC"
},
"protocol": {
"asset": "XCP"
},
"platform": {
"asset": "BTC"
}
}
}
}

Stable machine-readable failure

Media typeapplication/json
object
error
required
string
code
required
string
Allowed values: invalid_request unsupported_address_type unauthenticated forbidden not_found method_not_allowed state_changed expired invalid_transaction rate_limited internal_error upstream_unavailable service_unavailable checkout_changed target_unavailable signature_invalid template_mismatch mempool_rejected broadcast_unknown conflict_spend duplicate_funding_slot offer_selection_unavailable attached_delivery_single_item_only insufficient_funds insufficient_asset_balance price_below_minimum listing_price_above_maximum counter_price_invalid self_trade offer_capacity_full open_offer_limit policy_offer_refused
retryable
boolean
mempool_policy

On 422 mempool_rejected from a broadcast: which deterministic node policy refused the bytes. Retrying the same bytes fails the same way. fee_floor: re-quote at a higher fee_rate. chain_too_long: too many unconfirmed ancestors; wait for a confirmation, then retry. truc: a version-3 (TRUC) package rule, such as spending an unconfirmed version-3 output; wait for a confirmation, then retry.

string
Allowed values: fee_floor chain_too_long truc dust nonstandard
mempool_reason

The node’s own reject reason, on mempool_rejected (422) and on state_changed (409) when a broadcast lost to a conflicting or replacing spend.

string
wait_for_confirmation

Present and true when mempool_policy is chain_too_long or truc.

boolean
claims_released

On a checkout or accept completion refused as mempool_rejected: the journaled settlement ended and every listing, bid, and asset claim it held was released (its inputs were proven unspent). The quote or accept is replaced; request a new one.

boolean
refused_listings

Batch listing routes only: every refused item. The first sets the status and code.

Array<object>

One refused item in a batch refusal’s refused_listings array. Nothing in the batch was changed.

object
index
required
integer
listing_id
required
string
status
required
integer
code
required
string
error
required
string
key
additional properties
any
retry_after_seconds

On 429 rate_limited: the exact seconds until the oldest counted request leaves the window; a retry then is admitted (also sent as Retry-After). Limited writes are bucketed per route scope in exact sliding 60-second windows: by session address when a valid x-session-token is present, otherwise by IP, with a per-IP ceiling across sessions. Expensive writes: 20, ceiling 120. Signed completions: 120, ceiling 600. Session minting (/auth/*): 60 per IP. A request refused by any bucket is counted by none.

integer
>= 1
key
additional properties
any
Example
{
"code": "invalid_request",
"mempool_policy": "fee_floor"
}

Stable machine-readable failure

Media typeapplication/json
object
error
required
string
code
required
string
Allowed values: invalid_request unsupported_address_type unauthenticated forbidden not_found method_not_allowed state_changed expired invalid_transaction rate_limited internal_error upstream_unavailable service_unavailable checkout_changed target_unavailable signature_invalid template_mismatch mempool_rejected broadcast_unknown conflict_spend duplicate_funding_slot offer_selection_unavailable attached_delivery_single_item_only insufficient_funds insufficient_asset_balance price_below_minimum listing_price_above_maximum counter_price_invalid self_trade offer_capacity_full open_offer_limit policy_offer_refused
retryable
boolean
mempool_policy

On 422 mempool_rejected from a broadcast: which deterministic node policy refused the bytes. Retrying the same bytes fails the same way. fee_floor: re-quote at a higher fee_rate. chain_too_long: too many unconfirmed ancestors; wait for a confirmation, then retry. truc: a version-3 (TRUC) package rule, such as spending an unconfirmed version-3 output; wait for a confirmation, then retry.

string
Allowed values: fee_floor chain_too_long truc dust nonstandard
mempool_reason

The node’s own reject reason, on mempool_rejected (422) and on state_changed (409) when a broadcast lost to a conflicting or replacing spend.

string
wait_for_confirmation

Present and true when mempool_policy is chain_too_long or truc.

boolean
claims_released

On a checkout or accept completion refused as mempool_rejected: the journaled settlement ended and every listing, bid, and asset claim it held was released (its inputs were proven unspent). The quote or accept is replaced; request a new one.

boolean
refused_listings

Batch listing routes only: every refused item. The first sets the status and code.

Array<object>

One refused item in a batch refusal’s refused_listings array. Nothing in the batch was changed.

object
index
required
integer
listing_id
required
string
status
required
integer
code
required
string
error
required
string
key
additional properties
any
retry_after_seconds

On 429 rate_limited: the exact seconds until the oldest counted request leaves the window; a retry then is admitted (also sent as Retry-After). Limited writes are bucketed per route scope in exact sliding 60-second windows: by session address when a valid x-session-token is present, otherwise by IP, with a per-IP ceiling across sessions. Expensive writes: 20, ceiling 120. Signed completions: 120, ceiling 600. Session minting (/auth/*): 60 per IP. A request refused by any bucket is counted by none.

integer
>= 1
key
additional properties
any
Example
{
"code": "invalid_request",
"mempool_policy": "fee_floor"
}