> ## Documentation Index
> Fetch the complete documentation index at: https://spartera.readme.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Response Schema Specification

## Response Schema Specification

## Overview

Spartera requires a standardized response format to ensure consistency across all models
in the marketplace. This page provides detailed specifications and examples for implementing
the required response schema.

## Required Response Format

### Structure

```json
{
  "timestamp": "2026-01-30T19:30:00.000000+00:00",
  "answer_value": 123.45,
  "asset_id": "optional-identifier"
}
```

### Field Specifications

#### 1. `timestamp` (Required)

**Type:** String\
**Format:** ISO-8601 with timezone (UTC recommended)\
**Purpose:** Records when the prediction was generated

**Valid Formats:**

```json
// ✅ Recommended (with microseconds and timezone)
"2026-01-30T19:30:00.000000+00:00"

// ✅ Acceptable (with timezone)
"2026-01-30T19:30:00+00:00"

// ✅ Acceptable (Z notation for UTC)
"2026-01-30T19:30:00.000000Z"

// ❌ Invalid (no timezone)
"2026-01-30T19:30:00"

// ❌ Invalid (wrong format)
"01/30/2026 7:30 PM"
```

**Implementation Examples:**

```python
# Python
from datetime import datetime, timezone

timestamp = datetime.now(timezone.utc).isoformat()
# Output: "2026-01-30T19:30:00.123456+00:00"
```

```javascript
// JavaScript/Node.js
const timestamp = new Date().toISOString();
// Output: "2026-01-30T19:30:00.123Z"
```

```java
// Java
import java.time.Instant;

String timestamp = Instant.now().toString();
// Output: "2026-01-30T19:30:00.123456Z"
```

```go
// Go
import "time"

timestamp := time.Now().UTC().Format(time.RFC3339Nano)
// Output: "2026-01-30T19:30:00.123456789Z"
```

#### 2. `answer_value` (Required)

**Type:** Number (float or integer)\
**Purpose:** The prediction result from your model

**Valid Types:**

```json
// ✅ Float
"answer_value": 123.45

// ✅ Integer
"answer_value": 1

// ✅ Probability (0-1)
"answer_value": 0.87

// ✅ Percentage (0-100)
"answer_value": 87.5

// ✅ Negative numbers
"answer_value": -15.2

// ❌ Invalid (string)
"answer_value": "123.45"

// ❌ Invalid (boolean)
"answer_value": true

// ❌ Invalid (array)
"answer_value": [1, 2, 3]

// ❌ Invalid (object)
"answer_value": {"prediction": 123}
```

**Use Cases by Model Type:**

| Model Type                | Example Value | Description             |
| ------------------------- | ------------- | ----------------------- |
| **Binary Classification** | `0` or `1`    | Class label             |
| **Probability Score**     | `0.87`        | Confidence (0-1)        |
| **Regression**            | `2450.75`     | Predicted numeric value |
| **Multi-class (Single)**  | `3`           | Class index             |
| **Ranking Score**         | `87.5`        | Relative score          |

**Important Notes:**

* For multi-class classification, return a single class (highest probability)
* For confidence scores, use 0-1 range (not percentages)
* For currency, return raw numbers without formatting (use 2450.75, not "$2,450.75")
* For percentages, decide on 0-1 or 0-100 and document clearly

#### 3. `asset_id` (Optional)

**Type:** String or null\
**Purpose:** Identifier for tracking and logging

```json
// ✅ With asset_id (if provided in request)
"asset_id": "abc-123-def-456"

// ✅ Without asset_id
"asset_id": null
```

**How to Handle:**

```python
# Extract from request header
asset_id = request.headers.get('X-Asset-ID')

# Return in response
return {
    'timestamp': timestamp,
    'answer_value': prediction,
    'asset_id': asset_id  # Will be None if header not present
}
```

**When to Use:**

* Echo back the X-Asset-ID header value if provided
* Set to null if no asset ID in request
* Optionally use for internal logging/tracking

***

## Complete Examples by Model Type

### Binary Classification

**Model:** Fraud Detection\
**Prediction:** Transaction is fraudulent (1) or legitimate (0)

```json
{
  "timestamp": "2026-01-30T19:30:00.000000+00:00",
  "answer_value": 1,
  "asset_id": "fraud-check-tx-12345"
}
```

### Probability Score

