October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
curl

How to Send Custom HTTP Headers with PHP cURL for Screenshot or PDF APIs

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Send custom HTTP headers in PHP cURL with CURLOPT_HTTPHEADER: an array of complete Name: value strings. Keep the HTTP method, request body, authentication, and response handling in their own cURL options. This separation is what makes a screenshot or PDF request predictable and safe.

The basic PHP cURL pattern

PHP’s documented cURL flow is to initialize a handle, set options, execute it, inspect errors and status, then close the handle. For a JSON API, encode the payload, send it with CURLOPT_POSTFIELDS, and declare the request and response formats with headers when the provider requires them.

<?php
$url = 'https://api.example.test/v1/render';
$apiToken = getenv('API_TOKEN');
$payload = json_encode([
    'url' => 'https://example.com',
], JSON_THROW_ON_ERROR);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiToken,
        'Accept: application/pdf',
        'Content-Type: application/json',
    ],
    CURLOPT_TIMEOUT => 90,
]);

$response = curl_exec($ch);
if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException("API returned HTTP {$status}");
}

file_put_contents('output.pdf', $response);

This is a provider-neutral pattern, not a universal API contract. Replace the URL, method, authentication scheme, payload fields, and accepted response type with the target service’s documentation. Some endpoints return image or PDF bytes; others return JSON metadata or an asynchronous job identifier.

The PHP manual’s basic cURL examples show the same separation of initialization, options, execution, and error handling: PHP cURL examples.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How CURLOPT_HTTPHEADER works

Use complete header strings

CURLOPT_HTTPHEADER expects a numerically indexed array such as ['Accept: application/pdf', 'Content-Type: application/json']. Do not pass an associative PHP map and do not append CRLF characters; libcurl adds line endings itself. The option is documented at libcurl CURLOPT_HTTPHEADER.

Headers do not choose the method

POST and GET are not headers. Use CURLOPT_POST, CURLOPT_HTTPGET, or the appropriate custom-request option. A GET screenshot endpoint commonly needs query parameters and an authentication header but no request body or Content-Type.

Adding, replacing, and removing generated headers

libcurl may generate headers such as Content-Length or Expect. Supplying the same header in CURLOPT_HTTPHEADER can replace its value. An empty value, for example Accept:, removes an internally generated header. To send a header with no value, libcurl documents a trailing semicolon, such as X-Flag;. Use these forms only when the provider requires them.

Authentication, content type, and accept headers

Authentication

Use the scheme specified by the API: often Authorization: Bearer YOUR_TOKEN, but some services require an API-key header or query parameter. Do not combine a manually supplied Authorization header with competing libcurl authentication options unless the provider explicitly supports that arrangement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Content-Type

Set Content-Type: application/json when the body is JSON. If you send form fields, multipart data, or no body, use the format the endpoint documents; do not label form data as JSON.

Accept

Accept describes the response representation you prefer, such as application/pdf or image/png. It does not force a server to return that type. Always inspect the HTTP status and returned content type before writing bytes to a file.

GET and POST examples for capture APIs

GET with an API-key header

<?php
$query = http_build_query([
    'url' => 'https://example.com',
    'full_page' => 'true',
]);
$ch = curl_init('https://api.example.test/v1/screenshot?' . $query);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPGET => true,
    CURLOPT_HTTPHEADER => [
        'X-API-Key: ' . getenv('SCREENSHOT_API_KEY'),
        'Accept: image/png',
    ],
    CURLOPT_TIMEOUT => 90,
]);
$bytes = curl_exec($ch);
if ($bytes === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
if ($status !== 200 || strpos((string) $type, 'image/') !== 0) {
    throw new RuntimeException("Unexpected response: HTTP {$status}, {$type}");
}
file_put_contents('page.png', $bytes);

JSON POST for a PDF job

<?php
$payload = json_encode([
    'url' => 'https://example.com/invoice/123',
    'format' => 'pdf',
], JSON_THROW_ON_ERROR);
$ch = curl_init('https://api.example.test/v1/jobs');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('API_TOKEN'),
        'Content-Type: application/json',
        'Accept: application/json',
    ],
]);
$json = curl_exec($ch);
if ($json === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status < 200 || $status >= 300) {
    throw new RuntimeException("Job submission failed with HTTP {$status}");
}
$result = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
print_r($result);

Response handling for images, PDFs, JSON, and jobs

Do not assume a successful request means binary output. A synchronous endpoint may return PNG, JPEG, WebP, or PDF bytes. A job endpoint may return JSON containing an identifier, download URL, or callback information. Check CURLINFO_RESPONSE_CODE and CURLINFO_CONTENT_TYPE, and parse JSON only when the content type and endpoint contract indicate JSON.

