MTD API — AI Chat Endpoint

Base URL: https://api.motadev.xyz
Endpoint: POST /api/chat
Cost: 1 credit per request

Build a fully conversational AI assistant into your app using the MTD API chat endpoint. It maintains message history per user session, so your users can have back-and-forth conversations — not just one-shot prompts.


Prerequisites

  • An active MTD API account → api.motadev.xyz
  • Your API key from the Dashboard → Settings page
  • At least 1 credit in your account

Required Headers

Every request to /api/chat must include these three headers:

Header Description
X-API-KEY Your MTD API key (e.g. mtd_key1234567890ABCD)
User-Agent Identifies your app (any non-empty string works)
Referer Your app's base URL (e.g. https://yourapp.com)

Missing any of these will result in a 400 or 401 error and an abuse log against your IP.


Request Body

Send a JSON body with these fields:

{
  "user_id": "unique-user-identifier",
  "messages": {
    "system": "You are a helpful customer support agent for Acme Corp.",
    "user": "What is your return policy?"
  }
}
Field Type Required Description
user_id string A unique ID for the end user. Used to track conversation history. Can be a UUID, username, phone number — anything that identifies the user in your system.
messages.system string Sets the AI's persona/behaviour. Defaults to "You are a helpful assistant."
messages.user string The user's message in this turn.

How conversation history works: The API stores the last 20 messages per (your_api_key + user_id) pair. Every request automatically loads that history, so the AI remembers what was said earlier. You do not need to send previous messages yourself.


Response

A successful 200 response looks like:

{
  "success": true,
  "message": "Request completed",
  "reply": "Our return policy allows returns within 30 days of purchase...",
  "credits_remaining": 49,
  "tokens_used": 312
}
Field Description
reply The AI's response text
credits_remaining How many credits you have left after this call
tokens_used Total tokens consumed (input + output)

Error Responses

Status Meaning
400 Bad request — missing or malformed JSON body
401 Invalid or missing API key
402 Insufficient credits
429 Rate limited — max 30 requests per minute
503 AI backend temporarily unavailable

Code Examples

Python (requests)

import requests

API_KEY = "mtd_key1234567890ABCD"
BASE_URL = "https://api.motadev.xyz"

HEADERS = {
    "X-API-KEY": API_KEY,
    "User-Agent": "MyApp/1.0",
    "Referer": "https://myapp.com",
    "Content-Type": "application/json",
}

def chat(user_id: str, user_message: str, system_prompt: str = None):
    payload = {
        "user_id": user_id,
        "messages": {
            "user": user_message,
        }
    }
    if system_prompt:
        payload["messages"]["system"] = system_prompt

    response = requests.post(
        f"{BASE_URL}/api/chat",
        json=payload,
        headers=HEADERS,
        timeout=30,
    )
    data = response.json()

    if not data.get("success"):
        raise Exception(f"API Error: {data.get('message')}")

    return data["reply"], data["credits_remaining"]


# --- Example 1: Simple one-turn chat ---
reply, credits = chat(
    user_id="user_001",
    user_message="What is the capital of France?",
)
print(f"AI: {reply}")
print(f"Credits left: {credits}")


# --- Example 2: Persistent multi-turn conversation with a custom persona ---
SESSION_USER = "user_002"
SYSTEM = "You are a terse Linux sysadmin. Give short, direct answers with code where needed."

# Turn 1
reply, _ = chat(SESSION_USER, "How do I check disk usage?", SYSTEM)
print(f"Turn 1 — AI: {reply}")

# Turn 2 — the AI remembers it already explained disk usage
reply, _ = chat(SESSION_USER, "And how do I find the biggest files specifically?", SYSTEM)
print(f"Turn 2 — AI: {reply}")

Expected output (Example 1):

AI: The capital of France is Paris.
Credits left: 49

Expected output (Example 2):

Turn 1 — AI: df -h
Turn 2 — AI: du -ah / | sort -rh | head -20

Node.js

const axios = require("axios");

const API_KEY = "mtd_key1234567890ABCD";
const BASE_URL = "https://api.motadev.xyz";