**Model:** Customer Churn Prediction\
**Prediction:** 87% probability of churn

```json
{
  "timestamp": "2026-01-30T19:30:00.000000+00:00",
  "answer_value": 0.87,
  "asset_id": "churn-customer-789"
}
```

### Regression

**Model:** House Price Prediction\
**Prediction:** $450,000

```json
{
  "timestamp": "2026-01-30T19:30:00.000000+00:00",
  "answer_value": 450000.00,
  "asset_id": "property-valuation-456"
}
```

### Multi-class Classification

**Model:** Sentiment Analysis\
**Prediction:** Neutral (class 1, where 0=negative, 1=neutral, 2=positive)

```json
{
  "timestamp": "2026-01-30T19:30:00.000000+00:00",
  "answer_value": 1,
  "asset_id": "sentiment-text-abc"
}
```

### Ranking/Scoring

**Model:** Lead Qualification\
**Prediction:** Lead score of 87.5 out of 100

```json
{
  "timestamp": "2026-01-30T19:30:00.000000+00:00",
  "answer_value": 87.5,
  "asset_id": "lead-score-contact-999"
}
```

***

## Error Response Format

While Spartera handles most errors, your API should return helpful error messages:

### Standard Error Response

```json
{
  "error": "Missing required parameter: age",
  "details": "The 'age' field is required for prediction",
  "error_code": "MISSING_PARAMETER"
}
```

### Error Response Fields

| Field        | Type   | Required    | Description           |
| ------------ | ------ | ----------- | --------------------- |
| `error`      | String | ✅ Yes       | Short error message   |
| `details`    | String | Recommended | Detailed explanation  |
| `error_code` | String | Optional    | Machine-readable code |

### Common Error Responses

```json
// Missing Parameter
{
  "error": "Missing required fields",
  "details": "Fields missing: age, income",
  "error_code": "MISSING_FIELDS"
}

// Invalid Value
{
  "error": "Invalid parameter value",
  "details": "Age must be between 18 and 100, got: 150",
  "error_code": "INVALID_VALUE"
}

// Model Failure
{
  "error": "Model prediction failed",
  "details": "Internal model error. Please try again.",
  "error_code": "MODEL_ERROR"
}

// Rate Limit
{
  "error": "Rate limit exceeded",
  "details": "Maximum 100 requests per minute. Try again in 30 seconds.",
  "error_code": "RATE_LIMIT_EXCEEDED"
}
```

***

## Implementation Examples

### Python (Flask)

```python
from flask import Flask, request, jsonify
from datetime import datetime, timezone

app = Flask(__name__)

@app.route('/predict', methods=['POST'])
def predict():
    try:
        # Get input
        data = request.json
        
        # Validate (your logic)
        if 'age' not in data:
            return jsonify({
                'error': 'Missing required parameter: age'
            }), 400
        
        # Make prediction (your model)
        prediction = your_model.predict(data)
        
        # Extract asset_id
        asset_id = request.headers.get('X-Asset-ID')
        
        # Return Spartera format
        return jsonify({
            'timestamp': datetime.now(timezone.utc).isoformat(),
            'answer_value': float(prediction),
            'asset_id': asset_id
        }), 200
        
    except Exception as e:
        return jsonify({
            'error': str(e)
        }), 500
```

### Node.js (Express)

```javascript
const express = require('express');
const app = express();

app.use(express.json());

app.post('/predict', async (req, res) => {
    try {
        // Get input
        const data = req.body;
        
        // Validate
        if (!data.age) {
            return res.status(400).json({
                error: 'Missing required parameter: age'
            });
        }
        
        // Make prediction
        const prediction = await yourModel.predict(data);
        
        // Extract asset_id
        const assetId = req.headers['x-asset-id'] || null;
        
        // Return Spartera format
        res.json({
            timestamp: new Date().toISOString(),
            answer_value: prediction,
            asset_id: assetId
        });
        
    } catch (error) {
        res.status(500).json({
            error: error.message
        });
    }
});
```

### Go

