Tutorials & SDKs

Java Integration

Use Hive from JVM services with Java HttpClient. This guide covers bearer authentication, REST execution, tool discovery, structured error handling, and reusable client code for services that need live crypto prices, wallet data, DeFi analytics, and token security.

Requirements: Java 11+


Dependencies

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.17.0</version>
</dependency>

Quick Start

import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Map;

public class HiveExample {
    private static final String BASE_URL = "https://mcp.hiveintelligence.xyz";

    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("HIVE_API_KEY");
        ObjectMapper mapper = new ObjectMapper();

        Map<String, Object> payload = Map.of(
            "tool", "get_price",
            "args", Map.of("ids", "bitcoin", "vs_currencies", "usd")
        );

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(BASE_URL + "/api/v1/execute"))
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + apiKey)
            .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload)))
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

Reusable Client

import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;

public class HiveClient {
    private final String baseUrl;
    private final String apiKey;
    private final HttpClient httpClient;
    private final ObjectMapper objectMapper;

    public HiveClient(String apiKey) {
        this.baseUrl = "https://mcp.hiveintelligence.xyz";
        this.apiKey = apiKey;
        this.httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(30))
            .build();
        this.objectMapper = new ObjectMapper();
    }

    public Map<String, Object> execute(String tool, Map<String, Object> args) throws Exception {
        Map<String, Object> payload = Map.of(
            "tool", tool,
            "args", args
        );

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/api/v1/execute"))
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + apiKey)
            .POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(payload)))
            .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 300) {
            throw new RuntimeException("Hive request failed: " + response.body());
        }

        return objectMapper.readValue(response.body(), Map.class);
    }
}

Discovery

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://mcp.hiveintelligence.xyz/api/v1/tools?limit=50"))
    .header("Authorization", "Bearer " + System.getenv("HIVE_API_KEY"))
    .GET()
    .build();

Example Calls

HiveClient client = new HiveClient(System.getenv("HIVE_API_KEY"));

Map<String, Object> market = client.execute("get_coins_market_data", Map.of(
    "vs_currency", "usd",
    "order", "market_cap_desc",
    "per_page", 5
));

Map<String, Object> wallet = client.execute("moralis_get_wallet_net_worth", Map.of(
    "address", "0x1234...",
    "chain", "eth"
));

Map<String, Object> prediction = client.execute("codex_prediction_markets", Map.of(
    "networkId", 1
));

Error Handling

Hive returns a JSON envelope on every response. Non-2xx bodies carry a structured error object — parse it before retrying:

import com.fasterxml.jackson.databind.JsonNode;

public class HiveException extends RuntimeException {
    public final int httpStatus;
    public final String code;
    public HiveException(int httpStatus, String code, String message) {
        super(code + ": " + message);
        this.httpStatus = httpStatus;
        this.code = code;
    }
}

private Map<String, Object> executeWithRetry(String tool, Map<String, Object> args, int maxRetries)
        throws Exception {
    Exception last = null;
    for (int attempt = 0; attempt < maxRetries; attempt++) {
        try {
            HttpResponse<String> response = httpClient.send(buildRequest(tool, args),
                    HttpResponse.BodyHandlers.ofString());
            int status = response.statusCode();
            if (status == 429) {
                long retryAfter = response.headers().firstValueAsLong("Retry-After").orElse(1L << attempt);
                Thread.sleep(retryAfter * 1000L);
                continue;
            }
            if (status >= 500) {
                Thread.sleep(1000L * (1L << attempt));
                continue;
            }
            if (status >= 400) {
                JsonNode body = objectMapper.readTree(response.body());
                throw new HiveException(status,
                        body.path("error").path("code").asText("unknown"),
                        body.path("error").path("message").asText(response.body()));
            }
            return objectMapper.readValue(response.body(), Map.class);
        } catch (java.io.IOException | InterruptedException exc) {
            last = exc;
            Thread.sleep(1000L * (1L << attempt));
        }
    }
    throw new HiveException(0, "exhausted_retries", "All retries failed: " + last);
}

