Cansei de copiar resposta da telinha do chat e colar no editor. O que resolve isso é um ia.php de vinte linhas: curl_init apontando para o endpoint de mensagens, três headers e o payload em json_encode. Roda com php ia.php no terminal e a resposta volta em JSON, pronta pra entrar em qualquer rotina sua.
O ia.php inteiro
<?php
$payload = [
'model' => 'claude-opus-5',
'max_tokens' => 16000,
'messages' => [
['role' => 'user', 'content' => 'Explique indice composto no MySQL 8 em 3 linhas.'],
],
];
$ch = curl_init('https://api.anthropic.com/v1/messages');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPHEADER => [
'content-type: application/json',
'x-api-key: ' . getenv('ANTHROPIC_API_KEY'),
'anthropic-version: 2023-06-01',
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$corpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http !== 200) {
fwrite(STDERR, "HTTP $http: $corpon");
exit(1);
}
foreach (json_decode($corpo, true)['content'] as $bloco) {
if ($bloco['type'] === 'text') {
echo $bloco['text'], "n";
}
}
Antes de rodar, exporte a chave no shell: export ANTHROPIC_API_KEY='sua-chave'. Chave escrita dentro do arquivo vaza no primeiro commit distraído; getenv custa a mesma linha e não vai pro Git.
Os dois tropeços do primeiro dia
O primeiro é o header de autenticação. Muita API usa Authorization: Bearer, e essa aqui não: a chave vai em x-api-key e o anthropic-version é obrigatório. Errou um dos dois e volta 401 com authentication_error no corpo — por isso o script joga $corpo no STDERR e sai com código 1, em vez de morrer calado.
O segundo é achar que content[0] é sempre o texto. É um array de blocos, e nos modelos atuais o bloco de raciocínio vem antes do text. Filtrar pelo type, como no foreach, evita o resultado vazio que parece bug da API e é só leitura errada do JSON. Pelo mesmo motivo não economize no max_tokens: esse raciocínio conta no mesmo teto, e um valor apertado corta a saída no meio, com stop_reason voltando max_tokens.
Com isso no terminal, o passo seguinte é mover o bloco pra dentro de uma classe e trocar o echo por um retorno. O CURLOPT_TIMEOUT generoso fica: resposta longa demora mesmo.