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

# Submit Wallet-Ownership Proof Evidence API - Travel Rule

> Submit the signature, test deposit transaction id or screenshot for a wallet-ownership proof. A failed attempt returns a code; a wrong deposit rejects it.



Submit Widget Proof Evidence API Prompt
        Copy prompt to clipboard



      
      

\<pre>

\`Submit the evidence for a wallet-ownership proof started from a widget session. The hosted widget makes this call; use it only if I build my own widget UI.

Endpoint:
POST https://verification.didit.me/v3/travel-rule/widget/{token}/proofs/{proof_id}/verify/

Authentication:
None - the widget token in the URL path is the credential. Treat the token as a secret.

Body, by method:
\- MESSAGE_SIGNING - JSON {"signature": "..."}: the wallet's signature over the proof's challenge.
\- SATOSHI_TEST - JSON {"txid": "..."}: the test deposit's transaction id.
\- SCREENSHOT - multipart form with a file field.

Behavior:
\- 200 with status VERIFIED, is_ownership_verified and transfer_status once ownership is proven.
\- 200 with status PENDING for a screenshot (it waits for the customer's review) or a deposit not indexed or confirmed yet, with code DEPOSIT_NOT_FOUND or DEPOSIT_UNCONFIRMED (Didit rechecks it until the window closes; no resubmission needed).
\- Every submission counts in attempts.

Failure modes (errors carry a code to translate):
\- 400 - SIGNATURE_INVALID, SIGNATURE_UNSUPPORTED_SCHEME or DEPOSIT_LOOKUP_FAILED. The proof stays PENDING: let the end user try again.
\- 400 - DEPOSIT_MISMATCH, DEPOSIT_STALE or TXID_REUSED with status REJECTED: the deposit is genuinely wrong (another sender, not the expected amount to the deposit address, older than the challenge, or already used to prove another wallet). The proof is closed and uses one of the session's attempts; the body carries max_attempts, attempts_used and attempts_remaining. Pick a method again to start a new proof.
\- 409 - code OWNERSHIP_CHANGED, or a closed proof (REJECTED or EXPIRED; the body carries status, the code it closed with and the attempt counts): start a new proof.
\- 410 - the session expired, or code WINDOW_EXPIRED when the Satoshi test window closed.
\- 404 - unknown token or proof.

Full guide: /transaction-monitoring/wallet-ownership-widget#satoshi-test-verify-contract.`

\</pre>



      
      

Paste into



## OpenAPI

