Skip to content
RoxyAPI
Get API Key

Astrology function calling with OpenAI, Claude, and Gemini

Wire RoxyAPI endpoints into OpenAI, Anthropic, or Gemini as function tools. Time to ship: 15 minutes.

Function calling is the manual, control-heavy path for letting an LLM call RoxyAPI. You hand-define tool schemas, route tool calls to the right endpoint, and ship the results back. MCP does this automatically, which is why MCP is the default. Use function calling when your model does not support MCP, when you need tight control over which tools are exposed, or when you are gluing RoxyAPI into an existing agent framework.

You probably want MCP instead

If you are on Claude Code, Cursor, Antigravity, Claude Desktop, or any MCP-compatible client, skip this guide. The MCP setup auto-discovers all 261+ RoxyAPI endpoints and requires zero tool schemas. Function calling is the fallback when MCP is not available.

If you are an AI coding agent reading this guide to write function-calling code, also fetch the site-level AGENTS.md playbook at https://roxyapi.com/AGENTS.md for tight per-endpoint body shapes you will encode as tool schemas.

Function callingMCP
SetupYou write tool schemas, or auto-generate from OpenAPIZero config, agents discover tools at runtime
ControlYou pick exactly which tools to exposeAll tools available
CompatibilityAny model with tool-use supportRequires MCP-compatible client
Best forProduction apps with tight controlPrototyping, AI assistants, agent frameworks

What you can build with this

  • AI chatbots that call RoxyAPI from OpenAI, Anthropic, or Gemini
  • Agents where only specific RoxyAPI endpoints are exposed (least-privilege tool sets)
  • Serverless functions that route a user question to the right RoxyAPI call
  • Custom agent frameworks (LangChain, LlamaIndex, AG2) with RoxyAPI as a tool
  • Multi-provider apps that keep the same tool definitions across LLMs

What you need

  1. A RoxyAPI key. Get your API key.
  2. An LLM key from Anthropic, OpenAI, or Google AI Studio.

Step 1, define your tools

Each tool maps to one RoxyAPI endpoint. Define only the ones your app uses.

javascript
const tools = [
  {
    name: 'get_daily_horoscope',
    description: 'Get the daily horoscope for a zodiac sign',
    parameters: {
      type: 'object',
      properties: {
        sign: { type: 'string', enum: ['aries','taurus','gemini','cancer','leo','virgo','libra','scorpio','sagittarius','capricorn','aquarius','pisces'] }
      },
      required: ['sign'],
    },
  },
  {
    name: 'draw_tarot_cards',
    description: 'Draw tarot cards for a reading',
    parameters: {
      type: 'object',
      properties: {
        count: { type: 'number', description: 'Number of cards (1-78)' }
      },
      required: ['count'],
    },
  },
  {
    name: 'get_birth_chart',
    description: 'Generate a natal birth chart with planets, houses, and aspects',
    parameters: {
      type: 'object',
      properties: {
        date: { type: 'string', description: 'YYYY-MM-DD' },
        time: { type: 'string', description: 'HH:MM:SS (24h)' },
        latitude: { type: 'number' },
        longitude: { type: 'number' },
        timezone: { type: 'string', description: 'IANA id like America/New_York or decimal offset' },
      },
      required: ['date', 'time', 'latitude', 'longitude', 'timezone'],
    },
  },
];

Step 2, execute tool calls

When the model returns a tool call, route it to the right RoxyAPI endpoint. Pick your preferred call style.

bash
# For reference. The tool-call executor below uses fetch, but this is the underlying shape.
curl "https://roxyapi.com/api/v2/astrology/horoscope/aries/daily" \
  -H "X-API-Key: $ROXY_API_KEY"

curl -X POST https://roxyapi.com/api/v2/tarot/draw \
  -H "X-API-Key: $ROXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"count": 3}'

If a request fails, the response body is { error, code, doc_url } so your agent can report the issue to the user.

Step 3, wire it into your LLM

Same pattern everywhere. Send messages with tools, check for tool calls, execute, send the result back.

OpenAI

javascript
import OpenAI from 'openai';
const openai = new OpenAI();