Key HTTP codes to handle:

  • 400 — invalid tool name or args.
  • 401 — missing or invalid API key. Rotate via the dashboard; don't retry.
  • 429 — rate-limited. Honor Retry-After; exponential backoff otherwise.
  • 502 / 503 — upstream provider failure. Exponential backoff.

Async with CompletableFuture

For fan-out patterns (daily briefings, concurrent wallet profiles) use sendAsync:

import java.util.concurrent.CompletableFuture;
import java.util.List;

public CompletableFuture<JsonNode> executeAsync(String tool, Map<String, Object> args) throws Exception {
    HttpRequest request = buildRequest(tool, args);
    return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
            .thenApply(response -> {
                if (response.statusCode() >= 300) {
                    throw new RuntimeException("Hive call failed: " + response.body());
                }
                try {
                    return objectMapper.readTree(response.body());
                } catch (Exception exc) {
                    throw new RuntimeException(exc);
                }
            });
}

// Fan out 3 concurrent tool calls for a market brief
HiveClient client = new HiveClient(System.getenv("HIVE_API_KEY"));
CompletableFuture<JsonNode> prices = client.executeAsync("get_price", Map.of(
        "ids", "bitcoin,ethereum", "vs_currencies", "usd"));
CompletableFuture<JsonNode> tvl = client.executeAsync("get_protocol_tvl", Map.of());
CompletableFuture<JsonNode> oi = client.executeAsync("get_open_interest", Map.of("exchange", "binance"));

CompletableFuture.allOf(prices, tvl, oi).join();
System.out.println("Brief assembled: " + prices.get() + tvl.get() + oi.get());

Hive bills one credit per tool call regardless of concurrency, so fan-out is the right default for research and reporting agents.


Tool Discovery

Prefer runtime discovery over hardcoded schemas — new tools show up automatically as Hive ships providers:

public List<JsonNode> discover(String search) throws Exception {
    List<JsonNode> items = new java.util.ArrayList<>();
    String cursor = null;
    while (true) {
        StringBuilder url = new StringBuilder(baseUrl).append("/api/v1/tools?limit=200");
        if (cursor != null) url.append("&cursor=").append(cursor);
        if (search != null) url.append("&search=").append(search);
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url.toString()))
                .header("Authorization", "Bearer " + apiKey)
                .GET().build();
        JsonNode page = objectMapper.readTree(
                httpClient.send(request, HttpResponse.BodyHandlers.ofString()).body());
        page.path("data").forEach(items::add);
        JsonNode nextCursor = page.path("meta").path("cursor");
        if (nextCursor.isMissingNode() || nextCursor.isNull()) return items;
        cursor = nextCursor.asText();
    }
}

List<JsonNode> walletTools = client.discover("wallet");

Spring Boot Integration

If you run on Spring, register the client as a singleton bean and inject it into services:

@Configuration
public class HiveConfig {
    @Bean
    public HiveClient hiveClient(@Value("${hive.api.key}") String apiKey) {
        return new HiveClient(apiKey);
    }
}

@Service
public class MarketIntelService {
    private final HiveClient hive;

    public MarketIntelService(HiveClient hive) {
        this.hive = hive;
    }

    public Map<String, Object> briefing() throws Exception {
        return hive.execute("get_price",
                Map.of("ids", "bitcoin,ethereum,solana", "vs_currencies", "usd"));
    }
}

Use Spring's @Retryable or Resilience4j for retry policy instead of hand-rolled loops.


Notes

  • The current REST payload keys are tool and args. Older toolName / arguments examples are legacy.
  • Use GET /api/v1/tools for live schemas and tool discovery; never hardcode definitions.
  • Failed 4xx calls do not consume credits; 5xx server errors are refunded.
  • Every response carries a fetched_at timestamp agents can use to reason about staleness.