Resolve a handle
StableLook up who owns a handle. Resolution is read-only and public — no wallet, no signature, and no API key. The base URL is https://api.x1id.io; there is no /v1 prefix. The REST endpoint returns the handle's owner; for per-chain addresses (X1 / SOL / ETH / BTC) and richer results, use the SDK below.
Handles, not domains. X1ID handles (@jack) and X1NS domains (jack.x1) are complementary — this resolves handles. See how they fit together.
Parameters
The handle to resolve, with or without the leading @. Case-insensitive — x1 and @X1 resolve the same record. Given as a path segment: /resolve/x1.
Returns
Returns the resolution object for the handle. It reports the current owner and whether the handle is tokenized — it does not carry an addresses map or an expiry (names are permanent, so there is nothing to expire). An unregistered handle returns 404 { "error": "handle not registered" }.
{
"input": "x1",
"name": "x1",
"namespace": "handle",
"owner": "H8FsKYhMyCN9brknY7tL4JXRbKZEjVh7XgrVmWcX1HiA",
"tokenized": false,
"verification": "owner"
}| field | meaning |
|---|---|
input | the raw value you passed |
name | the normalized handle (no @) |
namespace | always handle for this endpoint |
owner | the wallet that owns the handle. For a tokenized handle this is informational — authority follows the NFT holder |
tokenized | whether the handle has been turned into an NFT |
verification | owner when the owner controls the registry account |
Ownership you can audit. Every handle is a record on the X1 registry program (8JgnNWi24bq9uzfnT9XmkWxvaWMVgoEs9bu8QsHhLe1P), so a resolution can be verified independently on-chain. See Trust & transparency.
Reverse lookup
Go the other way — an address back to its @handle. Only the address the owner has explicitly marked as their primary reverse-resolves, which is what prevents impersonation. An address with no primary returns 404 { "error": "no primary set" }.
curl https://api.x1id.io/reverse/H8FsKYhMyCN9brknY7tL4JXRbKZEjVh7XgrVmWcX1HiA
# 404 → { "error": "no primary set", "input": "H8FsKYhMyCN9…VmWcX1HiA" }Health
A liveness check for the service.
curl https://api.x1id.io/health
# → { "ok": true }SDK: multi-chain, records, and writes
The REST endpoint answers "who owns this handle". For per-chain addresses, records, and on-chain writes, use the @x1id/resolve SDK. It reads chain state directly over RPC (it never depends on this API's uptime), and its writes are unsigned instruction builders you sign and relay yourself — the SDK never holds keys. The @handle registry is on X1 testnet today (https://rpc.testnet.x1.xyz).
npm install @x1id/resolveRead: resolve across chains
resolve(input, { chain }) returns a Resolved object. X1/SOL come from the handle's authority; ETH/BTC from its on-chain records.
import { createResolver, WasmResolver } from '@x1id/resolve';
const wasm = await WasmResolver.fromBytes(/* module bytes */);
const x1id = createResolver({ rpcUrl: 'https://rpc.testnet.x1.xyz', wasm });
const r = await x1id.resolve('@x1', { chain: 'SOL' });
// {
// input: '@x1', name: 'x1', namespace: 'handle',
// address: 'H8FsKYhMyCN9brknY7tL4JXRbKZEjVh7XgrVmWcX1HiA',
// chain: 'SOL', verification: 'verified'
// }
// A handle with no record for the requested chain is explicit, never a wrong
// address: resolve('@x1', { chain: 'ETH' }) throws
// ResolveError { code: 'no-record-for-chain' }.Read: reverse and records
const name = await x1id.reverse(address);
// 'nike' → the address's primary @handle (no '@')
// null → no primary set
const recs = await x1id.records('@x1');
// HandleRecord[]: { account, handle, coinType, chain, value, address,
// verified, updatedAt, stale } ([] when none are set)Write: sign and relay yourself
Registration and set_primary run from app.x1id.io today. The SDK ships builders for the rest of the registry — each returns an unsigned { programId, keys, data } you assemble, sign, and send:
import { buildCreateSubnameIx } from '@x1id/resolve';
const ix = buildCreateSubnameIx({
programId, // 8JgnNWi24bq9uzfnT9XmkWxvaWMVgoEs9bu8QsHhLe1P
payer, owner, // signers — owner is the parent handle's authority
parent, subname, // the parent and subname PDAs
label: 'team', // issues team.you
});
// add ix to a transaction, sign with payer + owner, send.Also shipped, same build → sign → relay shape: gifts (buildCreateVoucherIx + HandleType), integrator rev-share (buildAddIntegratorIx), name locks (buildLockHandleIx), record delegation (buildSetRecordDelegateIx), and typed text records (buildCreateTextRecordIx). Full list in the SDK README.
Which RPC? Point the resolver at the chain that holds the names you want. @handle resolution is on X1 testnet today; on an RPC where the registry is not deployed a handle is an honest not-found, never a fabricated address.
