> ## Documentation Index
> Fetch the complete documentation index at: https://cobo.com/developers/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Satoshi Test challenge

> This operation creates a Satoshi Test challenge for self-custody address verification. Satoshi Test verifies address ownership by having the counterparty transfer a small, uniquely-generated amount from their wallet to a Cobo-controlled verification address.

A single endpoint covers both flows via the `action` parameter:
- **Two-step flow** (`action=PREPARE` then `action=SUBMIT`): Preview the verification details first, then activate. The 180-minute countdown only starts on `SUBMIT`. The server uses `(chain_id, from_address)` as the idempotency key, so the second call automatically targets the prepared challenge. For extra safety, pass the `challenge_id` returned by `PREPARE` in the subsequent `SUBMIT` call — it pins the activation to that specific challenge.
- **One-shot flow** (`action=SUBMIT` directly, without `challenge_id`): Prepare and submit in a single call. The challenge is created directly in `PENDING` state with the countdown started.

If the counterparty address has already been verified, the operation returns HTTP 400 `ADDRESS_ALREADY_VERIFIED`. Call [List address verifications](#operation/list_address_verifications) with `chain_id`, `address`, and `status=VERIFIED` first to pre-check.

Supported chains: `BTC`, `ETH`, `BASE_ETH`, `BSC_BNB`, `TRON`.


<Tip>
  Try [Cobo WaaS Skill](/v2/guides/overview/cobo-waas-skill) in your AI coding assistant (Claude Code, Cursor, etc.). Describe your needs in natural language to auto-generate production-ready SDK code and debug faster 🚀
</Tip>

<RequestExample>
  ```python Python theme={null}
  import cobo_waas2
  from cobo_waas2.models.create_satoshi_test_challenge_request import (
      CreateSatoshiTestChallengeRequest,
  )
  from cobo_waas2.models.satoshi_test_challenge import SatoshiTestChallenge
  from cobo_waas2.rest import ApiException
  from pprint import pprint

  # See configuration.py for a list of all supported configurations.
  configuration = cobo_waas2.Configuration(
      # Replace `<YOUR_PRIVATE_KEY>` with your private key
      api_private_key="<YOUR_PRIVATE_KEY>",
      # Select the development environment. To use the production environment, change the URL to https://api.cobo.com/v2.
      host="https://api.dev.cobo.com/v2",
  )
  # Enter a context with an instance of the API client
  with cobo_waas2.ApiClient(configuration) as api_client:
      # Create an instance of the API class
      api_instance = cobo_waas2.TravelRuleApi(api_client)
      create_satoshi_test_challenge_request = (
          cobo_waas2.CreateSatoshiTestChallengeRequest()
      )

      try:
          # Create Satoshi Test challenge
          api_response = api_instance.create_satoshi_test_challenge(
              create_satoshi_test_challenge_request=create_satoshi_test_challenge_request
          )
          print("The response of TravelRuleApi->create_satoshi_test_challenge:\n")
          pprint(api_response)
      except Exception as e:
          print(
              "Exception when calling TravelRuleApi->create_satoshi_test_challenge: %s\n"
              % e
          )

  ```

  ```java Java theme={null}
  // Import classes:
  import com.cobo.waas2.ApiClient;
  import com.cobo.waas2.ApiException;
  import com.cobo.waas2.Configuration;
  import com.cobo.waas2.Env;
  import com.cobo.waas2.api.TravelRuleApi;
  import com.cobo.waas2.model.*;

  public class Example {
    public static void main(String[] args) {
      ApiClient defaultClient = Configuration.getDefaultApiClient();
      // Select the development environment. To use the production environment, replace `Env.DEV` with
      // `Env.PROD
      defaultClient.setEnv(Env.DEV);

      // Replace `<YOUR_PRIVATE_KEY>` with your private key
      defaultClient.setPrivKey("<YOUR_PRIVATE_KEY>");
      TravelRuleApi apiInstance = new TravelRuleApi();
      CreateSatoshiTestChallengeRequest createSatoshiTestChallengeRequest =
          new CreateSatoshiTestChallengeRequest();
      try {
        SatoshiTestChallenge result =
            apiInstance.createSatoshiTestChallenge(createSatoshiTestChallengeRequest);
        System.out.println(result);
      } catch (ApiException e) {
        System.err.println("Exception when calling TravelRuleApi#createSatoshiTestChallenge");
        System.err.println("Status code: " + e.getCode());
        System.err.println("Reason: " + e.getResponseBody());
        System.err.println("Response headers: " + e.getResponseHeaders());
        e.printStackTrace();
      }
    }
  }

  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"fmt"
  	coboWaas2 "github.com/CoboGlobal/cobo-waas2-go-sdk/cobo_waas2"
  	"github.com/CoboGlobal/cobo-waas2-go-sdk/cobo_waas2/crypto"
  	"os"
  )

  func main() {
  	createSatoshiTestChallengeRequest := *coboWaas2.NewCreateSatoshiTestChallengeRequest(coboWaas2.SatoshiTestChallengeAction("PREPARE"), "ETH", "0x1234567890abcdef1234567890abcdef12345678", "123e4567-e89b-12d3-a456-426614174000", coboWaas2.TravelRuleTransactionType("DEPOSIT"))

  	configuration := coboWaas2.NewConfiguration()
  	// Initialize the API client
  	apiClient := coboWaas2.NewAPIClient(configuration)
  	ctx := context.Background()

  	// Select the development environment. To use the production environment, replace coboWaas2.DevEnv with coboWaas2.ProdEnv
  	ctx = context.WithValue(ctx, coboWaas2.ContextEnv, coboWaas2.DevEnv)
  	// Replace `<YOUR_PRIVATE_KEY>` with your private key
  	ctx = context.WithValue(ctx, coboWaas2.ContextPortalSigner, crypto.Ed25519Signer{
  		Secret: "<YOUR_PRIVATE_KEY>",
  	})
  	resp, r, err := apiClient.TravelRuleAPI.CreateSatoshiTestChallenge(ctx).
  		CreateSatoshiTestChallengeRequest(createSatoshiTestChallengeRequest).
  		Execute()
  	if err != nil {
  		fmt.Fprintf(
  			os.Stderr,
  			"Error when calling `TravelRuleAPI.CreateSatoshiTestChallenge``: %v\n",
  			err,
  		)
  		fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
  	}
  	// response from `CreateSatoshiTestChallenge`: SatoshiTestChallenge
  	fmt.Fprintf(os.Stdout, "Response from `TravelRuleAPI.CreateSatoshiTestChallenge`: %v\n", resp)
  }

  ```

  ```javascript JavaScript theme={null}
  const CoboWaas2 = require("@cobo/cobo-waas2");
  // Initialize the API client
  const apiClient = CoboWaas2.ApiClient.instance;
  // Select the development environment. To use the production environment, replace `Env.DEV` with `Env.PROD`
  apiClient.setEnv(CoboWaas2.Env.DEV);
  // Replace `<YOUR_PRIVATE_KEY>` with your private key
  apiClient.setPrivateKey("<YOUR_PRIVATE_KEY>");
  // Call the API
  const apiInstance = new CoboWaas2.TravelRuleApi();
  const opts = {
    CreateSatoshiTestChallengeRequest:
      new CoboWaas2.CreateSatoshiTestChallengeRequest(),
  };
  apiInstance.createSatoshiTestChallenge(opts).then(
    (data) => {
      console.log("API called successfully. Returned data: " + data);
    },
    (error) => {
      console.error(error);
    },
  );

  ```
</RequestExample>


## OpenAPI

````yaml post /travel_rule/satoshi_test/challenge
openapi: 3.0.3
info:
  title: Cobo Wallet as a Service 2.0
  description: >
    The Cobo Wallet-as-a-Service (WaaS) 2.0 API is the latest version of Cobo's
    WaaS API offering. It enables you to access Cobo's full suite of crypto
    wallet technologies with powerful and flexible access controls. By
    encapsulating complex security protocols and streamlining blockchain
    interactions, this API allows you to concentrate on your core business
    activities without worrying about the safety of your assets. The WaaS 2.0
    API presents the following key features:


    - A unified API for Cobo's [all four wallet
    types](https://manuals.cobo.com/en/portal/introduction#an-all-in-one-wallet-platform)

    - Support for 80+ chains and 3000+ tokens

    - A comprehensive selection of webhook events

    - Flexible usage models for MPC Wallets, including [Organization-Controlled
    Wallets](https://manuals.cobo.com/en/portal/mpc-wallets/ocw/introduction)
    and [User-Controlled
    Wallets](https://manuals.cobo.com/en/portal/mpc-wallets/ucw/introduction)

    - Programmatic control of smart contract wallets such as Safe{Wallet} with
    fine-grained access controls

    - Seamlessly transfer funds across multiple exchanges, including Binance,
    OKX, Bybit, Deribit, and more


    For more information about the WaaS 2.0 API, see [Introduction to WaaS
    2.0](https://www.cobo.com/developers/v2/guides/overview/introduction).
  termsOfService: https://cobo.com/waas/tos/
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
  contact:
    name: Cobo WaaS
    url: https://www.cobo.com/waas
    email: help@cobo.com
  version: 1.0.0
servers:
  - url: https://api.dev.cobo.com/v2
    description: Development environment
  - url: https://api.cobo.com/v2
    description: Production environment
security:
  - CoboAuth: []
tags:
  - name: Organizations
    description: Operations related to Organizations.
  - name: Wallets
    description: Operations related to all wallets.
  - name: Wallets - MPC Wallets
    description: Operations related to mpc wallet.
  - name: Wallets - Exchange Wallet
    description: Operations related to exchange wallet.
  - name: Wallets - Smart Contract Wallets
    description: Operations related to smart contract wallet.
  - name: Transactions
    description: Operations related to all transactions.
  - name: Developers - Webhooks
    description: Operations related to webhooks.
  - name: Stakings
    description: Operations related to staking.
  - name: OAuth
    description: Operations related to OAuth.
  - name: Developers
    description: Operations related to developers.
  - name: AddressBooks
    description: Operations related to address books.
  - name: TravelRule
    description: Operations related to travel rule.
  - name: GraphQL
    description: Operations related to executing GraphQL queries and mutations.
  - name: PrimeBroker
    description: Operations related to prime broker.
  - name: AppWorkflows
    description: Operations related to app workflow.
  - name: FeeStation
    description: Operations related to fee station.
  - name: Payment
    description: Operations related to payment.
  - name: Batch Payouts
    description: Operations related to batch payouts.
  - name: Tokenization
    description: Operations related to tokenization.
  - name: AutoSweep
    description: Operations related to auto sweep.
  - name: Compliance
    description: Operations related to compliance.
paths:
  /travel_rule/satoshi_test/challenge:
    post:
      tags:
        - TravelRule
      summary: Create Satoshi Test challenge
      description: >
        This operation creates a Satoshi Test challenge for self-custody address
        verification. Satoshi Test verifies address ownership by having the
        counterparty transfer a small, uniquely-generated amount from their
        wallet to a Cobo-controlled verification address.


        A single endpoint covers both flows via the `action` parameter:

        - **Two-step flow** (`action=PREPARE` then `action=SUBMIT`): Preview the
        verification details first, then activate. The 180-minute countdown only
        starts on `SUBMIT`. The server uses `(chain_id, from_address)` as the
        idempotency key, so the second call automatically targets the prepared
        challenge. For extra safety, pass the `challenge_id` returned by
        `PREPARE` in the subsequent `SUBMIT` call — it pins the activation to
        that specific challenge.

        - **One-shot flow** (`action=SUBMIT` directly, without `challenge_id`):
        Prepare and submit in a single call. The challenge is created directly
        in `PENDING` state with the countdown started.


        If the counterparty address has already been verified, the operation
        returns HTTP 400 `ADDRESS_ALREADY_VERIFIED`. Call [List address
        verifications](#operation/list_address_verifications) with `chain_id`,
        `address`, and `status=VERIFIED` first to pre-check.


        Supported chains: `BTC`, `ETH`, `BASE_ETH`, `BSC_BNB`, `TRON`.
      operationId: create_satoshi_test_challenge
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSatoshiTestChallengeRequest'
      responses:
        '201':
          $ref: '#/components/responses/createSatoshiTestChallengeResponse'
        4XX:
          $ref: '#/components/responses/badRequestError'
        5XX:
          $ref: '#/components/responses/internalServerError'
      security:
        - CoboAuth: []
        - OAuth2:
            - travel_rule.edit
components:
  schemas:
    CreateSatoshiTestChallengeRequest:
      type: object
      title: Create Satoshi Test challenge request
      description: >
        Request body for creating a Satoshi Test challenge. A single endpoint
        covers both the two-step flow (`PREPARE` then `SUBMIT`) and the one-shot
        flow (`SUBMIT` directly). Idempotent on `(chain_id, from_address)` per
        organization.
      required:
        - action
        - chain_id
        - from_address
        - transaction_id
        - transaction_type
      properties:
        action:
          $ref: '#/components/schemas/SatoshiTestChallengeAction'
        chain_id:
          type: string
          description: >-
            The chain ID of the counterparty address. See the operation
            description for supported chains.
          example: ETH
        from_address:
          type: string
          description: >-
            The counterparty (self-custody) wallet address that will transfer
            the micro-deposit.
          example: '0x1234567890abcdef1234567890abcdef12345678'
        transaction_id:
          type: string
          format: uuid
          description: The Cobo transaction ID that this Satoshi Test is verifying for.
          example: 123e4567-e89b-12d3-a456-426614174000
        transaction_type:
          $ref: '#/components/schemas/TravelRuleTransactionType'
        challenge_id:
          type: string
          format: uuid
          description: >
            The `challenge_id` returned by a previous `PREPARE` call.

            - When `action=SUBMIT`: if provided, activates that specific
            challenge by id (recommended when you cached the id client-side
            after `PREPARE`). If omitted, the server activates the latest
            matching challenge identified by `(chain_id, from_address)`.

            - When `action=PREPARE`: **must be omitted**. A new challenge is
            always generated; passing a `challenge_id` here will cause the
            request to be rejected.
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
    SatoshiTestChallengeAction:
      type: string
      enum:
        - PREPARE
        - SUBMIT
      example: PREPARE
      description: >
        The action to perform when creating a Satoshi Test challenge.

        - `PREPARE`: Preview the verification address and amount. The 180-minute
        countdown is NOT started yet. Repeated `PREPARE` calls for the same
        `(chain_id, from_address)` refresh the amount.

        - `SUBMIT`: Activate the challenge and start the 180-minute countdown.
        If a `PREPARE` challenge already exists for this `(chain_id,
        from_address)` it is activated; otherwise a new challenge is created
        directly in `PENDING` state (one-shot flow).
    TravelRuleTransactionType:
      type: string
      enum:
        - DEPOSIT
        - WITHDRAW
      example: DEPOSIT
      description: >
        The direction of the underlying transaction in a Travel Rule operation.

        - `DEPOSIT`: A deposit transaction (verifying the source address).

        - `WITHDRAW`: A withdrawal transaction (verifying the destination
        address).
    SatoshiTestChallenge:
      type: object
      title: Satoshi Test challenge
      description: >-
        Full information about a Satoshi Test challenge, returned by the create
        and get operations.
      required:
        - challenge_id
        - from_address
        - to_address
        - amount
        - token_id
        - chain_id
        - status
        - remaining_seconds
      properties:
        challenge_id:
          type: string
          format: uuid
          description: The unique identifier of the Satoshi Test challenge.
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        from_address:
          type: string
          description: >-
            The counterparty (self-custody) wallet address that must transfer
            the micro-deposit.
          example: '0x1234567890abcdef1234567890abcdef12345678'
        to_address:
          type: string
          description: >-
            The Cobo-generated verification address that will receive the
            micro-deposit.
          example: '0xabcdef1234567890abcdef1234567890abcdef12'
        amount:
          type: string
          description: >
            The exact amount (in the token's smallest unit) that must be
            transferred. The amount is unique per challenge and is used together
            with `to_address` to identify a matching on-chain transfer.
          example: '1100001000000000'
        token_id:
          type: string
          description: >-
            The ID of the token used for the micro-deposit (typically the
            chain's native asset).
          example: ETH
        chain_id:
          type: string
          description: The chain on which the micro-deposit is expected.
          example: ETH
        status:
          $ref: '#/components/schemas/SatoshiTestChallengeStatus'
        remaining_seconds:
          type: integer
          description: >
            Remaining time (in seconds) before the challenge expires. `0` when
            the challenge is not yet submitted or has already completed/expired.
          example: 10550
        matched_txid:
          type: string
          nullable: true
          description: >-
            The on-chain transaction hash of the matching transfer, once
            matched.
          example: 0xabc123...
        started_at:
          type: integer
          format: int64
          nullable: true
          description: >-
            Timestamp (milliseconds) when the challenge was submitted and the
            countdown started.
          example: 1732523887000
        expires_at:
          type: integer
          format: int64
          nullable: true
          description: >-
            Timestamp (milliseconds) when the challenge will expire if not
            matched.
          example: 1732534687000
    ErrorResponse:
      type: object
      description: The response of a failed request.
      required:
        - error_code
        - error_message
        - error_id
      properties:
        error_code:
          type: integer
          description: >-
            The error code. Refer to [Error codes and status
            codes](https://www.cobo.com/developers/v2/api-references/error-codes)
            for more details.
        error_message:
          type: string
          description: The error description.
        error_id:
          type: string
          description: >-
            The error log ID. You can provide the error ID when submitting a
            ticket to help Cobo to locate the issue.
          example: 0b6ddf19083c4bd1a9ca01bec44b24dd
    SatoshiTestChallengeStatus:
      type: string
      enum:
        - PREPARE
        - PENDING
        - MATCHED
        - VERIFIED
        - EXPIRED
        - DELETED
      example: PENDING
      description: >
        The lifecycle status of a Satoshi Test challenge.

        - `PREPARE`: Challenge created (address and amount returned); the
        180-minute countdown is not started yet.

        - `PENDING`: Challenge submitted; countdown active, waiting for the
        counterparty's on-chain transfer.

        - `MATCHED`: An on-chain transfer matching the expected amount has been
        observed; waiting for block confirmations.

        - `VERIFIED`: The matched transfer reached confirmation — the address is
        verified.

        - `EXPIRED`: Challenge was not matched within 180 minutes.

        - `DELETED`: Challenge was cancelled by the client.
  responses:
    createSatoshiTestChallengeResponse:
      description: >
        The Satoshi Test challenge was created.


        - `action=PREPARE`: returned challenge has `status=PREPARE`; the
        180-minute countdown is not started yet.

        - `action=SUBMIT`: returned challenge has `status=PENDING`; `started_at`
        and `expires_at` are set.


        If the counterparty address has already been verified (by signature or a
        prior Satoshi Test), this operation returns HTTP 400
        `ADDRESS_ALREADY_VERIFIED` instead — call [List address
        verifications](#operation/list_address_verifications) with `chain_id`,
        `address`, and `status=VERIFIED` first to pre-check.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SatoshiTestChallenge'
    badRequestError:
      description: >-
        Bad request. Your request contains malformed syntax or invalid
        parameters.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    internalServerError:
      description: Internal server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    CoboAuth:
      type: apiKey
      in: header
      name: BIZ-API-KEY
      description: >
        The API key. For more details, refer to [API
        key](https://www.cobo.com/developers/v2/guides/overview/cobo-auth#api-key).


        In the API playground, enter your [API
        secret](https://www.cobo.com/developers/v2/guides/overview/cobo-auth#api-secret),
        and your API key will be accordingly calculated.
    OAuth2:
      type: oauth2
      description: >-
        The [Org Access
        Token](https://www.cobo.com/developers/v2/apps/org-access-tokens). Use
        this authorization method only if you are developing Cobo Portal Apps
        for installation and use across different organizations.
      flows:
        authorizationCode:
          authorizationUrl: https://auth.cobo.com/authorize
          tokenUrl: https://auth.cobo.com/oauth/token
          scopes:
            address_book.read: Read address book
            api_key.read: Read API key information
            callback.read: Read callback message
            callback.resend: Resend callback message
            wallet.create: Create wallet
            wallet.read: Read wallet information
            wallet.update: Update wallet information
            wallet.delete: Delete wallet information
            wallet.create_address: Create wallet address
            wallet.manage_utxo: Manage UTXO
            mpc_project.create: Create MPC project
            mpc_project.read: Read MPC project information
            mpc_project.update: Update MPC project information
            mpc_vault.create: Create MPC Vault
            mpc_vault.read: Read MPC Vault information
            mpc_vault.update: Update MPC Vault information
            mpc_key_group.create: Create MPC key group
            mpc_key_group.read: Read MPC key group information
            mpc_key_group.update: Update MPC key group information
            mpc_key_group.delete: Delete MPC key group information
            transaction.read: Read transaction information
            transaction.withdraw: Make withdrawals
            transaction.estimate_fee: Estimate transaction fee
            transaction.contract_call: Initiate contract calls
            transaction.message_sign: Initiate message signings
            transaction.stake: Stake assets
            transaction.unstake: Unstake assets
            transaction.unstake_withdraw: Withdraw unstaked assets
            transaction.manage: Manage ongoing transactions
            transaction.update: Update transaction notes
            travel_rule.read: Read travel rule information
            travel_rule.edit: Edit travel rule information
            webhook.read: Read webhook URLs/events
            webhook.edit: Edit webhook URLs
            webhook.resend: Resend webhook events
            payment_orders_payin.create: Create pay-in order
            payment_orders_payin.read: Read pay-in order information
            payment_orders_payin.update: Update pay-in order
            payment_orders_refund.create: Create payment refund order
            payment_orders_refund.read: Read payment refund order information
            payment_settlement.create: Create payment settlement request
            payment_settlement.read: Read payment settlement request information
            payment_merchant.create: Create payment merchant
            payment_merchant.read: Read payment merchant information
            payment_merchant.update: Update payment merchant
            payment_forced_sweep.create: Create payment force sweep request
            payment_forced_sweep.read: Read payment force sweep request information
            compliance_funds.refund: Refund compliance funds request
            compliance_funds.isolate: Isolate compliance funds request
            compliance_funds.unfreeze: Unfreeze compliance funds request
            compliance_funds.read: Read compliance funds request information
            compliance_kyt_review.update: Update KYT review status
            compliance_kyt_decisions.update: Update KYT decision status
            compliance_kyt_status.read: Read KYT screening status
            compliance_kya_screenings.create: Create KYA address screening requests
            compliance_kya_screenings.read: Read KYA address screening results

````