# HTTP Client

Complete guide for integrating with NCN Network using HTTP REST API.

***

## Overview

The HTTP API provides:

* Simple REST interface
* JSON request/response format
* Easy integration with any language
* Web browser compatibility

***

## Base URL

| Environment | URL                                  |
| ----------- | ------------------------------------ |
| Local       | `http://localhost:8080`              |
| Testnet     | `https://api.testnet.ncn-network.io` |
| Mainnet     | `https://api.ncn-network.io`         |

***

## Endpoints

### Health Check

```http
GET /health
```

**Response:**

```json
{
  "status": "healthy",
  "version": "0.1.0",
  "uptime_seconds": 3600
}
```

### Submit Inference

```http
POST /api/v1/inference
Content-Type: application/json

{
  "model_uuid": "bark_semantic",
  "input_data": "{\"text\": \"Hello, world!\"}"
}
```

**Response:**

```json
{
  "request_id": "req-abc123",
  "status": "queued",
  "payment_required": false
}
```

### Get Task Status

```http
GET /api/v1/inference/{request_id}
```

**Response:**

```json
{
  "request_id": "req-abc123",
  "status": "completed",
  "output_data": "{\"tokens\": [1, 2, 3]}",
  "error_message": null
}
```

### List Models

```http
GET /api/v1/models
```

**Response:**

```json
{
  "models": [
    {
      "model_uuid": "bark_semantic",
      "name": "Bark Semantic Model",
      "category": "audio",
      "description": "Text to semantic tokens"
    }
  ]
}
```

***

## Client Examples

### cURL

```bash
# Submit inference
curl -X POST http://localhost:8080/api/v1/inference \
  -H "Content-Type: application/json" \
  -d '{
    "model_uuid": "bark_semantic",
    "input_data": "{\"text\": \"Hello, world!\"}"
  }'

# Get status
curl http://localhost:8080/api/v1/inference/req-abc123

# Health check
curl http://localhost:8080/health
```

### Python (requests)

```python
import requests
import json
import time

class NCNHttpClient:
    def __init__(self, base_url='http://localhost:8080'):
        self.base_url = base_url
        self.session = requests.Session()
    
    def submit_inference(self, model_uuid, input_data):
        """Submit an inference request."""
        response = self.session.post(
            f"{self.base_url}/api/v1/inference",
            json={
                "model_uuid": model_uuid,
                "input_data": json.dumps(input_data) if isinstance(input_data, dict) else input_data
            }
        )
        response.raise_for_status()
        return response.json()
    
    def get_status(self, request_id):
        """Get task status."""
        response = self.session.get(
            f"{self.base_url}/api/v1/inference/{request_id}"
        )
        response.raise_for_status()
        return response.json()
    
    def inference(self, model_uuid, input_data, timeout=60, poll_interval=1):
        """Submit inference and wait for result."""
        # Submit
        result = self.submit_inference(model_uuid, input_data)
        request_id = result['request_id']
        
        # Poll for result
        start_time = time.time()
        while time.time() - start_time < timeout:
            status = self.get_status(request_id)
            
            if status['status'] == 'completed':
                return json.loads(status['output_data'])
            elif status['status'] == 'failed':
                raise Exception(status.get('error_message', 'Unknown error'))
            
            time.sleep(poll_interval)
        
        raise TimeoutError(f"Request {request_id} timed out")
    
    def health_check(self):
        """Check if gateway is healthy."""
        response = self.session.get(f"{self.base_url}/health")
        response.raise_for_status()
        return response.json()

# Usage
client = NCNHttpClient()
result = client.inference(
    model_uuid="bark_semantic",
    input_data={"text": "Hello, world!"}
)
print(result)
```

### JavaScript (fetch)

```javascript
class NCNHttpClient {
  constructor(baseUrl = 'http://localhost:8080') {
    this.baseUrl = baseUrl;
  }

  async submitInference(modelUuid, inputData) {
    const response = await fetch(`${this.baseUrl}/api/v1/inference`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        model_uuid: modelUuid,
        input_data: typeof inputData === 'object' 
          ? JSON.stringify(inputData) 
          : inputData
      })
    });
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${await response.text()}`);
    }
    
    return response.json();
  }

  async getStatus(requestId) {
    const response = await fetch(`${this.baseUrl}/api/v1/inference/${requestId}`);
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${await response.text()}`);
    }
    
    return response.json();
  }

  async inference(modelUuid, inputData, timeout = 60000, pollInterval = 1000) {
    // Submit
    const result = await this.submitInference(modelUuid, inputData);
    const requestId = result.request_id;
    
    // Poll for result
    const startTime = Date.now();
    while (Date.now() - startTime < timeout) {
      const status = await this.getStatus(requestId);
      
      if (status.status === 'completed') {
        return JSON.parse(status.output_data);
      } else if (status.status === 'failed') {
        throw new Error(status.error_message || 'Unknown error');
      }
      
      await new Promise(resolve => setTimeout(resolve, pollInterval));
    }
    
    throw new Error(`Request ${requestId} timed out`);
  }

  async healthCheck() {
    const response = await fetch(`${this.baseUrl}/health`);
    return response.json();
  }
}

// Usage
const client = new NCNHttpClient();
const result = await client.inference('bark_semantic', { text: 'Hello, world!' });
console.log(result);
```

### Go

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "time"
)