```go
package main

import (
    "encoding/json"
    "net/http"
    "time"
)

type PredictionRequest struct {
    Age    int     `json:"age"`
    Income float64 `json:"income"`
}

type PredictionResponse struct {
    Timestamp   string  `json:"timestamp"`
    AnswerValue float64 `json:"answer_value"`
    AssetID     string  `json:"asset_id,omitempty"`
}

func predictHandler(w http.ResponseWriter, r *http.Request) {
    // Parse request
    var req PredictionRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, "Invalid request", http.StatusBadRequest)
        return
    }
    
    // Make prediction
    prediction := yourModel.Predict(req)
    
    // Get asset_id
    assetID := r.Header.Get("X-Asset-ID")
    
    // Return response
    resp := PredictionResponse{
        Timestamp:   time.Now().UTC().Format(time.RFC3339Nano),
        AnswerValue: prediction,
        AssetID:     assetID,
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(resp)
}
```

***

## Validation Checklist

Before connecting to Spartera, verify your response:

* [ ] Returns valid JSON
* [ ] Contains all three required fields
* [ ] `timestamp` is ISO-8601 format with timezone
* [ ] `answer_value` is a number (not string)
* [ ] `asset_id` is string or null (not missing)
* [ ] HTTP status code is 200 for success
* [ ] Error responses use appropriate status codes (400, 500, etc.)
* [ ] Response headers include `Content-Type: application/json`

***

## Common Mistakes

### ❌ Returning String Instead of Number

```json
// Wrong
{
  "timestamp": "2026-01-30T19:30:00Z",
  "answer_value": "123.45",  // String!
  "asset_id": null
}

// Correct
{
  "timestamp": "2026-01-30T19:30:00Z",
  "answer_value": 123.45,  // Number
  "asset_id": null
}
```

### ❌ Missing Timezone

```json
// Wrong
{
  "timestamp": "2026-01-30T19:30:00",  // No timezone!
  "answer_value": 123.45,
  "asset_id": null
}

// Correct
{
  "timestamp": "2026-01-30T19:30:00+00:00",  // Has timezone
  "answer_value": 123.45,
  "asset_id": null
}
```

### ❌ Omitting asset\_id Field

```json
// Wrong
{
  "timestamp": "2026-01-30T19:30:00Z",
  "answer_value": 123.45
  // Missing asset_id field entirely!
}

// Correct
{
  "timestamp": "2026-01-30T19:30:00Z",
  "answer_value": 123.45,
  "asset_id": null  // Include even if null
}
```

### ❌ Extra Fields

```json
// Acceptable but not necessary
{
  "timestamp": "2026-01-30T19:30:00Z",
  "answer_value": 123.45,
  "asset_id": null,
  "confidence": 0.95,  // Extra field (ignored by Spartera)
  "model_version": "v2.1"  // Extra field (ignored by Spartera)
}
```

**Note:** Extra fields are ignored but won't cause errors. However, keep responses minimal for better performance.

***

## Testing Your Response

### Manual Test with cURL

```bash
curl -X POST https://your-api.com/predict \
  -H "X-API-Key: your-key" \
  -H "Content-Type: application/json" \
  -d '{"age": 35, "income": 75000}' \
  | python -m json.tool
```

Expected output:

```json
{
  "timestamp": "2026-01-30T19:30:00.123456+00:00",
  "answer_value": 0.87,
  "asset_id": null
}
```

### Automated Validation

```python
import requests
import json
from datetime import datetime

def validate_response(url, api_key, payload):
    headers = {
        'X-API-Key': api_key,
        'Content-Type': 'application/json'
    }
    
    response = requests.post(url, json=payload, headers=headers)
    
    # Check status code
    assert response.status_code == 200, f"Expected 200, got {response.status_code}"
    
    # Parse JSON
    data = response.json()
    
    # Check required fields
    assert 'timestamp' in data, "Missing timestamp"
    assert 'answer_value' in data, "Missing answer_value"
    assert 'asset_id' in data, "Missing asset_id"
    
    # Check types
    assert isinstance(data['timestamp'], str), "timestamp must be string"
    assert isinstance(data['answer_value'], (int, float)), "answer_value must be number"
    
    # Validate timestamp format
    datetime.fromisoformat(data['timestamp'].replace('Z', '+00:00'))
    
    print("✅ Response format valid!")
    return data

# Test
result = validate_response(
    'https://your-api.com/predict',
    'your-key',
    {'age': 35, 'income': 75000}
)
```

***

**Next Steps:**

* Implement the response format in your API
* Test with the validation script above
* Read [Connecting Your API](./connecting-api.md) to register your endpoint
* Learn about [Function ID Routing](./function_id-routing.md) for advanced use cases