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

# Verify a crypto external account

> Step-by-step guide to resolving a Travel Rule declared-level verification for a crypto external account, ahead of a withdrawal.

This guide walks you through setting up and resolving a `declared`-level Travel Rule verification for a [crypto external account](/rest-apis/core-api/external-accounts/introduction#types-of-external-accounts) — collecting a self-declaration about the address up front, rather than during a withdrawal quote.

## Prerequisites

* The user has [completed onboarding](/developer-guides/user-onboarding/overview) and has the required capabilities enabled.
* The user already has a `crypto` external account — see [Create external account](/rest-apis/core-api/external-accounts/create-external-account).

## Walkthrough

```mermaid theme={null}
sequenceDiagram
  autonumber
  participant Usr as User
  participant U as Your App
  participant B as Your Backend
  participant A as Uphold

  Usr->>U: Verify a saved crypto address
  U->>B: Set up verification
  B->>A: PUT /core/external-accounts/{id}/verifications/declared
  A-->>B: { verification (status: pending, requestForInformation) }
  B-->>U: Surface the self-declaration questions
  Usr->>U: Answer the questions
  U->>B: Submit proof
  B->>A: PUT /core/requests-for-information/{requestForInformationId}
  A-->>B: { requestForInformation (status: ok) }
  B-->>U: Verification completed
```

## Set up the verification

Call [Set up crypto external account verification](/rest-apis/core-api/external-accounts/setup-external-account-verification) with `level: "declared"`.

```http theme={null}
PUT /core/external-accounts/d0686449-36c7-c62e-b81f-de844bbc79d4/verifications/declared
```

A `201` response means a new verification was initiated. Its `requestForInformation.proofOptions.selfDeclaration.schema` describes exactly which fields to collect from the user.

```json [expandable] theme={null}
{
  "verification": {
    "via": "request-for-information",
    "level": "declared",
    "status": "pending",
    "requestForInformation": {
      "id": "19ca55fb-fc52-4209-b765-e3dbdc327231",
      "type": "crypto-address-travel-rule",
      "status": "pending",
      "context": {
        "network": "xrp-ledger",
        "addresses": [
          "rN7n7otQDd6FczFgLdlqtyMVrn3WD6CJYy"
        ]
      },
      "proofOptions": {
        "selfDeclaration": {
          "schema": {
            "type": "object",
            "required": [
              "isVASP",
              "isSelfHostedWallet",
              "isSelfOwnedCryptoAddress"
            ],
            "properties": {
              "isVASP": { "type": "boolean" },
              "isSelfHostedWallet": { "type": "boolean" },
              "isSelfOwnedCryptoAddress": { "type": "boolean" }
            }
          }
        }
      }
    }
  }
}
```

<Info>
  Calling this endpoint again is safe: while the verification is `pending` or `failed`, a new request for information is initiated (`201`). Once it's `completed`, the same verification is returned unchanged (`200`) — it's never redone or regressed.
</Info>

<Warning>
  If a stronger, `verified`-level verification is already `completed` for this address, this returns `409 operation_not_allowed` with `details.reasons` including `stronger-verification-already-completed` — there's nothing to declare, a cryptographic proof already covers it.
</Warning>

## Submit the self-declaration

Present the fields from `proofOptions.selfDeclaration.schema` to the user, then submit their answers with [Update request for information](/rest-apis/core-api/requests-for-information/update-request-for-information).

```http theme={null}
PUT /core/requests-for-information/19ca55fb-fc52-4209-b765-e3dbdc327231
{
  "proof": {
    "isVASP": false,
    "isSelfHostedWallet": true,
    "isSelfOwnedCryptoAddress": true
  }
}
```

```json [expandable] theme={null}
{
  "requestForInformation": {
    "id": "19ca55fb-fc52-4209-b765-e3dbdc327231",
    "type": "crypto-address-travel-rule",
    "status": "ok",
    "context": {
      "network": "xrp-ledger",
      "addresses": [
        "rN7n7otQDd6FczFgLdlqtyMVrn3WD6CJYy"
      ]
    },
    "proofOptions": {
      "selfDeclaration": {
        "schema": {
          "type": "object",
          "required": [
            "isVASP",
            "isSelfHostedWallet",
            "isSelfOwnedCryptoAddress"
          ],
          "properties": {
            "isVASP": { "type": "boolean" },
            "isSelfHostedWallet": { "type": "boolean" },
            "isSelfOwnedCryptoAddress": { "type": "boolean" }
          }
        }
      }
    },
    "proof": {
      "isVASP": false,
      "isSelfHostedWallet": true,
      "isSelfOwnedCryptoAddress": true
    }
  }
}
```

<Note>
  When `isVASP` is `true`, also include a `vaspDid` identifying the VASP that owns the address. If it can't be resolved by the Travel Rule provider, the request returns `404 entity_not_found` (`details.entity: "vasp"`) — ask the user to double-check the VASP they selected.
</Note>

## Confirm the verification

Call [Get external account verification](/rest-apis/core-api/external-accounts/get-external-account-verification) to confirm the verification is `completed`.

```http theme={null}
GET /core/external-accounts/d0686449-36c7-c62e-b81f-de844bbc79d4/verifications/declared
```

```json theme={null}
{
  "verification": {
    "via": "request-for-information",
    "level": "declared",
    "status": "completed",
    "completedAt": "2024-06-01T00:00:00.000Z",
    "requestForInformation": { "...": "..." }
  }
}
```

<Check>The address now carries a completed `declared` verification, reflected in the account's compact `verifications` array on [Get external account](/rest-apis/core-api/external-accounts/get-external-account).</Check>

## Testing

Verify the following:

1. [Set up crypto external account verification](/rest-apis/core-api/external-accounts/setup-external-account-verification) returns `201` with a `pending` verification and a `crypto-address-travel-rule` RFI.
2. [Update request for information](/rest-apis/core-api/requests-for-information/update-request-for-information) with a valid self-declaration proof returns `200` with `status: "ok"`.
3. [Get external account verification](/rest-apis/core-api/external-accounts/get-external-account-verification) now returns `status: "completed"`.
4. Calling [Set up crypto external account verification](/rest-apis/core-api/external-accounts/setup-external-account-verification) again returns `200` with the same, unchanged verification.