const headers = {
  "X-API-KEY": API_KEY,
  "User-Agent": "MyNodeApp/1.0",
  "Referer": "https://mynodeapp.com",
  "Content-Type": "application/json",
};

async function chat(userId, userMessage, systemPrompt = "You are a helpful assistant.") {
  const response = await axios.post(
    `${BASE_URL}/api/chat`,
    {
      user_id: userId,
      messages: {
        system: systemPrompt,
        user: userMessage,
      },
    },
    { headers, timeout: 30000 }
  );

  const data = response.data;
  if (!data.success) throw new Error(`API Error: ${data.message}`);
  return { reply: data.reply, credits: data.credits_remaining };
}

// --- Example 1: Customer support bot ---
(async () => {
  const { reply, credits } = await chat(
    "customer_456",
    "I haven't received my order yet, it's been 2 weeks.",
    "You are a polite e-commerce support agent for ShopFast. Always apologise first."
  );
  console.log("AI:", reply);
  console.log("Credits remaining:", credits);
})();


// --- Example 2: Coding assistant with follow-up ---
(async () => {
  const userId = "dev_789";
  const sysPrompt = "You are a senior JavaScript developer. Be concise and always show code.";

  const turn1 = await chat(userId, "How do I debounce a function?", sysPrompt);
  console.log("Turn 1:", turn1.reply);

  // Follow-up — no need to resend the previous context, API handles it
  const turn2 = await chat(userId, "Now show me how to cancel it early.", sysPrompt);
  console.log("Turn 2:", turn2.reply);
})();

Rust

use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::collections::HashMap;

const API_KEY: &str = "mtd_key1234567890ABCD";
const BASE_URL: &str = "https://api.motadev.xyz";

#[derive(Debug, Deserialize)]
struct ChatResponse {
    success: bool,
    message: String,
    reply: Option<String>,
    credits_remaining: Option<i64>,
    tokens_used: Option<i64>,
}

fn chat(
    client: &Client,
    user_id: &str,
    user_message: &str,
    system_prompt: &str,
) -> Result<ChatResponse, Box<dyn std::error::Error>> {
    let body = json!({
        "user_id": user_id,
        "messages": {
            "system": system_prompt,
            "user": user_message,
        }
    });

    let response = client
        .post(format!("{}/api/chat", BASE_URL))
        .header("X-API-KEY", API_KEY)
        .header("User-Agent", "RustApp/1.0")
        .header("Referer", "https://myrustapp.com")
        .header("Content-Type", "application/json")
        .json(&body)
        .send()?;

    let data: ChatResponse = response.json()?;
    Ok(data)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();

    // Example 1: Single question
    let result = chat(
        &client,
        "rust_user_001",
        "Explain ownership in Rust in one sentence.",
        "You are a Rust programming expert.",
    )?;

    if result.success {
        println!("AI: {}", result.reply.unwrap_or_default());
        println!("Credits left: {}", result.credits_remaining.unwrap_or(0));
    } else {
        eprintln!("Error: {}", result.message);
    }

    // Example 2: Follow-up question — the API remembers turn 1
    let follow_up = chat(
        &client,
        "rust_user_001",
        "Give me a quick code example of that.",
        "You are a Rust programming expert.",
    )?;

    if follow_up.success {
        println!("\nFollow-up:\n{}", follow_up.reply.unwrap_or_default());
    }

    Ok(())
}

Tips & Best Practices

Picking a user_id: Use something stable per user — a database ID, UUID, or hashed email. Don't use session tokens that rotate on every login or you'll lose conversation history.

System prompt strategy: Keep it short and specific. Instead of "Be helpful", try "You are a billing support agent for Acme Corp. Only answer questions about invoices, payments, and subscriptions. For anything else, say 'please contact our sales team'."

Resetting a conversation: There's no explicit reset endpoint — just change the user_id to start fresh. A common pattern is user_001_session_20240601.

Rate limits: 30 requests per minute per IP. For high-volume apps, spread requests across multiple API keys or batch non-urgent messages.

Credit monitoring: Always check credits_remaining in the response. When it hits 0, subsequent requests will return 402. Consider building a low-credit alert in your app.