Blockstream Enterprise Custody SDK
Issuer Guide (SDK)

Restriction management

Restrictions control asset destinations and burn permissions. The page explains restriction concepts, queries, updates, enforcement, and operational guidance.

Restrictions control where an asset can be sent and whether it can be burned. They are the primary compliance tool in AMP2.

For a hard block that prevents a specific wallet from touching an asset at all, see the Blacklist page. Restrictions and the blacklist solve different problems and can be used together — see Restrictions vs blacklist below.

Restriction concepts

FieldMeaning
widsWallets this restriction group applies to
toWhitelistAllowed destination wallets for transfers
useToWhitelistIf true, only whitelist destinations allowed
canBurnIf true, wallets in this group can burn the asset

Restrictions are enforced by the HSM at PSET cosigning time. If a transfer or burn violates the active policy, AMP2 refuses to cosign.

Create a single wallet restriction

Apply a restriction to one wallet for one asset:

import {
  EditAssetWalletRestrictionRequestSchema,
  type AmpActions,
} from '@blockstream/amp-registry';

const restrictionResult = await broadcastRequest<
  typeof AmpActions.editAssetWalletRestrictions
>({
  action: 'edit',
  resource: `/amp/assets/${assetId}/wallets/${walletId}/restrictions`,
  details: {
    can_burn: false,
    whitelist: [treasuryWid, approvedInvestorWid],
  },
}, broadcaster);

if (restrictionResult.status !== 'success') {
  throw new Error(`Failed to set restriction: ${restrictionResult.message}`);
}

This means: when walletId holds this asset, it can only send to treasuryWid or approvedInvestorWid. It cannot burn.

Create bulk restrictions

Apply the same policy to multiple wallets:

import type { AmpActions } from '@blockstream/amp-registry';

const bulkRestrictionResult = await broadcastRequest<
  typeof AmpActions.editAssetWalletRestrictionsList
>({
  action: 'edit',
  resource: `/amp/assets/${assetId}/restrictions`,
  details: {
    can_burn: false,
    use_to_whitelist: true,
    to_whitelist: [treasuryWid, approvedWid1, approvedWid2],
    wids: [investorWid1, investorWid2, investorWid3],
  },
}, broadcaster);

All three investor wallets now share the same restriction group with the same whitelist and burn permissions.

Query restrictions

V1 format

const restrictions = await broadcastRequest<
  typeof AmpActions.getAssetRestrictions
>({
  action: 'get',
  resource: `/amp/assets/${assetId}/restrictions`,
}, broadcaster);

V2 format (expanded group details)

const restrictionsV2 = await broadcastRequest<
  typeof AmpActions.getAssetRestrictionsV2
>({
  action: 'get',
  resource: `/amp/assets/v2/${assetId}/restrictions`,
}, broadcaster);

if (restrictionsV2.status !== 'success') {
  throw new Error('Failed to get asset restrictions');
}

The V2 response includes expanded group membership details.

Per wallet restriction

const walletRestriction = await broadcastRequest<
  typeof AmpActions.getAssetWalletRestrictions
>({
  action: 'get',
  resource: `/amp/assets/${assetId}/wallets/${walletId}/restrictions`,
}, broadcaster);

Delete restrictions

Delete a wallet's restriction

await broadcastRequest<
  typeof AmpActions.deleteAssetWalletRestrictions
>({
  action: 'delete',
  resource: `/amp/assets/${assetId}/wallets/${walletId}/restrictions`,
}, broadcaster);

Delete an entire restriction group

await broadcastRequest<
  typeof AmpActions.deleteAssetWalletRestrictionByGroup
>({
  action: 'delete',
  resource: `/amp/assets/${assetId}/restrictions/group/${groupId}`,
}, broadcaster);

Updating restrictions

There is no separate update operation. You update a restriction by sending it again to the same resource. What happens next depends on the group type.

Single group

Re-send the restriction to the per-wallet resource. The existing restriction is replaced atomically in one request — no delete step is needed.

  • The restriction is issued a new group_id on every update. Do not cache group ids for single restrictions.
  • If the wallet currently belongs to a multiple group, the request is rejected with 409. Remove it from that group first.

Multiple group

Re-send the restriction to the asset-level resource with the existing group_id. The group keeps its identity, and can_burn, use_to_whitelist and to_whitelist are updated in place. Omit group_id and you create a new group instead.

wids replaces the group membership; it does not add to it. Any wallet in the group but missing from wids is removed and becomes unrestricted — not blocked. Always send the complete membership list.

If any submitted wallet already belongs to a different group for this asset, the request is rejected with 409 listing those wallets, and nothing is changed.

Moving a wallet to a different group

A wallet cannot be added to a group while it still belongs to another group for the same asset — the request is rejected with 409. Regrouping therefore always takes two steps: delete the wallet's current restriction, then add it to the target group. This applies to every change of group, including single → multiple and multiple → single.

Enforcement and transfer relationship

When an issuer calls the send endpoint:

  1. AMP2 constructs the PSET with the requested recipients.
  2. The HSM checks the source wallet's restriction group for this asset.
  3. If useToWhitelist is true, every recipient must be in the toWhitelist.
  4. If the transaction burns tokens, canBurn must be true for the source wallet.
  5. If any check fails, the cosign request is refused.

Restrictions vs blacklist

Restrictions and the blacklist are separate mechanisms. Use restrictions to shape where an asset may flow; use the blacklist to stop a wallet from handling the asset at all.

Restrictions (whitelist / burn)Blacklist
GranularityA restriction group over one or more walletsA single (asset, wallet) pair
EffectLimits allowed transfer destinations and burn permissionBlocks the wallet from moving the asset entirely
DirectionApplied to the source wallet's outgoing transfersApplies whether the wallet is the sender or the recipient
Manage via/amp/assets/{aid}/wallets/{wid}/restrictions/amp/assets/{aid}/wallet/{wid}/blacklist

A wallet can be subject to both at once. If a wallet is blacklisted for an asset, the transfer is rejected regardless of any whitelist that would otherwise allow it.

Operational guidance

  • Always include the treasury wallet in whitelists: investors typically need to be able to return assets to the issuer.
  • Don't delete to change policy: re-send the restriction to the same resource instead. Deleting first leaves the wallet unrestricted until the new policy lands.
  • Log all restriction changes: record operator, timestamp, reason, and the old/new policy in your issuer systems.
  • Test on testnet: restriction enforcement is strict. A misconfigured whitelist will block legitimate transfers with no override.
  • Clear both sides when unblocking: a blacklist blocks sender and recipient independently. If both ends of a transfer are blacklisted, remove both records before retrying.

Next steps

On this page