Skip to content

PHP Tutorial Working with JSON and APIs

cURL Basics

Lesson 312 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

cURL is a library for making HTTP requests, and PHP has an extension for it (ext-curl). It is the standard tool for calling APIs.

Check that it is available:

index.php
PHP
<?php
var_dump(extension_loaded("curl"));
Output
OUTPUT
bool(true)

If it is false, enable extension=curl in php.ini.

A GET request

index.php
PHP
<?php
$ch = curl_init("https://api.example.com/products?limit=5");

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,      // return the body as a string
    CURLOPT_TIMEOUT => 10,               // total time allowed (seconds)
    CURLOPT_CONNECTTIMEOUT => 5,         // time allowed to connect
    CURLOPT_FOLLOWLOCATION => false,     // do not follow redirects blindly
    CURLOPT_HTTPHEADER => ["Accept: application/json"],
]);

$body = curl_exec($ch);

if ($body === false) {
    $error = curl_error($ch);            // e.g. "Could not resolve host"
    throw new RuntimeException("Request failed: " . $error);
}

$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

$data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

The steps are always: curl_init(), set options, curl_exec(), check for failure, read the status. Since PHP 8.0 a cURL handle is an object (CurlHandle) that closes itself automatically, so curl_close() is no longer needed.

The options you will use most

OptionMeaning
CURLOPT_RETURNTRANSFERReturn the response instead of printing it
CURLOPT_TIMEOUTMaximum seconds for the whole request
CURLOPT_CONNECTTIMEOUTMaximum seconds to connect
CURLOPT_HTTPHEADERAn array of header lines
CURLOPT_POSTSend a POST request
CURLOPT_POSTFIELDSThe request body
CURLOPT_CUSTOMREQUESTSet PUT, PATCH or DELETE
CURLOPT_FOLLOWLOCATIONFollow redirects (and CURLOPT_MAXREDIRS)
CURLOPT_USERAGENTThe User-Agent string
CURLOPT_SSL_VERIFYPEERKeep true. Never turn certificate checks off in production

A POST with JSON

index.php
PHP
<?php
$payload = json_encode(["name" => "Pen", "price" => 12.5], JSON_THROW_ON_ERROR);

$ch = curl_init("https://api.example.com/products");

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_HTTPHEADER => [
        "Content-Type: application/json",
        "Accept: application/json",
        "Authorization: Bearer " . getenv("API_TOKEN"),
    ],
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

A reusable function

index.php
PHP
<?php
function apiRequest(string $method, string $url, ?array $json = null, array $headers = []): array
{
    $ch = curl_init($url);

    $options = [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => array_merge(["Accept: application/json"], $headers),
    ];

    if ($json !== null) {
        $options[CURLOPT_POSTFIELDS] = json_encode($json, JSON_THROW_ON_ERROR);
        $options[CURLOPT_HTTPHEADER][] = "Content-Type: application/json";
    }

    curl_setopt_array($ch, $options);

    $body = curl_exec($ch);

    if ($body === false) {
        throw new RuntimeException("cURL error: " . curl_error($ch));
    }

    return [
        "status" => curl_getinfo($ch, CURLINFO_HTTP_CODE),
        "body" => $body,
    ];
}

Reading the response

index.php
PHP
<?php
function describeResponse(int $status, string $body): string
{
    $data = json_decode($body, true);

    if ($status >= 200 && $status < 300) {
        return "OK: " . ($data["name"] ?? "no name");
    }

    return "Error $status: " . ($data["message"] ?? "unknown error");
}

echo describeResponse(200, '{"name":"Pen"}') . "\n";
echo describeResponse(404, '{"message":"Not found"}');
Output
OUTPUT
OK: Pen
Error 404: Not found

Common cURL problems

MessageLikely cause
Could not resolve hostWrong host name, or no internet from the server
Operation timed outThe service is slow or blocked. Check timeouts and firewalls
SSL certificate problemMissing CA certificates (configure curl.cainfo in php.ini). Do not disable verification
Empty body, status 0The request failed. Read curl_error()

Never disable certificate checks

You will find code online with CURLOPT_SSL_VERIFYPEER => false. It “fixes” certificate errors by turning off the protection that makes HTTPS safe. Fix the certificate configuration instead.

Guzzle and other clients

The popular Guzzle library (installed with Composer), Symfony’s HTTP client, and PHP’s own PSR-18 clients wrap cURL in a cleaner API with retries, async requests and middleware. For anything beyond a few calls, use one of them.

dangerous
Timeouts are not optional
Without CURLOPT_TIMEOUT, a hanging service can hold your PHP process (and your visitor’s page) for as long as the server allows. Always set both timeouts.