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

# Verify account ownership

> Confirm control of social and work accounts, bind a portable handle to a wallet, and show a verified badge your app can check.

Confirm that a person controls an account, then reuse the proof across your apps. OAuth runs on Proofable, so you never handle provider tokens.

| Prove                                       | Check                                                      | Runs                          |
| ------------------------------------------- | ---------------------------------------------------------- | ----------------------------- |
| A social account                            | [`ownership-social`](/verification/ownership-social)       | Hosted                        |
| A Google Workspace or Microsoft 365 account | [`ownership-org-oauth`](/verification/ownership-org-oauth) | Hosted                        |
| A handle bound to a wallet                  | [`ownership-pseudonym`](/verification/ownership-pseudonym) | Signed in your app, or hosted |

## Linked accounts

Send the person to Hosted Verify and read the proof ID back:

```text theme={"dark"}
https://proofable.me/verify?verifiers=ownership-social&returnUrl=https://app.example.com/verified
```

Use `ownership-org-oauth` for work accounts. Its `expectedOrgDomain` field limits the proof to one company domain.

Store the proof ID from the `qHash` field and reuse it. Don't re-run the flow on every visit.

## Verified handles

Bind a handle to a wallet with `ownership-pseudonym`, then badge, link, and gate on the proof. It suits creator platforms, media networks, and launchpads that need handle ownership without legal identity.

### Flow

1. The user claims a handle in your app.
2. Your app asks Proofable to bind the handle, a `namespace`, and the wallet.
3. Proofable returns a proof ID in `qHash` and a proof URL.
4. Your app stores the proof ID with the user record.
5. Your app shows a verified badge that links to the proof page.
6. Before any privileged action, your server checks the proof.

### Sign in your app

Use `client.verify()` when your app already handles wallet signatures:

```js theme={"dark"}
import { ProofableClient } from '@proofable/sdk';

const client = new ProofableClient();

const proof = await client.verify({
  verifier: 'ownership-pseudonym',
  data: {
    pseudonymId: 'alice123', // 3 to 32 lowercase characters
    namespace: 'acme', // keeps your handles separate from the default namespace
    displayName: 'Alice',
    metadata: { platform: 'acme' },
  },
  wallet: window.ethereum,
});

// Store proof.qHash with the user record.
// proof.proofUrl is https://proofable.me/proof/{qHash}
```

`pseudonymId` must match `^[a-z0-9][a-z0-9._-]{1,30}[a-z0-9]$`. Handle proofs expire, so re-verify before `expiresAt`.

### Or verify on Proofable

```js theme={"dark"}
import { getHostedCheckoutUrl } from '@proofable/sdk';

window.location.assign(
  getHostedCheckoutUrl({
    gateId: 'gate_acme-handles',
    returnUrl: 'https://acme.network/handle/callback',
  }),
);
```

Read the proof ID from the `qHash` field in the callback URL or popup message, and store it.

### Show the badge

```jsx theme={"dark"}
import { ProofBadge } from '@proofable/sdk/widgets';

export function CreatorHandle({ handle, qHash }) {
  return (
    <div className="handle-row">
      <span>@{handle}</span>
      <ProofBadge qHash={qHash} />
    </div>
  );
}
```

The badge links to `https://proofable.me/proof/{qHash}` and shows live status.

### Check on your server

```js theme={"dark"}
const result = await client.gateCheck({
  gateId: 'gate_acme-handles',
  address: walletAddress,
});

if (result.data?.gate?.allRequiredSatisfied !== true) {
  throw new Error('Handle not verified');
}
```

Or call the HTTP API:

```bash theme={"dark"}
curl "https://api.proofable.me/api/v1/proofs/check?gateId=gate_acme-handles&address=0x...&namespace=acme"
```

### Namespaces

Namespaces other than the default require the namespace owner to confirm DNS control with [`ownership-dns-txt`](/verification/ownership-dns-txt), or approval from Proofable. Contact Proofable to reserve a production namespace.

A complete React and Vite app is in the [verified-handle-react example](https://github.com/proofable/sdk/tree/main/examples/verified-handle-react).
