nimimo Logonimimo
All articles
·4 min read

How Handle Resolution Works

A name goes in, three addresses come out. Here is the whole mechanism, and why the server can hold it safely.

identitytechnical

A crypto address is a bad name. bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq is not something you say out loud, write on an invoice, or check twice before pressing send. It is a checksum wearing a costume.

Naming systems exist to fix this, but nearly all of them are chain-shaped. A name on Ethereum resolves on Ethereum. It does not help you receive Bitcoin. You end up with one name per chain, which is the original problem with extra steps.

nimimo resolves one handle to every chain you have an address on. This post is the mechanism. It covers what happens between @lucky-mountain going in and three addresses coming out, and why the part that lives on our server is not the part that could hurt you.

The server is a directory, not a vault

Resolution is a lookup. You give the system a name, it gives you back public addresses. That is the entire operation. No signing, no authorization, no access to funds. The response contains only information that is meant to be published.

This is why the directory can live on a server without weakening the non-custodial model. Your addresses are derived on your device from a secret that never leaves it. The server receives the addresses afterwards, as public data, the same way it would receive a display name.

An identity has to live somewhere central because a namespace needs an arbiter. Two people cannot both be @lucky-mountain, and you cannot settle that question on a device that is offline half the time. So the namespace is centralized and the keys are not. Those are separable problems, and nimimo separates them.

The public endpoint

Resolution is exposed as a read-only HTTP endpoint. No key, no account, no SDK required. It answers a GET and it sets permissive CORS headers, so a browser page can call it directly.

curl 'https://nimimo.com/api/v1/resolve?handle=lucky-mountain'

The response is the handle and the addresses it currently maps to:

{
  "handle": "lucky-mountain",
  "addresses": {
    "bitcoin": "bc1q...",
    "ethereum": "0x...",
    "solana": "..."
  }
}

If you only care about one chain, ask for one chain. The shape of the response changes to match, so you do not have to reach into a map for a key that might not be there:

// GET /api/v1/resolve?handle=lucky-mountain&chain=bitcoin
{
  "handle": "lucky-mountain",
  "chain": "bitcoin",
  "address": "bc1q..."
}

An unknown handle is an explicit answer rather than an empty one. You get a structured error, not an empty object that your code has to guess about:

{
  "error": "not_found",
  "message": "Handle not found"
}

Why the response shape matters

Two details in there are deliberate, and both exist because of how integration code actually fails.

The first is that a single-chain request returns a single address field instead of a one-entry map. Code that asks for Bitcoin and receives a map has to index into it, and indexing into a map is where a missing chain silently becomes undefined and then silently becomes a send to nowhere.

The second is that not-found is an error object rather than an empty address map. An empty map is indistinguishable from a handle that exists but has no addresses yet, and those two cases deserve very different behaviour in your UI.

Resolution tells you where to send. It does not tell you who owns the handle in any legally meaningful sense. Treat a resolved address the way you would treat an address someone sent you in a message: correct for the name you asked about, and worth confirming through a second channel for large amounts.

What resolution is not

It is not a transaction path. Nothing in the resolve endpoint can move funds, because nothing in the resolve endpoint has access to a key. The worst case for a compromised directory is that someone learns which addresses belong to which handle, information that is already public on the profile page and, by design, on the chains themselves.

It is also not a guarantee of permanence in the way a chain is. Addresses are cached server state, and server state can be edited by whoever controls the server. This is the honest limit of the directory model, and it is the reason the addresses are derived rather than assigned: your device can always recompute what your addresses should be, from your own secret, without asking us.

That is the property worth internalizing. The directory is a convenience layer over a derivation you could perform yourself. If it disappeared tomorrow, your funds would be exactly where they were, reachable by anyone holding the same seed.

Building on it

If you are integrating, the endpoint is public and the resolution path is open source; it is part of nimimo-core, published earlier this month. You can read exactly what a handle turns into before you depend on it, which is a different relationship than trusting a documented contract.

A name that works on three chains is a small idea. It is only useful because of what sits behind it: a derivation that happens on your device, a directory that holds nothing dangerous, and a lookup you can verify line by line.

Ready to try it?

No seed phrases. No KYC. Just an email.

Read the API docs