Developer guide
Quickstart
Quickstart
This guide covers everything from issuing a CLEVI API key to sending your first request and receiving a response. One address and one key let you call cip-5.5-im and cip-5.5-mm, and because requests and responses follow the OpenAI Chat Completions format, you only need to change two values in the OpenAI SDK you already use: base_url and api_key. The path for the Anthropic SDK and the embeddings and speech paths are covered in the Make API calls document.
Issuing an API key
Keys are issued on the API Keys page of the CLEVI Cloud console. The same page lets you revoke keys and manage their scope. Follow the steps below to get a key to use in requests.
- Sign in or create an account: https://platform.clevi.net/account/login
- Add a workspace: https://clevi.app/cloud
- Go to https://clevi.app/cloud/keys
- Issue a new key and copy its value.
- Save the copied value in an environment variable.
Replace sk-... in the examples in this guide with the key you issued. If you store it in an environment variable with the command below, you can copy and run the later examples as they are.
export CLEVI_API_KEY="sk-..."Choosing a model
Put one of the names below in the model field of the request body exactly as shown. Both models use the same address and the same request format, and accept text and images as input.
- cip-5.5-im
- cip-5.5-mm
| Model ID | Size | Input limit | Max output | Suited for |
|---|---|---|---|---|
| cip-5.5-im | 360B | 256K | 64K | Tasks with a clear goal and scope. Prioritizes response speed and throughput. |
| cip-5.5-mm | 800B | 512K | 64K | Complex tasks that combine many sources and constraints. Used for long-context analysis and multi-step agents. |
The models your account can actually call are determined by the Playground model list and the GET /models response. The full model list and the calls each model allows are in the Models document; estimated credit deductions are on the Usage page of the console.
POST /api/v2/aiservice/openai/v1/chat/completions
Takes an array of messages and a model name and returns the message generated by the model in the choices array. The full address is https://platform.clevi.net/api/v2/aiservice/openai/v1/chat/completions and the request body is application/json. Authentication uses the Authorization header with the Bearer prefix followed by the key. You can also send the key in the X-API-Key header; if both headers are specified, the X-API-Key value takes precedence.
| Name | Type | Required | Description |
|---|---|---|---|
| model | string | Yes | cip-5.5-im or cip-5.5-mm |
| messages | array | Yes | Array of conversation message objects. At least 1 |
| messages[].role | string | Yes | One of system, user, or assistant |
| messages[].content | string | Yes | Message body |
| stream | boolean | No | If true, the response is delivered in Server-Sent Events chunks |
| max_tokens | integer | No | Maximum number of tokens to generate in the response |
| temperature | number | No | The higher the value, the more likely the same request produces different responses |
curl https://platform.clevi.net/api/v2/aiservice/openai/v1/chat/completions \
-H "Authorization: Bearer $CLEVI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "cip-5.5-im",
"messages": [
{"role": "user", "content": "CLEVI API를 한 문장으로 설명해 줘."}
]
}'import os
import requests
url = "https://platform.clevi.net/api/v2/aiservice/openai/v1/chat/completions"
response = requests.post(
url,
headers={"Authorization": f"Bearer {os.environ['CLEVI_API_KEY']}"},
json={
"model": "cip-5.5-im",
"messages": [{"role": "user", "content": "CLEVI API를 한 문장으로 설명해 줘."}],
},
timeout=60,
)
print(response.json()["choices"][0]["message"]["content"])const url =
"https://platform.clevi.net/api/v2/aiservice/openai/v1/chat/completions";
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CLEVI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "cip-5.5-im",
messages: [{ role: "user", content: "CLEVI API를 한 문장으로 설명해 줘." }],
}),
});
const data = await response.json();
console.log(data.choices[0].message.content);Example response. The id, created, and usage values differ for each request.
{
"id": "chatcmpl-3f0a9c72",
"object": "chat.completion",
"created": 1755500000,
"model": "cip-5.5-im",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "CLEVI API는 주소 하나로 여러 모델을 호출하는 채팅 완료 API입니다."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 21,
"completion_tokens": 19,
"total_tokens": 40
}
}Calling with the OpenAI SDK
Change the OpenAI SDK's base_url to https://platform.clevi.net/api/v2/aiservice/openai/v1 and put your CLEVI key in api_key. Leave the rest of the calling code as it is.
# pip install openai
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["CLEVI_API_KEY"],
base_url="https://platform.clevi.net/api/v2/aiservice/openai/v1",
)
completion = client.chat.completions.create(
model="cip-5.5-mm",
messages=[{"role": "user", "content": "CLEVI API를 한 문장으로 설명해 줘."}],
)
print(completion.choices[0].message.content)// npm install openai
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.CLEVI_API_KEY,
baseURL: "https://platform.clevi.net/api/v2/aiservice/openai/v1",
});
const completion = await client.chat.completions.create({
model: "cip-5.5-mm",
messages: [{ role: "user", content: "CLEVI API를 한 문장으로 설명해 줘." }],
});
console.log(completion.choices[0].message.content);Receiving a stream
Set stream to true in the request body and the server responds with Server-Sent Events. The first chunk arrives with the Content-Type: text/event-stream, Cache-Control: no-cache, and X-Accel-Buffering: no headers, and each chunk after that carries a chat.completion.chunk object in a data: line. The last line is data: [DONE]. The Python and TypeScript examples below reuse the client created in the previous section.
curl -N https://platform.clevi.net/api/v2/aiservice/openai/v1/chat/completions \
-H "Authorization: Bearer $CLEVI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "cip-5.5-im",
"messages": [{"role": "user", "content": "CLEVI API를 한 문장으로 설명해 줘."}],
"stream": true
}'stream = client.chat.completions.create(
model="cip-5.5-im",
messages=[{"role": "user", "content": "CLEVI API를 한 문장으로 설명해 줘."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="")const stream = await client.chat.completions.create({
model: "cip-5.5-im",
messages: [{ role: "user", content: "CLEVI API를 한 문장으로 설명해 줘." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}Example chunks.
data: {"id":"chatcmpl-3f0a9c72","object":"chat.completion.chunk","model":"cip-5.5-im","choices":[{"index":0,"delta":{"content":"CLEVI"},"finish_reason":null}]}
data: {"id":"chatcmpl-3f0a9c72","object":"chat.completion.chunk","model":"cip-5.5-im","choices":[{"index":0,"delta":{"content":" API는"},"finish_reason":null}]}
data: {"id":"chatcmpl-3f0a9c72","object":"chat.completion.chunk","model":"cip-5.5-im","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]If an error occurs during streaming, the same error JSON arrives as a single data: line, and the HTTP status code changes with it.
Errors
A failed request reports its cause with an HTTP status code. If the upstream returns a 4xx or 5xx, that code is passed through as is. Check the actions in the table below first, and if the same code repeats, keep the request time, the body you sent, and the X-Request-Id.
| Code | Meaning | What to do |
|---|---|---|
| 400 | The request body is malformed | Check that model and messages are present and that the JSON is closed |
| 401 | The key is missing, expired, or revoked | Check the key status on the API Keys page and confirm that the Authorization header starts with Bearer |
| 403 | No access to the model, usage limit exceeded, or insufficient credits | Check error.message for the reason. Limits are under Allocated usage limits on the Overview page; balance and plan are under Plan and credits |
| 404 | The model does not exist or is not accessible with this key, or the path does not exist | Check that the model name appears in the GET /models response and that the address ends with /api/v2/aiservice/openai/v1/chat/completions |
| 429 | The upstream provider applied a rate limit | If a Retry-After header is present, wait that long; otherwise double the retry interval each time and resend |
| 5xx | A temporary error in the gateway or upstream | Resend with a retry interval that doubles each time, and if it repeats, report it through Help and Support with the X-Request-Id |
402 is never returned. Insufficient credits and exceeded usage limits come back as 403. The error body has the format below, with the reason in error.message.
{"error":{"message":"API key is required.","type":"invalid_request_error"}}If you include an X-Request-Id header in the request, that value is used to trace it when you contact support. If you do not send one, the server issues it.
Next steps
Comparing results across model names and parameters is done in the Playground. Creating or revoking keys is done on the API Keys page. Documents to read next:
- Models: the full model list, per-model specifications, and allowed calls
- Make API calls: the Anthropic-compatible path, embeddings and speech paths, and streaming rules
- Error codes: the full status code table and retry rules