> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# GPT-6 Luna API

> 使用准确模型 ID 调用 GPT-6 Luna，并读取原生响应。

调用 GPT-6 Luna 时使用 `model: "gpt-6-luna"`。下面通过 OpenAI Chat Completions 发送同步请求。

这些代码用于演示接入方式，不是已执行的模型输出。将密钥保存在服务端环境变量 `BEATAPI_API_KEY` 中；cURL 里的 `<BEATAPI_API_KEY>` 是占位符，需要替换为自己的密钥。不要把密钥放进浏览器代码。

## 发送请求

`POST https://api.beatapi.io/v1/chat/completions`

在服务端项目中安装 `openai`。

```typescript
import OpenAI from "openai";

const apiKey = process.env.BEATAPI_API_KEY;
if (!apiKey) throw new Error("Set BEATAPI_API_KEY in your server environment.");

const client = new OpenAI({
  apiKey,
  baseURL: "https://api.beatapi.io/v1",
});

const completion = await client.chat.completions.create({
  model: "gpt-6-luna",
  messages: [{ role: "user", content: "Classify the following support ticket using exactly one label: account_access, billing, or product_defect. Return the label and a brief reason. Ticket: I reset my password, but the new password still does not let me sign in." }],
});

const choice = completion.choices[0];
if (!choice || choice.finish_reason !== "stop") {
  throw new Error(`Handle the finish reason before accepting the result: ${choice?.finish_reason}`);
}
const text = choice.message.content;
if (typeof text !== "string" || !text.trim()) {
  throw new Error("The response contains no text answer.");
}
console.log(text);
console.log({ id: completion.id, model: completion.model, usage: completion.usage });
```

### cURL

```bash
curl --request POST \
  --url https://api.beatapi.io/v1/chat/completions \
  --header 'Authorization: Bearer <BEATAPI_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "gpt-6-luna",
  "messages": [
    {
      "role": "user",
      "content": "Classify the following support ticket using exactly one label: account_access, billing, or product_defect. Return the label and a brief reason. Ticket: I reset my password, but the new password still does not let me sign in."
    }
  ]
}'
```

## 读取并校验结果

从 `choices[0].message.content` 读取回答，再检查真实的 `finish_reason` 和 `usage`。本例仅接受 `stop`；被截断的回答或工具请求需要由应用另行处理。用回答分派工单前，还要校验返回标签是否属于允许的标签集合。

HTTP 200 本身不能证明回答满足任务要求，应用还需要校验内容。这类文本请求直接返回结果，不要用 `/v1/tasks` 轮询。

通过 `GET /v1/models` 核对当前账户可用的模型 ID。这个最小示例不承诺额外的推理、采样、缓存控制或托管工具参数。