Overview
Moo-AI uses a REST-style JSON API. Send requests over HTTPS, authenticate with a moo_sk_... secret key, and receive JSON responses.
Authentication
Protected endpoints require a Moo-AI API key in the HTTP Authorization header.
Authorization: Bearer moo_sk_YOUR_API_KEY
For browser-based websites, call Moo-AI from your own server-side PHP/Node/Ruby/etc. endpoint. Your browser should call your backend, and your backend should attach the Moo-AI key.
Models & reasoning levels
| Model | Use | Plan |
|---|---|---|
moo-mini | Fast general requests | Free, Pro, Business |
moo-core | General production workloads | Pro, Business |
moo-reason | Higher-effort reasoning | Pro, Business |
| reasoning_effort | Availability |
|---|---|
instant | Free, Pro, Business |
standard | Free, Pro, Business |
deep | Pro, Business |
Endpoints
| Method | Endpoint | Authentication | Description |
|---|---|---|---|
| GET | /health | No | API health status |
| GET | /v1/plans | No | Available plans and limits |
| GET | /v1/models | Yes | Models available to the account |
| GET | /v1/account | Yes | Current account and plan |
| GET | /v1/usage | Yes | Current usage |
| POST | /v1/chat/completions | Yes | Generate a Moo-AI response |
| POST | /v1/billing/checkout | Yes | Create Pro checkout session |
| POST | /v1/billing/portal | Yes | Open billing management |
Chat completions
POSThttps://moozonian.com/moo-ai/v1/chat/completions
Request body
{
"model": "moo-mini",
"reasoning_effort": "standard",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Explain how solar panels work."
}
],
"max_tokens": 800,
"temperature": 0.7
}| Field | Type | Required | Description |
|---|---|---|---|
model | string | No | Defaults to moo-mini. |
reasoning_effort | string | No | instant, standard, or deep. |
messages | array | Yes | Conversation messages. |
max_tokens | integer | No | Maximum generated output tokens, bounded by plan limits. |
temperature | number | No | Sampling temperature from 0 to 2. |
Response format
{
"id": "chatcmpl_...",
"object": "chat.completion",
"created": 1788750000,
"model": "moo-mini",
"reasoning_effort": "standard",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 42,
"completion_tokens": 116,
"total_tokens": 158
},
"moo": {
"plan": "free",
"latency_ms": 842,
"backend": "local"
}
}The generated assistant text is located at choices[0].message.content.
Programming language examples
Replace moo_sk_YOUR_API_KEY with a key generated from your Moo-AI developer dashboard.
PHP
<?php
$apiKey = getenv('MOO_AI_API_KEY');
$payload = [
'model' => 'moo-mini',
'reasoning_effort' => 'standard',
'messages' => [
['role' => 'user', 'content' => 'Hello from PHP']
]
];
$ch = curl_init('https://moozonian.com/moo-ai/v1/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 120
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($response === false) {
throw new RuntimeException(curl_error($ch));
}
curl_close($ch);
$data = json_decode($response, true);
if ($status >= 400) {
throw new RuntimeException($data['error']['message'] ?? 'Moo-AI request failed');
}
echo $data['choices'][0]['message']['content'];JavaScript / Node.js
Use this server-side in Node.js 18+ so the secret key remains private.
const response = await fetch('https://moozonian.com/moo-ai/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MOO_AI_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'moo-mini',
reasoning_effort: 'standard',
messages: [
{ role: 'user', content: 'Hello from Node.js' }
]
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data?.error?.message || 'Moo-AI request failed');
}
console.log(data.choices[0].message.content);jQuery
Do not put moo_sk_... in jQuery. Have jQuery call your own server endpoint, and let that server endpoint call Moo-AI.
$.ajax({
url: '/api/ask-moo.php',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
message: 'Hello from my website'
}),
success: function (data) {
$('#answer').text(data.answer);
},
error: function () {
$('#answer').text('Moo-AI request failed');
}
});Your /api/ask-moo.php server route should use the PHP example above and inject the secret key from an environment variable.
HTML5
HTML5 itself cannot securely store a secret API key. Submit to your own backend endpoint.
<form id="moo-form">
<textarea id="prompt" required></textarea>
<button type="submit">Ask Moo-AI</button>
</form>
<pre id="answer"></pre>
<script>
document.getElementById('moo-form').addEventListener('submit', async (event) => {
event.preventDefault();
const response = await fetch('/api/ask-moo.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
message: document.getElementById('prompt').value
})
});
const data = await response.json();
document.getElementById('answer').textContent = data.answer;
});
</script>Ruby
require 'net/http'
require 'json'
require 'uri'
uri = URI('https://moozonian.com/moo-ai/v1/chat/completions')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{ENV.fetch('MOO_AI_API_KEY')}"
request['Content-Type'] = 'application/json'
request.body = {
model: 'moo-mini',
reasoning_effort: 'standard',
messages: [
{ role: 'user', content: 'Hello from Ruby' }
]
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
data = JSON.parse(response.body)
raise(data.dig('error', 'message') || 'Moo-AI request failed') unless response.is_a?(Net::HTTPSuccess)
puts data.dig('choices', 0, 'message', 'content')C++
This example uses libcurl and nlohmann/json.
#include <curl/curl.h>
#include <nlohmann/json.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
using json = nlohmann::json;
size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp) {
static_cast<std::string*>(userp)->append(
static_cast<char*>(contents), size * nmemb
);
return size * nmemb;
}
int main() {
const char* key = std::getenv("MOO_AI_API_KEY");
if (!key) return 1;
json body = {
{"model", "moo-mini"},
{"reasoning_effort", "standard"},
{"messages", {{{"role", "user"}, {"content", "Hello from C++"}}}}
};
CURL* curl = curl_easy_init();
std::string response;
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + std::string(key)).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, "https://moozonian.com/moo-ai/v1/chat/completions");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.dump().c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode result = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
if (result != CURLE_OK) return 1;
auto data = json::parse(response);
std::cout << data["choices"][0]["message"]["content"] << "\n";
}ASP.NET / C#
using System.Net.Http.Headers;
using System.Net.Http.Json;
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"Bearer",
Environment.GetEnvironmentVariable("MOO_AI_API_KEY")
);
var payload = new
{
model = "moo-mini",
reasoning_effort = "standard",
messages = new[]
{
new { role = "user", content = "Hello from ASP.NET" }
}
};
var response = await http.PostAsJsonAsync(
"https://moozonian.com/moo-ai/v1/chat/completions",
payload
);
var data = await response.Content.ReadFromJsonAsync<MooResponse>();
response.EnsureSuccessStatusCode();
Console.WriteLine(data!.choices[0].message.content);
public record MooResponse(Choice[] choices);
public record Choice(Message message);
public record Message(string role, string content);Python
import os
import requests
response = requests.post(
"https://moozonian.com/moo-ai/v1/chat/completions",
headers={
"Authorization": f"Bearer {os.environ['MOO_AI_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": "moo-mini",
"reasoning_effort": "standard",
"messages": [
{"role": "user", "content": "Hello from Python"}
],
},
timeout=120,
)
response.raise_for_status()
data = response.json()
print(data["choices"][0]["message"]["content"])Java
import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class MooAIExample {
public static void main(String[] args) throws Exception {
String key = System.getenv("MOO_AI_API_KEY");
String json = """
{
"model":"moo-mini",
"reasoning_effort":"standard",
"messages":[
{"role":"user","content":"Hello from Java"}
]
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://moozonian.com/moo-ai/v1/chat/completions"))
.timeout(Duration.ofSeconds(120))
.header("Authorization", "Bearer " + key)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response =
HttpClient.newHttpClient().send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
func main() {
payload := map[string]any{
"model": "moo-mini",
"reasoning_effort": "standard",
"messages": []map[string]string{
{"role": "user", "content": "Hello from Go"},
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(
"POST",
"https://moozonian.com/moo-ai/v1/chat/completions",
bytes.NewReader(body),
)
req.Header.Set("Authorization", "Bearer "+os.Getenv("MOO_AI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
data, _ := io.ReadAll(res.Body)
fmt.Println(string(data))
}Swift
import Foundation
let apiKey = ProcessInfo.processInfo.environment["MOO_AI_API_KEY"]!
let url = URL(string: "https://moozonian.com/moo-ai/v1/chat/completions")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
"model": "moo-mini",
"reasoning_effort": "standard",
"messages": [
["role": "user", "content": "Hello from Swift"]
]
]
request.httpBody = try JSONSerialization.data(withJSONObject: payload)
let (data, response) = try await URLSession.shared.data(for: request)
if let http = response as? HTTPURLResponse, !(200...299).contains(http.statusCode) {
throw URLError(.badServerResponse)
}
print(String(data: data, encoding: .utf8)!)Kotlin
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
fun main() {
val apiKey = System.getenv("MOO_AI_API_KEY")
val body = """
{
"model":"moo-mini",
"reasoning_effort":"standard",
"messages":[
{"role":"user","content":"Hello from Kotlin"}
]
}
""".trimIndent()
val request = HttpRequest.newBuilder()
.uri(URI.create("https://moozonian.com/moo-ai/v1/chat/completions"))
.header("Authorization", "Bearer $apiKey")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build()
val response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString())
println(response.body())
}Rust
use reqwest::Client;
use serde_json::json;
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let response = client
.post("https://moozonian.com/moo-ai/v1/chat/completions")
.bearer_auth(env::var("MOO_AI_API_KEY")?)
.json(&json!({
"model": "moo-mini",
"reasoning_effort": "standard",
"messages": [
{"role": "user", "content": "Hello from Rust"}
]
}))
.send()
.await?
.error_for_status()?;
let data: serde_json::Value = response.json().await?;
println!("{}", data["choices"][0]["message"]["content"]);
Ok(())
}Dart / Flutter
For production mobile apps, call Moo-AI from your own authenticated backend rather than embedding the secret API key in the shipped application.
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
Future<void> main() async {
final key = Platform.environment['MOO_AI_API_KEY']!;
final response = await http.post(
Uri.parse('https://moozonian.com/moo-ai/v1/chat/completions'),
headers: {
'Authorization': 'Bearer $key',
'Content-Type': 'application/json',
},
body: jsonEncode({
'model': 'moo-mini',
'reasoning_effort': 'standard',
'messages': [
{'role': 'user', 'content': 'Hello from Dart'}
]
}),
);
if (response.statusCode >= 400) {
throw Exception(response.body);
}
final data = jsonDecode(response.body);
print(data['choices'][0]['message']['content']);
}Bash / cURL
export MOO_AI_API_KEY="moo_sk_YOUR_API_KEY"
curl -X POST "https://moozonian.com/moo-ai/v1/chat/completions" \
-H "Authorization: Bearer $MOO_AI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model":"moo-mini",
"reasoning_effort":"standard",
"messages":[
{"role":"user","content":"Hello from Bash"}
]
}'Error handling
| Status | Meaning | Typical cause |
|---|---|---|
| 400 | Bad request | Invalid JSON or missing messages. |
| 401 | Authentication error | Missing, invalid, or revoked API key. |
| 403 | Access error | Model or reasoning level not included in the current plan. |
| 404 | Not found | Unknown API route. |
| 429 | Rate/quota limit | Minute, daily, or monthly allowance exceeded. |
| 502 | Backend error | The local Moo-AI inference backend is unavailable. |
| 503 | Service unavailable | Database or service health problem. |
{
"error": {
"message": "Invalid or revoked Moo-AI API key.",
"type": "authentication_error"
}
}Security guidance
- Store keys in environment variables or a secret manager.
- Never commit
moo_sk_...keys to Git. - Never embed a secret key in HTML, public JavaScript, jQuery, or a distributed mobile/desktop app.
- For browser and mobile apps, use your own authenticated backend as a proxy to Moo-AI.
- Revoke a key immediately from the dashboard if it is exposed.
- Create separate keys for separate servers or applications so they can be revoked independently.