For large files, avoid keeping the entire response in memory by opening a writable stream and using CURLOPT_FILE. If you need error bodies for diagnostics, capture headers separately with CURLOPT_HEADERFUNCTION or use a temporary file strategy, then remove partial files after failures.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Redirects and protecting credentials

When redirects are enabled with CURLOPT_FOLLOWLOCATION, libcurl documents that custom headers can be sent on subsequent requests. Its documented safeguards prevent Authorization and Cookie headers from being sent to other hosts under the applicable version behavior, unless unrestricted-auth behavior is enabled. Treat every redirect destination as untrusted unless you control it.

Do not enable unrestricted forwarding merely to make a redirect work. Prefer the final HTTPS URL, validate redirect destinations, or handle redirects yourself so secrets do not leave the intended host. Never log bearer tokens, API keys, cookie values, or complete authorization headers.

Do not invent a universal Host header. The target host is derived from the URL. PHP’s HTTP context documentation also cautions against setting Host when redirects are enabled: PHP HTTP context options.

Common mistakes and fixes

  • “Invalid header” or a malformed request: ensure every array item is a string in Name: value form, with no CRLF terminator.
  • HTTP 401 or 403: verify the exact authentication header name, scheme, token scope, and environment variable. Do not assume Bearer auth.
  • HTTP 415 Unsupported Media Type: make Content-Type match the actual body and provider contract.
  • JSON parse errors: the response may be an HTML error page or binary file. Check status and content type before calling json_decode.
  • A PDF or image opens as corrupt: you may have saved a JSON error body, enabled header output, or truncated the transfer. Keep CURLOPT_RETURNTRANSFER or CURLOPT_FILE enabled, inspect status, and compare the file type with the response header.
  • Timeouts: distinguish connection, total, and provider rendering limits. Set a realistic CURLOPT_TIMEOUT, and use the provider’s asynchronous job mode for long pages.
  • Redirect loses authentication: inspect the Location host. Rebuild the request for the trusted final host rather than forwarding secrets broadly.
  • “Header” parameter confusion: a PDF vendor’s document header or footer is content rendered inside the PDF, not an HTTP request header. PDFShift illustrates this distinction in its PHP cURL guide: Adding a custom header or footer in PHP with cURL.

Operational checklist

  1. Read the endpoint documentation for method, authentication, body schema, response mode, limits, and redirect behavior.
  2. Build the URL and payload separately from the header array.
  3. Use only the headers the API requires: authentication, matching content type, and an appropriate accept value.
  4. Set a timeout and retain cURL’s error message for diagnostics without logging secrets.
  5. Check status and content type before parsing or saving the response.
  6. Test an invalid token and an invalid URL deliberately so your error path is exercised.
  7. For production, use HTTPS, environment-based secrets, bounded retries for transient failures, and idempotency controls where the provider supports them.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo is a screenshot API and MCP server. Its GET endpoint accepts a URL and returns PNG, JPEG, WebP, or PDF. A one-call PHP request looks like this:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
require __DIR__ . '/vendor/autoload.php';

$q = http_build_query([
    'access_key' => 'YOUR_API_KEY',
    'url' => 'https://stripe.com',
]);
$ch = curl_init('https://api.screenshotneo.com/v1/shot?' . $q);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPGET => true,
    CURLOPT_TIMEOUT => 90,
]);
$bytes = curl_exec($ch);
if ($bytes === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status < 200 || $status >= 300) {
    throw new RuntimeException("ScreenshotNeo returned HTTP {$status}");
}
file_put_contents('shot.webp', $bytes);

See the ScreenshotNeo documentation for output and option details. Before capture, it can accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Can I send a header without a value?

Yes. libcurl documents a trailing semicolon, such as X-Flag;, for a header with no value. An empty value such as Accept: has a different purpose: it removes an internally generated header.

Should I put an API key in the URL or a header?

Use the provider’s documented method. A header is generally less likely to appear in copied URLs and access logs, but the service may require a query parameter. Never substitute one for the other without confirmation.

How do I know whether a response is a PDF?

Check the HTTP status, CURLINFO_CONTENT_TYPE, and the endpoint’s contract. A valid PDF normally has a PDF media type and begins with PDF file bytes; do not rely on the filename alone.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I send a header without a value?

Yes. libcurl documents a trailing semicolon, such as X-Flag;, for a header with no value. An empty value such as Accept: has a different purpose: it removes an internally generated header.

Should I put an API key in the URL or a header?

Use the provider’s documented method. A header is generally less likely to appear in copied URLs and access logs, but the service may require a query parameter. Never substitute one for the other without confirmation.

How do I know whether a response is a PDF?

Check the HTTP status, CURLINFO_CONTENT_TYPE, and the endpoint’s contract. A valid PDF normally has a PDF media type and begins with PDF file bytes; do not rely on the filename alone.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.