const openaiTools = tools.map(t => ({ type: 'function', ...t }));
const input = [{ role: 'user', content: 'What is my horoscope for Aries today?' }];

let response = await openai.responses.create({ model: 'gpt-6.1-sol', input, tools: openaiTools });

const calls = response.output.filter(item => item.type === 'function_call');
if (calls.length) {
  input.push(...response.output);
  for (const call of calls) {
    const result = await executeTool(call.name, JSON.parse(call.arguments));
    input.push({ type: 'function_call_output', call_id: call.call_id, output: JSON.stringify(result) });
  }
  response = await openai.responses.create({ model: 'gpt-6.1-sol', input, tools: openaiTools });
}
console.log(response.output_text);

Anthropic

javascript
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic();

const anthropicTools = tools.map(t => ({ name: t.name, description: t.description, input_schema: t.parameters }));
const messages = [{ role: 'user', content: 'Draw me 3 tarot cards' }];

const response = await anthropic.messages.create({
  model: 'claude-sonnet-5-5',
  max_tokens: 1024,
  messages,
  tools: anthropicTools,
});

const toolUse = response.content.find(block => block.type === 'tool_use');
if (toolUse) {
  const result = await executeTool(toolUse.name, toolUse.input);
  const followUp = await anthropic.messages.create({
    model: 'claude-sonnet-5-5',
    max_tokens: 1024,
    messages: [
      ...messages,
      { role: 'assistant', content: response.content },
      { role: 'user', content: [{ type: 'tool_result', tool_use_id: toolUse.id, content: JSON.stringify(result) }] },
    ],
    tools: anthropicTools,
  });
  console.log(followUp.content.find(block => block.type === 'text')?.text);
}

Gemini

javascript
import { GoogleGenAI } from '@google/genai';
const genai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const geminiTools = [{
  functionDeclarations: tools.map(t => ({ name: t.name, description: t.description, parametersJsonSchema: t.parameters })),
}];

const contents = [{ role: 'user', parts: [{ text: 'Draw me 3 tarot cards' }] }];
const response = await genai.models.generateContent({
  model: 'gemini-flash-latest',
  contents,
  config: { tools: geminiTools },
});

const call = response.functionCalls?.[0];
if (call) {
  const result = await executeTool(call.name, call.args);
  const followUp = await genai.models.generateContent({
    model: 'gemini-flash-latest',
    contents: [
      ...contents,
      response.candidates[0].content,
      { role: 'user', parts: [{ functionResponse: { id: call.id, name: call.name, response: result } }] },
    ],
    config: { tools: geminiTools },
  });
  console.log(followUp.text);
}

Auto-generate tool definitions from OpenAPI

Every RoxyAPI domain also publishes its own OpenAPI spec, which keeps a generated tool list to the one domain you need. Parse it to generate tool schemas instead of writing them by hand. To read a contract rather than import one, query the combined spec with the jq recipe in AGENTS.md.

bash
curl https://roxyapi.com/api/v2/astrology/openapi.json > astrology.openapi.json

Available domains: astrology, vedic-astrology, forecast, human-design, chinese-astrology, feng-shui, mesoamerican-astrology, vastu, numerology, kabbalah, tarot, biorhythm, ayurveda, iching, crystals, dreams, angel-numbers, location. Use openapi-typescript or any OpenAPI-to-tool-schema generator.

Gotchas

  • One JSON Schema, three wrappers. OpenAI takes { type: 'function', name, description, parameters }. Anthropic renames parameters to input_schema. Gemini takes it as parametersJsonSchema inside functionDeclarations[].
  • OpenAI: use the Responses API. Tool calls arrive as function_call items in response.output; answer each with a function_call_output carrying the same call_id.
  • Timezone accepts both shapes. IANA string ("America/New_York") or decimal (-5). Prefer IANA for DST correctness.
  • Geocode before chart endpoints. Natal chart, kundli, panchang, synastry need latitude, longitude, timezone. Add a search_cities tool and tell the model to call it first.
  • Tell the model to call a tool, not to guess. System prompt: "For horoscope, birth chart, human design, forecast, or any spiritual topic, always call a tool. Never answer from training data."

What to build next