````yaml POST /v3/travel-rule/widget/{token}/proofs/{proof_id}/verify/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/travel-rule/widget/{token}/proofs/{proof_id}/verify/:
    post:
      tags:
        - Travel Rule
      summary: Submit wallet-ownership proof evidence
      description: >-
        Public endpoint keyed by the widget session token, no API key required.
        Send the evidence the proof's method needs: signature for
        MESSAGE_SIGNING, txid for SATOSHI_TEST (JSON), or a file for SCREENSHOT
        (multipart). Every submission counts as an attempt. A signature that
        does not verify, or a deposit that does not match, answers 400 with a
        code and leaves the proof PENDING so the end user can try again. A
        deposit seen but not confirmed yet answers 200 with status PENDING and
        is rechecked automatically until the window closes. A screenshot answers
        200 with status PENDING and waits in your review queue (GET
        /v3/travel-rule/wallet-proofs/). An EXPIRED or REJECTED proof never
        verifies later: start a new one. Signature formats verified per chain
        family: EVM chains take a personal_sign (EIP-191) signature, hex
        encoded; Bitcoin takes a BIP-137 signmessage signature (P2PKH,
        P2SH-P2WPKH and P2WPKH addresses) or a BIP-322 simple signature (P2WPKH
        and P2TR addresses), base64 encoded; Solana takes an Ed25519 signature
        over the challenge, base58 encoded; Tron takes a signMessageV2 (TIP-191)
        signature, hex encoded. A BIP-322 full or proof-of-funds signature, or a
        multisig address, fails with SIGNATURE_UNSUPPORTED_SCHEME.
      operationId: verifyTravelRuleWidgetProof
      parameters:
        - name: token
          in: path
          required: true
          description: Opaque session token returned when the widget session was minted.
          schema:
            type: string
        - name: proof_id
          in: path
          required: true
          description: proof_id returned when the proof was started.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                signature:
                  type: string
                  description: >-
                    MESSAGE_SIGNING: the wallet's signature over the proof's
                    challenge.
                txid:
                  type: string
                  description: 'SATOSHI_TEST: the transaction id of the test deposit.'
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: >-
                    SCREENSHOT: an image showing the wallet in the end user's
                    wallet app.
      responses:
        '200':
          description: >-
            VERIFIED, or still PENDING (a screenshot awaiting review, a deposit
            not indexed or not confirmed yet, with code DEPOSIT_NOT_FOUND or
            DEPOSIT_UNCONFIRMED).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleWidgetProofVerifyResult'
        '400':
          description: >-
            Missing evidence; a failed attempt that keeps the proof PENDING so
            the end user can try again (code SIGNATURE_INVALID,
            SIGNATURE_UNSUPPORTED_SCHEME or DEPOSIT_LOOKUP_FAILED); or a test
            deposit that rejects the proof (code DEPOSIT_MISMATCH, DEPOSIT_STALE
            or TXID_REUSED, status REJECTED, with the session's attempt counts):
            picking a method again starts a new proof while attempts_remaining
            is above 0.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleWidgetProofError'
        '404':
          description: Unknown token, or no such proof on this session.
        '409':
          description: >-
            code OWNERSHIP_CHANGED (the proof is closed with it); a closed proof
            (REJECTED or EXPIRED), with its status, the code it closed with and
            the session's attempt counts: pick a method again to start a new
            proof; or a SELF_DECLARATION proof, which is verified when started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleWidgetProofError'
        '410':
          description: >-
            The session expired, or code WINDOW_EXPIRED when the satoshi test
            window closed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleWidgetProofError'
      security:
        - {}
      x-codeSamples:
        - lang: curl
          label: curl
          source: >-
            curl -X POST
            https://verification.didit.me/v3/travel-rule/widget/{token}/proofs/{proof_id}/verify/
            \
              -H 'Content-Type: application/json' \
              -d '{"signature": "0x..."}'
components:
  schemas:
    TravelRuleWidgetProofVerifyResult:
      type: object
      properties:
        proof_id:
          type: string
          format: uuid
        method:
          type: string
          enum:
            - MESSAGE_SIGNING
            - SATOSHI_TEST
            - SCREENSHOT
            - SELF_DECLARATION
        status:
          type: string
          enum:
            - PENDING
            - VERIFIED
            - REJECTED
            - EXPIRED
        is_ownership_verified:
          type: boolean
          description: >-
            Present when the proof is VERIFIED: the address book entry is now
            ownership-verified.
        transfer_status:
          type: string
          nullable: true
          description: >-
            Present when the proof is VERIFIED: the linked transfer's status,
            null without one.
        detail:
          type: string
          description: >-
            Present while the proof stays PENDING: a submitted screenshot
            awaiting review, or a test deposit that is not confirmed yet.
        code:
          allOf:
            - $ref: '#/components/schemas/TravelRuleWalletProofFailureReason'
          description: 'Present on a pending test deposit: why it is not confirmed yet.'
    TravelRuleWidgetProofError:
      type: object
      properties:
        detail:
          type: string
          description: Human-readable message in English.
        code:
          allOf:
            - $ref: '#/components/schemas/TravelRuleWalletProofFailureReason'
          description: >-
            Machine-readable reason, so a client can show its own translated
            message.
        status:
          type: string
          enum:
            - PENDING
            - VERIFIED
            - REJECTED
            - EXPIRED
          description: >-
            Present when the proof is closed: REJECTED by the deposit just
            submitted (400), or REJECTED or EXPIRED when evidence is sent to a
            proof that is already closed (409).
        proof_id:
          type: string
          format: uuid
          description: 'Present with status: the closed proof.'
        method:
          type: string
          enum:
            - MESSAGE_SIGNING
            - SATOSHI_TEST
            - SCREENSHOT
            - SELF_DECLARATION
          description: 'Present with status: the closed proof''s method.'
        max_attempts:
          type: integer
          description: 'Present with status: rejected wallet proofs this session allows.'
        attempts_used:
          type: integer
          description: 'Present with status: rejected proofs so far.'
        attempts_remaining:
          type: integer
          description: >-
            Present with status: when 0, starting another proof answers 409 and
            you mint a new widget session.
    TravelRuleWalletProofFailureReason:
      type: string
      enum:
        - ''
        - SIGNATURE_INVALID
        - SIGNATURE_UNSUPPORTED_SCHEME
        - DEPOSIT_NOT_FOUND
        - DEPOSIT_UNCONFIRMED
        - DEPOSIT_LOOKUP_FAILED
        - DEPOSIT_MISMATCH
        - DEPOSIT_STALE
        - TXID_REUSED
        - CHAIN_UNSUPPORTED
        - WINDOW_EXPIRED
        - OWNERSHIP_CHANGED
        - METHOD_SWITCHED
        - REVIEW_REJECTED
        - ABANDONED
      description: >-
        Why a wallet-ownership proof, or its last attempt, fell short of
        VERIFIED. Empty when nothing failed. A PENDING proof can carry one: the
        last attempt failed and the end user can try again. DEPOSIT_MISMATCH,
        DEPOSIT_STALE, TXID_REUSED and REVIEW_REJECTED close the proof as
        REJECTED. SIGNATURE_INVALID: the signature does not match the wallet and
        challenge. SIGNATURE_UNSUPPORTED_SCHEME: the wallet signed in a format
        Didit does not verify. DEPOSIT_NOT_FOUND, DEPOSIT_UNCONFIRMED,
        DEPOSIT_LOOKUP_FAILED: the test deposit is not readable or not confirmed
        yet; Didit keeps checking it until the test window closes.
        DEPOSIT_MISMATCH: the transaction does not send the expected amount from
        the wallet to the deposit address. DEPOSIT_STALE: the transaction
        predates the challenge. TXID_REUSED: the transaction already proved
        another wallet. CHAIN_UNSUPPORTED: the method is not available on this
        chain. WINDOW_EXPIRED: the test window closed. OWNERSHIP_CHANGED: the
        wallet's holder changed, or the wallet was deleted from your address
        book, after the widget session was minted. METHOD_SWITCHED: the end user
        picked another method before finishing this one. REVIEW_REJECTED: your
        reviewer rejected the screenshot. ABANDONED: the widget session lapsed
        before the end user finished.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.