# Developers

Three things to build on URnetwork, and three different credentials. Picking
the right one is the first decision, and the difference is not cosmetic.

| You are building | Start with | Credential |
| --- | --- | --- |
| An app or device that connects to URnetwork | [SDK](/docs/getting-started-sdk), then the [SDK tour](/docs/tour-sdk) | An account JWT, exchanged for one carrying a `clientId` |
| Automation over your own network | [Operator API](/docs/api) | Your network JWT or `urn_` API key |
| A product people sign in to, admitting it to their network | [Sign in with URnetwork](/docs/sign-in-with-urnetwork) | An OAuth `client_id` issued to you |

The line that matters is **whose network you are acting on**. The SDK and the
Operator API are you acting on your own, with a credential you hold and control.
Sign in with URnetwork is a person admitting your software to *theirs* — you
never hold that credential, they grant it and they can withdraw it.

## The SDK

One Go core, compiled four ways: native code bound for Kotlin on Android and
Swift on iOS/macOS, a c-shared library behind a C ABI for Windows and Linux, and
WebAssembly for the browser. They front the same engine, so behavior matches
across platforms — but only three of the four can move packets, because a
browser page cannot own a tun interface.

[Which binding to pick](/docs/getting-started-sdk#which-binding) lays out the
trade-offs side by side. Take that decision before you write code: it settles
your process model, not just your syntax.

## Operator API

The HTTP API behind URnetwork. It bootstraps the `connect` protocol, issues the
JWTs clients authenticate with, and exposes the match-making transactions the
network runs on. Every route and schema is at [/docs/api](/docs/api), generated
from the specification.

It is scoped to **your** network. The name invites the reading that it operates
on the network generally; it does not.

One step trips nearly everyone: the `/auth` routes return a JWT **without** a
`clientId`, and the `connect` protocol requires one **with** it. Use the
`/network` routes to exchange it. A network is a globally unique subnet
(`xyz.ur.network`); a `clientId` is a 16-byte address, equivalent to an IPv6
address and expressed as a UDID.

## Sign in with URnetwork

Lets people admit your app or agent to their private network, so it can
coordinate with everything else they have running there. This is in development
and not yet live — see the [page itself](/docs/sign-in-with-urnetwork) for what
exists today.

The [MCP server](/docs/mcp) is not a fourth category. It is one resource server
reachable with a Sign in with URnetwork token, and a worked example of the
pattern.

## Token boundaries

The two credential systems are signed with **disjoint key sets**. That is a
security boundary rather than a convention: a Sign in with URnetwork token is
not a platform credential, and presenting one where a platform JWT is expected
fails by construction. OAuth access tokens are also audience-bound — each one
verifies for exactly one resource and is rejected everywhere else.

There is one sanctioned crossing, and it is a bridge rather than a bypass: an
admitted app exchanges its OAuth token for a platform JWT carrying a `clientId`,
scoped to the network it was admitted to. The exchange is an authorization
decision made server-side; no single token verifies in two places.

If you are holding two credentials and one of them is not working, this is
usually why.
