# API de PDF com PHP: comprimir com cURL e ler o erro

Como chamar a API de compressão de PDF com PHP e cURL: CURLFile, chave apdf_live_, leitura do status e do Content-Type, e os erros 401, 402 e 429.

URL canônica: https://ajustapdf.com/blog/api-pdf-com-php

Publicado em 2026-10-20 · 5 min de leitura · por [AjustaPDF](https://ajustapdf.com/sobre#editorial)

Para comprimir um PDF pela API com PHP e cURL, faça um POST multipart para https://api.ajustapdf.com/pdf/compress, com o arquivo no campo file, o nível no campo level e o cabeçalho Authorization com a chave apdf\_live\_. Quando dá certo, a resposta é o próprio PDF comprimido; quando falha, é um JSON com error e message.

## O que a API espera

A [compressão](/comprimir-pdf) é uma operação própria do endpoint `/pdf/compress`. Ele aceita um arquivo PDF por chamada, no campo `file`, e o campo `level` com um dos valores `leve`, `media`, `forte` ou `alvo`. Sem o campo, o servidor usa o nível médio. Para gerar o PDF no próprio Laravel antes de comprimi-lo, veja gerar PDF no Laravel com DomPDF. Com `alvo`, envie também `targetMb`, que aceita valores de 0,05 a 200: é o mesmo mecanismo das páginas de [comprimir PDF para 2 MB](/comprimir-pdf-para-2mb) e de [comprimir PDF para 500 KB](/comprimir-pdf-para-500kb).

Cada compressão gasta uma operação da cota diária do plano da conta dona da chave. A chave identifica a conta, e não um visitante: por isso a cota que aparece é a sua, do plano que você tem.

## A chave de API

A chave é criada na sua conta, em /conta, na seção Chaves de API. Ela começa com `apdf_live_` seguido de 32 caracteres, e o site mostra o valor completo só uma vez, no momento da criação. Depois disso, só o prefixo aparece na lista, para você reconhecer a chave. Para revogar, use a mesma seção.

## A chamada completa

O arquivo vai num `CURLFile`, o nível num campo comum e a chave no cabeçalho. Desde o PHP 5.6, o caminho com arroba não é mais aceito por padrão, então o CURLFile é o jeito certo de enviar. O script abaixo comprime um PDF, lê os cabeçalhos de cota e só grava o arquivo quando a resposta é mesmo um PDF:

```
<?php
$chave = getenv("AJUSTAPDF_KEY");
$cotas = [];

$ch = curl_init("https://api.ajustapdf.com/pdf/compress");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => [
        "file" => new CURLFile("contrato.pdf", "application/pdf", "contrato.pdf"),
        "level" => "media",
    ],
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $chave],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 120,
    CURLOPT_HEADERFUNCTION => function ($ch, $linha) use (&$cotas) {
        if (stripos($linha, "x-quota-") === 0) {
            [$nome, $valor] = explode(":", $linha, 2);
            $cotas[strtolower($nome)] = trim($valor);
        }
        return strlen($linha);
    },
]);

$corpo = curl_exec($ch);
if ($corpo === false) {
    exit("Falha de rede: " . curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$tipo = (string) curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

if ($status === 200 && strpos($tipo, "application/pdf") === 0) {
    file_put_contents("contrato-comprimido.pdf", $corpo);
    echo "Uso hoje: " . ($cotas["x-quota-used"] ?? "?") . " de " . ($cotas["x-quota-limit"] ?? "?");
} else {
    $erro = json_decode($corpo, true);
    echo $status . " " . ($erro["error"] ?? "ERRO") . ": " . ($erro["message"] ?? "sem mensagem");
}
```

Se a conexão falhar antes de qualquer resposta, `curl_exec` devolve falso. Trate esse caso à parte, como no script, porque não há status nem corpo para ler.

## Ler a resposta sem confundir erro com PDF

Esse é o ponto que mais quebra integrações. Quando o status é 200, o corpo é o PDF e pode ser gravado direto com `file_put_contents`. Quando não é, o corpo é JSON, com error e message, e gravá-lo num arquivo .pdf produz um arquivo que parece gerado e não abre. Confira sempre o status e o tipo antes de gravar: a resposta de sucesso vem com `application/pdf`, e a de erro, com `application/json`, lido em `CURLINFO_CONTENT_TYPE`.

Uma armadilha comum é ligar `CURLOPT_FAILONERROR`. Essa opção faz o cURL devolver falso em respostas 4xx e 5xx, mas descarta o corpo, e com ele a mensagem de erro. Se você quer mostrar ao usuário o motivo da falha, deixe a opção desligada e leia o JSON você mesmo.

## Cabeçalhos úteis na resposta

| Cabeçalho | Quando aparece | Para que serve |
| --- | --- | --- |
| Content-Type | Sempre | application/pdf no sucesso, application/json no erro |
| x-quota-used | No sucesso | Operações da cota já usadas no dia |
| x-quota-limit | No sucesso | Limite diário do plano |
| x-compress-fitted | Só com o nível alvo | 1 quando coube no tamanho pedido, 0 quando não coube |
| x-compress-level | Só com o nível alvo | O nível usado, ou original quando nada precisou mudar |

## Erros que aparecem no PHP

Trate cada código de forma diferente. Repetir a chamada sem mudar nada só faz sentido para o tempo limite. Os demais pedem uma correção antes de tentar de novo.

-   **401, INVALID\_API\_KEY.** A chave está revogada ou foi digitada com erro. Gere outra em /conta e atualize a variável de ambiente.
-   **402, QUOTA\_EXCEEDED.** A cota diária da conta acabou. A resposta traz o uso atual e o limite, e a cota volta a contar no dia seguinte.
-   **402, FILE\_TOO\_LARGE.** O arquivo passa do limite por arquivo do plano. Comprima antes de enviar, ou use o nível alvo com um tamanho menor.
-   **429, TOO\_MANY\_REQUESTS.** Chegaram muitas operações dessa rede. Espere e reduza o ritmo do seu script.
-   **400, NO\_FILE.** O campo file veio vazio ou com outro nome. Confira o CURLFile e o nome do campo.
-   **504, TIMEOUT.** O processamento passou do tempo permitido. Tente de novo, e, se o arquivo for grande, comprima por partes.

## Onde a chave não deve ficar

A chave é segredo de servidor. Se ela aparecer no JavaScript de uma página pública, qualquer visitante a copia e gasta a sua cota. Mantenha a chamada no backend do seu sistema, com a chave em variável de ambiente, e revogue a chave em /conta se ela tiver vazado num repositório.

## Onde a API para

Para uma compressão por vez, a chamada acima resolve. Quem trabalha com Java ou C# encontra o mesmo contrato no [guia de Java e C#](/blog/api-pdf-com-java-ou-csharp). Para um fluxo em que o próprio usuário envia o arquivo, ele pode usar a ferramenta no site, com a cota dele, e não há necessidade de chave. A API faz sentido quando o seu sistema recebe os PDFs e precisa de um passo automático. Para automações com outras ferramentas, o guia sobre [n8n, Make e Zapier](/blog/automatizar-pdf-n8n-make-zapier) mostra o mesmo contrato HTTP em outro ambiente, e o de [curl no terminal](/blog/curl-api-pdf-terminal) (ou o de [pasta inteira em lote](/blog/pdf-em-lote-pasta-inteira)) é o melhor lugar para testar a chave antes de escrever o PHP; quem ainda escolhe como gerar o PDF no próprio sistema compara dompdf, TCPDF e mPDF. Se quem vai chamar as ferramentas é um assistente de IA, o servidor MCP em `https://api.ajustapdf.com/mcp` aceita a mesma chave.

## Perguntas frequentes

### Como enviar um PDF para a API de compressão com PHP e cURL?

Crie um cURL apontando para https://api.ajustapdf.com/pdf/compress, envie o arquivo com new CURLFile no campo file e o nível no campo level, e passe o cabeçalho Authorization com Bearer e a sua chave apdf_live_. Leia o status e o Content-Type antes de gravar a resposta como PDF.

### Por que o PDF que o PHP salvou da API não abre?

Provavelmente o arquivo recebeu a resposta de erro, que é JSON com os campos error e message. Confira o status HTTP e o Content-Type antes de gravar. Com 401, 402 ou 429, o corpo é texto JSON, e um arquivo com essa mensagem não é um PDF.

### Qual chave usar no cabeçalho Authorization da API de PDF?

A chave que começa com apdf_live_, criada em /conta, na seção Chaves de API. Envie no formato Authorization: Bearer seguido da chave, sem aspas. O site mostra a chave completa só na criação, então guarde-a num arquivo de configuração ou numa variável de ambiente do servidor.

### Como comprimir um PDF com PHP só até um tamanho máximo?

Envie level com o valor alvo e targetMb com o tamanho em megabytes, de 0,05 a 200. O servidor tenta leve, média e forte, nessa ordem, e entrega o primeiro que caiba. Se nem o forte couber, o cabeçalho x-compress-fitted volta com 0 e o arquivo devolvido é o menor que saiu.
