Connect your app to a Host
How you connect to a Host depends on your architecture. A local-first Go app embeds DefraDB and peers with Hosts over libp2p, so it needs connection strings. A direct-query TypeScript app talks to a Host's GraphQL endpoint over HTTP, so it needs an endpoint URL. Both start with the discovery step in Find Views and Hosts, which shows where each value comes from.
A Host client exposes four interfaces:
| Port | Interface |
|---|---|
| 9181 | GraphQL API at /api/v0/graphql |
| 9182 | GraphQL playground, when enabled |
| 9171 | libp2p peering |
| 8080 | Health and self-description endpoints |
Public Hosts vary in how they publish these, so always read the actual connection_string and endpoint_address from the registry instead of assuming ports.
Check a Host's health first
Before wiring a Host into your app, check that it is alive and processing data:
curl -s -H "Accept: application/json" http://<host>:8080/health | jq '{status, current_block}'
{
"status": "healthy",
"current_block": 25903651
}
The Accept: application/json header asks for the JSON form; a browser gets an HTML status page instead. A healthy status with a recent current_block means the Host is peered and syncing. The same server answers GET /registration with the Host's DID, connection_string, and endpoint_address, which is a quick way to confirm a Host's identity before you trust its data.
Embedded app (Go)
A local-first app receives pushed data over libp2p, so the connection happens in the app-sdk config. Take the Host's connection_string from the registry:
curl -s http://testnet.shinzo.network:1317/shinzonetwork/host/v1/hosts \
| jq -r '.hosts[].connection_string'
Add one or more of them to defradb.p2p.bootstrap_peers in your config.yaml:
defradb:
p2p:
enabled: true
bootstrap_peers:
- "/ip4/34.66.172.230/tcp/9171/p2p/12D3KooWKVCMswzcXYe9kW2z7nSB9YUWjVVLsMbJnBjVPFUQkbQ7"
listen_addr: "/ip4/127.0.0.1/tcp/9171"
Use the full multiaddr form /ip4/<ip>/tcp/9171/p2p/<peerID> exactly as the registry returns it. Bare IPs (34.66.172.230), ip:port pairs (34.66.172.230:9171), and multiaddrs without a /p2p/<peerID> suffix do not work here: the embedded app passes each entry straight to DefraDB, which requires the peer ID, and the app ends up connected to 0 peers. (The peer-ID auto-discovery you may have read about is a Host client feature; it doesn't apply to an app-sdk config.) Listing a few bootstrap peers makes the first connection more reliable, since registered Hosts come and go on a testnet. Pick bootstrap peers from Hosts shown as Online in the Explorer.
Once peered, subscribe to a View and data starts arriving. Subscribe to Views with the app-sdk covers that flow.
Direct-query app (TypeScript)
A direct-query app never peers with anything. It reads the Host's endpoint_address from the registry and POSTs signed GraphQL requests to it:
curl -s http://testnet.shinzo.network:1317/shinzonetwork/host/v1/hosts \
| jq -r '.hosts[].endpoint_address'
Registry entries can outlive the Hosts behind them, so pick a Host shown as Online in the Explorer and use its endpoint_address.
The endpoint already includes the API path, so you POST straight to it:
curl -s -X POST "http://34.66.172.230/api/v0/graphql" \
-H "Content-Type: application/json" \
-d '{
"query": "{ Erc20Event(limit: 1) { blockNumber } }",
"extensions": {
"request_signature": "0x<signature>",
"query_hash": "0x<query-hash>",
"nonce": "0x<random-32-bytes>",
"request_timestamp": 1788433155,
"pool_address": "0x<pool-address>",
"fanout": 1
}
}'
View queries carry a signature in the extensions envelope, and one billed query maps to one pool: a request can touch only one View collection, and its pool_address extension names the pool it bills to. The 0x<...> values above are placeholders — the signature commits to this exact query, a fresh nonce, and a timestamp, so no static example can be valid; the tutorial generates a fresh envelope on every run. When a Host enforces billing, rejections come back as plain errors: 403 if the request signature is missing, stale, or fails verification, and 402 if the signer's query balance is too low. Query your first View builds the signing flow end to end.
Billing enforcement is rolling out on the testnet, so some Hosts still answer unsigned queries. Signed requests are the supported interface either way; treat unsigned access as a convenience that will go away.
Prefer your own Host
Public Hosts are shared infrastructure. If you want guaranteed availability, or you'd rather no third party see your queries at all, you can point everything above at a Host you run yourself. See Use your own infrastructure.
Need help
- For onboarding and technical support, join the Shinzo Discord.
- To report a documentation bug or request a feature, open an issue in the docs repo.
- For a technical issue with the Host client, open an issue in the shinzo-host-client repo.