type NCNClient struct {
    BaseURL string
    Client  *http.Client
}

type InferenceRequest struct {
    ModelUUID string `json:"model_uuid"`
    InputData string `json:"input_data"`
}

type InferenceStatus struct {
    RequestID    string `json:"request_id"`
    Status       string `json:"status"`
    OutputData   string `json:"output_data"`
    ErrorMessage string `json:"error_message"`
}

func NewNCNClient(baseURL string) *NCNClient {
    return &NCNClient{
        BaseURL: baseURL,
        Client:  &http.Client{Timeout: 30 * time.Second},
    }
}

func (c *NCNClient) SubmitInference(modelUUID string, inputData interface{}) (*InferenceStatus, error) {
    inputJSON, _ := json.Marshal(inputData)
    
    reqBody, _ := json.Marshal(InferenceRequest{
        ModelUUID: modelUUID,
        InputData: string(inputJSON),
    })
    
    resp, err := c.Client.Post(
        c.BaseURL+"/api/v1/inference",
        "application/json",
        bytes.NewBuffer(reqBody),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    var status InferenceStatus
    json.NewDecoder(resp.Body).Decode(&status)
    return &status, nil
}

func (c *NCNClient) GetStatus(requestID string) (*InferenceStatus, error) {
    resp, err := c.Client.Get(c.BaseURL + "/api/v1/inference/" + requestID)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    var status InferenceStatus
    json.NewDecoder(resp.Body).Decode(&status)
    return &status, nil
}

func (c *NCNClient) Inference(modelUUID string, inputData interface{}, timeout time.Duration) (map[string]interface{}, error) {
    result, err := c.SubmitInference(modelUUID, inputData)
    if err != nil {
        return nil, err
    }
    
    deadline := time.Now().Add(timeout)
    for time.Now().Before(deadline) {
        status, err := c.GetStatus(result.RequestID)
        if err != nil {
            return nil, err
        }
        
        if status.Status == "completed" {
            var output map[string]interface{}
            json.Unmarshal([]byte(status.OutputData), &output)
            return output, nil
        } else if status.Status == "failed" {
            return nil, fmt.Errorf("task failed: %s", status.ErrorMessage)
        }
        
        time.Sleep(1 * time.Second)
    }
    
    return nil, fmt.Errorf("timeout")
}

func main() {
    client := NewNCNClient("http://localhost:8080")
    
    result, err := client.Inference("bark_semantic", map[string]string{
        "text": "Hello, world!",
    }, 60*time.Second)
    
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    fmt.Printf("Result: %v\n", result)
}
```

***

## Error Handling

### HTTP Status Codes

| Code | Meaning      | Action             |
| ---- | ------------ | ------------------ |
| 200  | Success      | Process response   |
| 400  | Bad Request  | Check input format |
| 404  | Not Found    | Check request\_id  |
| 429  | Rate Limited | Retry with backoff |
| 500  | Server Error | Retry or report    |
| 503  | Unavailable  | Retry later        |

### Error Response Format

```json
{
  "error": {
    "code": "INVALID_MODEL",
    "message": "Model 'unknown' not found",
    "details": {}
  }
}
```

### Retry Logic

```python
import time
from requests.exceptions import RequestException

def retry_request(func, max_retries=3, backoff=1.0):
    for attempt in range(max_retries):
        try:
            return func()
        except RequestException as e:
            if attempt < max_retries - 1:
                if hasattr(e.response, 'status_code'):
                    if e.response.status_code in [429, 503]:
                        time.sleep(backoff * (2 ** attempt))
                        continue
            raise
```

***

## Authentication (Future)

When API keys are implemented:

```http
Authorization: Bearer YOUR_API_KEY
```

```python
client = NCNHttpClient()
client.session.headers['Authorization'] = 'Bearer YOUR_API_KEY'
```

***

## Rate Limiting

### Limits

| Endpoint                 | Limit    |
| ------------------------ | -------- |
| POST /api/v1/inference   | 100/min  |
| GET /api/v1/inference/\* | 1000/min |
| GET /health              | No limit |

### Rate Limit Headers

```http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1704067260
```

### Handle Rate Limits

```python
def handle_rate_limit(response):
    if response.status_code == 429:
        reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
        wait_time = max(reset_time - time.time(), 1)
        time.sleep(wait_time)
        return True
    return False
```

***

## Next Steps

* [gRPC Client](/nc/neurochainai-guides/clients/grpc-client.md) - Higher performance option
* [Payment Integration](/nc/neurochainai-guides/clients/payment-integration.md) - Handle payments
* [Examples](/nc/neurochainai-guides/clients/examples.md) - More code examples


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.neurochain.ai/nc/neurochainai-guides/clients/http-client.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
