В этой статье
Для ручной проверки OpenAI API достаточно обычного HTTP-клиента. Нужны API-ключ, идентификатор доступной модели и JSON с массивом messages. Запрос к Chat Completions — это POST https://api.openai.com/v1/chat/completions; в минимальной схеме обязательны model и messages. Поддержка остальных параметров зависит от выбранной модели, поэтому не переносите в запрос весь набор полей из чужого примера без проверки документации.
Что подготовить
Ключ передавайте в заголовке Authorization как Bearer-токен. Не вставляйте его в исходный код, коммит или клиентский JavaScript: браузерный код виден пользователю, а вместе с ним станет виден и секрет. Для локальной проверки положите ключ в переменную окружения:
export OPENAI_API_KEY='ваш_api_ключ'
В Windows PowerShell аналогичная команда:
$env:OPENAI_API_KEY = 'ваш_api_ключ'
В этом примере ключ живёт только в текущей сессии оболочки. Для приложения используйте штатное хранилище секретов вашей среды, а на сервере ограничьте доступ к переменной процессом приложения. Официальный quickstart OpenAI также показывает вызов через переменную окружения, а не через ключ, записанный в коде.
Модель задайте отдельной переменной, чтобы не путать её идентификатор с названием тарифа ChatGPT:
export MODEL_ID='model-id-from-your-project'
Если идентификатор неизвестен, сначала запросите список моделей:
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY"
В ответе ищите модель, доступную вашему API-проекту. Endpoint и формат списка описаны в Models API Reference. Название подписки ChatGPT для этого не подходит. Подписка ChatGPT и биллинг API — разные системы, поэтому первая сама по себе не означает наличие оплаченного доступа к API; это отдельно разъяснено в справке OpenAI о биллинге.
Рабочий POST-запрос
Для первого теста отправьте два сообщения: инструкцию для модели и вопрос пользователя. Заголовок Content-Type сообщает серверу, что тело содержит JSON.
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d @- <<JSON
{
"model": "${MODEL_ID}",
"messages": [
{
"role": "system",
"content": "Отвечай кратко и по-русски."
},
{
"role": "user",
"content": "Объясни одним предложением, зачем нужен HTTP-заголовок Content-Type."
}
]
}
JSON
Здесь model — строковый идентификатор модели, а messages — упорядоченная история диалога. У каждого элемента есть role и content: первое поле задаёт роль сообщения, второе содержит текст. Порядок важен: модель получает массив как контекст, а не как набор независимых параметров. Точную схему и совместимые поля проверяйте в Chat Completions API Reference.
Вместо heredoc можно передать JSON из файла — это удобно, если тело запроса собирает приложение:
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
--data-binary @request.json
Сам ключ всё равно должен оставаться в заголовке и переменной окружения. Не используйте curl -v рядом с секретом без необходимости: подробный лог легко попадёт в CI или историю диагностики. Проверьте также логи прокси и middleware, которые могут записывать заголовки запроса.
Как проверить не только HTTP 200
Успешный HTTP-статус ещё не заменяет проверку тела ответа. Для обычного, не потокового запроса сохраните JSON во временный файл и отдельно запишите код ответа:
response_file="$(mktemp)"
http_code="$(curl -sS -o "$response_file" -w '%{http_code}' \
https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d @- <<JSON
{
"model": "${MODEL_ID}",
"messages": [
{"role": "system", "content": "Отвечай кратко и по-русски."},
{"role": "user", "content": "Назови один HTTP-метод."}
]
}
JSON
)"
echo "HTTP $http_code"
if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then
jq -r '.error.message // "Сервер вернул ошибку без поля error.message"' "$response_file"
rm -f "$response_file"
exit 1
fi
answer="$(jq -er '.choices[0].message.content' "$response_file")" || {
echo 'В успешном ответе нет choices[0].message.content' >&2
cat "$response_file" >&2
rm -f "$response_file"
exit 1
}
printf '%s\n' "$answer"
jq '{finish_reason: .choices[0].finish_reason, usage: .usage}' "$response_file"
rm -f "$response_file"
Проверка отделяет сетевой результат от JSON: любой код вне диапазона 2xx считается ошибкой. При ошибке она показывает только error.message, а для успеха требует choices[0].message.content. Если сервер вернул другой JSON, команда завершится с ошибкой, и это будет заметно до передачи пустой строки в следующий компонент.
В обычном ответе текст находится в choices[0].message.content. Поле finish_reason помогает понять, чем закончилась генерация, а usage — проверить сведения о расходе токенов. Это минимальная проверка формы ответа, а не полноценная политика повторов: при сетевом обрыве нельзя автоматически повторять операции вслепую, если приложение связывает ответ с побочным действием.
Потоковый режим (stream) проверяется иначе: вместо одного готового JSON приходят последовательные chunk-объекты. Код, который ожидает единственный choices[0].message.content, для такого ответа не подходит. Для первого подключения оставьте поток выключенным и сначала добейтесь корректного обычного ответа.
Если сервер вернул ошибку
Проверяйте проблему в таком порядке:
- Убедитесь, что
OPENAI_API_KEYзадана в том процессе, где запускаетсяcurl, но не выводите её значение. - Проверьте URL
https://api.openai.com/v1/chat/completions, методPOSTи заголовок, начинающийся сBearer. - Проверьте JSON: в нём должны быть
modelи непустой массивmessages, а каждая запись должна иметь поддерживаемыеroleиcontent. - Сверьте
MODEL_IDсо списком моделей и доступом API-проекта. Название плана ChatGPT не является идентификатором модели. - Посмотрите HTTP-код и поле
error.messageв теле ответа. Не подменяйте диагностику предположением по одному тексту ошибки.
После основного технического решения, если вам отдельно нужна пользовательская подписка или другой цифровой сервис, можно посмотреть общий каталог Amber Market. Это не способ пополнить OpenAI API и не замена API billing: в каталоге нет отдельного товара для пополнения баланса OpenAI API, а пользовательская подписка и баланс API — разные вещи. Перед заказом проверьте карточку и итоговые условия; ссылка относится только к отдельной пользовательской услуге, а не к выполненному выше API-запросу.
Для нового проекта OpenAI рекомендует рассмотреть Responses API. Но если приложению нужна именно совместимая схема Chat Completions или вы поддерживаете существующий код, POST /v1/chat/completions остаётся описанным endpoint с контрактом model + messages. Зафиксируйте этот контракт на границе приложения: секрет добавляется только сервером, запрос получает проверяемый HTTP-результат, а бизнес-логика читает ответ лишь после проверки структуры.
Источники
- Chat Completions | OpenAI API ReferenceOpenAI
- Developer quickstartOpenAI
- Models | OpenAI API ReferenceOpenAI
- Managing billing for ChatGPT and the API platformOpenAI Help Center