Skip to content
Last updated

Blocking Accounts

Another version of this information is available

If you're new to Tilia services, another version of this information is available in the Tutorials section of these docs, which might be an easier place to start.

There may be times you wish to temporarily or permanently block a user from accessing Tilia. For example, if the user has been blocked from your platform or violated your Terms of Service.

In addition to any blocking you may do, Tilia actively monitors user activity and will block accounts that have violated our Terms of Service (TOS). Blocked accounts are unable to conduct transactions or access Tilia UIs. You are also unable to create redirect URLs for blocked accounts.

As a publisher, you can both block and unblock accounts on Tilia, and both operations use the same scope, write_accounts. What limits you is not the scope but who issued the block: you can remove a block your own integrator created, and you cannot remove one that Tilia created. Trying to remove a Tilia-issued block returns a 400 with the code invalid_block_issuer.

To block an account

Blocking accounts requires an API token with the scope write_accounts.

A block names a capability to withhold and a reason for withholding it. As a publisher you use the capability login with the reason account_close; the remaining capabilities (transactions, payouts) and reasons (merge_account, compliance, gdpr) are reserved for Tilia. Values are case-insensitive and accept either spaces or underscores, so Account close and account_close are the same reason.

curl --location --request POST https://accounts.tilia-inc.com/v2/block \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \
--data-raw '{
  "account_id": "{account_id}",
  "block_capability": "login",
  "block_reason": "account_close"
}'

Blocking response body

Like all Tilia responses, the body is wrapped in status, message, codes, and payload. The payload holds the account ID and every active block on the account, keyed by capability.

{
    "status": "Success",
    "message": [],
    "codes": [],
    "payload": {
        "account_id": "{account_id}",
        "blocks": {
            "login": {
                "block_id": "blk_2FizFe7kSxtgUf4Trw0Jwei7pJv",
                "account_id": "{account_id}",
                "issuer": "publisher",
                "capability": "login",
                "reason": "account_close",
                "integrator": "{your_integrator}",
                "status": "ACTIVE",
                "created": "0001-01-01T00:00:00Z",
                "updated": "0001-01-01T00:00:00Z"
            }
        }
    }
}

The issuer is publisher for blocks you create and tilia for blocks Tilia creates, and it is the field that decides who may remove the block later. A block you have just created echoes back the record as written, so its created and updated timestamps are zero; read the stored timestamps with GET /v2/block/{account_id}.

Blocking the login capability for the reason account_close fails with a 400 and the code WALLET_HAS_BALANCE if the account still holds a balance in any wallet other than its standard virtual wallet. Settle or transfer those balances before closing the account. A standard virtual currency balance does not block the request; Tilia sweeps it to your facilitator wallet as part of the close.

Keep in mind that blocking does not expire. The account must be unblocked in order to access Tilia.

As a best practice, we recommend that you keep track of any accounts that you have blocked somewhere in your system, along with your reason for blocking. This will make it easier for you to determine if and when these accounts should be unblocked.

Detecting blocked accounts

The direct way to read block state is to ask for the account's blocks. This requires an API token with the scope read_accounts.

curl --location --request GET https://accounts.tilia-inc.com/v2/block/{account_id} \
--header 'Authorization: Bearer <Access_Token>'

The response has the same shape as the blocking response: a map of active blocks keyed by capability. An account with nothing blocked returns an empty blocks object. Only active blocks appear, so a capability that was blocked and later unblocked is simply absent.

{
    "status": "Success",
    "message": [],
    "codes": [],
    "payload": {
        "account_id": "{account_id}",
        "blocks": {
            "transactions": {
                "block_id": "blk_2FizFe7kSxtgUf4Trw0Jwei7pJv",
                "account_id": "{account_id}",
                "issuer": "tilia",
                "capability": "transactions",
                "reason": "compliance",
                "integrator": "{your_integrator}",
                "status": "ACTIVE",
                "created": "2026-08-14T18:22:07.412339Z",
                "updated": "2026-08-14T18:22:07.412339Z"
            }
        }
    }
}

Block state also appears on the account profile, which is useful when you are already fetching profile data. Reading another account's profile requires the scope search_accounts.

curl --location --request GET https://accounts.tilia-inc.com/v1/{account_id}/user-info \
--header 'Authorization: Bearer <Access_Token>'

Two fields in that response describe blocking, and they do not mean the same thing. is_blocked reflects the login block, plus a legacy flag carried by older accounts, so an account whose transactions capability is blocked still reports is_blocked as false even though it cannot buy or sell. An older account can also report true with no login entry in blocked_capabilities. blocked_capabilities lists every active block, in the same form as the blocks endpoint. Read blocked_capabilities unless sign-in is the only thing you care about.

{
    "status": "Success",
    "message": [],
    "codes": [],
    "payload": {
        "account_id": "09c9e3ee-8af5-4206-aaa4-1a913ea855d2",
        "username": "string",
        "email": "string",
        "is_blocked": false,
        "blocked_capabilities": {
            "transactions": {
                "block_id": "blk_2FizFe7kSxtgUf4Trw0Jwei7pJv",
                "account_id": "09c9e3ee-8af5-4206-aaa4-1a913ea855d2",
                "issuer": "tilia",
                "capability": "transactions",
                "reason": "compliance",
                "integrator": "string",
                "status": "ACTIVE",
                "created": "2026-08-14T18:22:07.412339Z",
                "updated": "2026-08-14T18:22:07.412339Z"
            }
        },
        "integrator": "string",
        "created": "2020-07-03T01:05:59.49468Z"
    }
}

When authorization is attempted on a blocked account, a 403 error is returned with a response similar to the following:

{
    "status": "Failure",
    "message": [],
    "codes": [],
    "payload": "account is blocked ({account_id})"
}

To unblock an account

Unblocking removes one capability's block at a time, and it uses the same scope as blocking, write_accounts. Name the capability in the path.

Important

You are never permitted to unblock accounts that have been blocked by Tilia.

curl --location --request DELETE https://accounts.tilia-inc.com/v2/block/{account_id}/capability/login \
--header 'Authorization: Bearer <Access_Token>'

If the block you name was issued by Tilia, the request fails with a 400 and the code invalid_block_issuer rather than an authorization error. Check the block's issuer first if you need to know in advance whether you can remove it. Unblocking a capability that is not blocked succeeds and changes nothing.

Unblocking response body

The payload again lists the blocks that remain active on the account, so removing the only block leaves an empty blocks object.

{
    "status": "Success",
    "message": [],
    "codes": [],
    "payload": {
        "account_id": "{account_id}",
        "blocks": {}
    }
}

Monitoring Block Status via Webhook

We recommend that you implement a webhook to notify you about changes to an account's block status. Refer to the Blocking & Unblocking Accounts webhook documentation for request body details.

For more information about developing and registering webhook handlers, visit Webhooks.