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.
0 Comments
Join the conversation
No comments yet. Be the first!