Apis

By the end of this lesson you'll be able to call any external API from PHP — fetch data with file_get_contents and cURL, send authenticated POST requests, parse the JSON you get back, and handle errors, status codes, and timeouts like a professional.

Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.

Part of the free Php course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ The Quick Way: file_get_contents

The fastest way to read a remote URL is file_get_contents() — the same function you'd use to read a file, except you hand it a web address. It downloads the response body as one big string. Most APIs answer in JSON (a text format for structured data), so you then call json_decode($json, true) to turn that text into a PHP associative array you can read by key. The true matters: it gives you an array, not a harder-to-use object.

Two lines do the real work: one fetches the text, one decodes it. The catch is that file_get_contents on a URL is bare-bones — it sends no useful headers, has no obvious timeout, and on failure returns false with only a warning. For real APIs you need to configure the request, which is the next section.

2️⃣ Adding Headers & a Timeout: Stream Context

A stream context is an options bundle you pass as the third argument to file_get_contents . It lets you set the HTTP method, request headers (many APIs reject a request with no User-Agent ), and a timeout so a dead server can't hang your script forever. After the call, PHP auto-fills $http_response_header with the response status line so you can see what the server actually said.

Setting ignore_errors => true is important: without it, a 404 or 500 makes file_get_contents return false and throw away the body — but error responses usually contain a helpful JSON message you'll want to read. This works, but cURL gives you cleaner control, so it's what professionals reach for.

3️⃣ The Standard Way: cURL

cURL is PHP's built-in library for HTTP requests and the tool you'll use most. Every cURL request follows the same four steps: curl_init() creates a request handle, curl_setopt() configures it (one option at a time), curl_exec() sends it, and curl_close() frees the handle. The single most important option is CURLOPT_RETURNTRANSFER => true — without it, cURL prints the response instead of returning it as a string.

Notice curl_getinfo($ch, CURLINFO_HTTP_CODE) — that's how you read the HTTP status code (200 = OK, 404 = not found, 500 = server error). Always set a CURLOPT_TIMEOUT so one slow API can't freeze your whole app.

4️⃣ POST, JSON Bodies & Bearer Auth

To send data — create a record, log in, trigger an action — you make a POST request. Set CURLOPT_POST => true , put your JSON in CURLOPT_POSTFIELDS , and add a Content-Type: application/json header so the server knows how to read it. Most APIs require authentication : the common pattern is a Bearer token , a secret string you send in an Authorization: Bearer <token> header. Read that token from the environment with getenv() — never write it into your code.

This is the production shape of an API call: send the request, then branch on the result. First check whether the request failed at the network level ( $body === false ), then check the status code for 2xx success, and only decode the JSON when you know you have a real response. Skipping these checks is the number-one source of API bugs.

5️⃣ Status Codes, Timeouts & Rate-Limit Etiquette

An API can refuse you for many reasons, and it tells you which with a status code : 200/201 success, 401 bad token, 404 not found, 429 too many requests, 500 server error. Always branch on the code before trusting the body. Equally, always set a timeout so a hanging server can't take your app down with it.

Being a good API citizen — rate-limit etiquette — keeps you from getting blocked. Don't request the same data twice; cache it. Don't hammer an endpoint in a tight loop; add a small delay. And if you get a 429 , read the Retry-After header and wait that many seconds before retrying. Now you try the two core skills — fetching and guarding.

Fill in each ___ using the 👉 hint, then run it and check it against the Output panel.

One more. A real client never decodes a response it hasn't checked. Add the condition that only proceeds on a successful status code.

📋 Quick Reference — Consuming APIs

No code is filled in this time — just a brief and an outline. Write it yourself, run it on a machine with internet, then check your result against the expected output in the comments. This is exactly the fetch-check-decode loop you'll use against every real API.

Practice quiz

What does json_decode($json, true) return?

  • A stdClass object
  • A JSON string
  • An associative array
  • A cURL handle

Answer: An associative array. Passing true as the second argument gives an associative array you can read by key, instead of a harder-to-use object.

What are the four steps of every cURL request, in order?

  • init, setopt, exec, close
  • open, read, write, close
  • connect, send, receive, free
  • create, configure, send, parse

Answer: init, setopt, exec, close. Every cURL request follows curl_init -> curl_setopt -> curl_exec -> curl_close.

What does CURLOPT_RETURNTRANSFER => true do?

  • Sends the request body
  • Sets a timeout
  • Enables POST
  • Returns the response as a string instead of printing it

Answer: Returns the response as a string instead of printing it. Without CURLOPT_RETURNTRANSFER, cURL prints the response; with it, curl_exec returns the body as a string.

How do you read the HTTP status code after a cURL request?

  • curl_status($ch)
  • curl_getinfo($ch, CURLINFO_HTTP_CODE)
  • curl_code($ch)
  • $ch->status

Answer: curl_getinfo($ch, CURLINFO_HTTP_CODE). curl_getinfo($ch, CURLINFO_HTTP_CODE) reads the status code (200, 404, 500, etc).

Which cURL option carries the JSON body of a POST request?

  • CURLOPT_POSTFIELDS
  • CURLOPT_BODY
  • CURLOPT_HTTPHEADER
  • CURLOPT_DATA

Answer: CURLOPT_POSTFIELDS. Set CURLOPT_POST => true and put the encoded JSON in CURLOPT_POSTFIELDS, with a Content-Type: application/json header.

Why does json_decode() sometimes return null?

  • The body was too large
  • cURL was not installed
  • The input was not valid JSON (e.g. an HTML error page or empty body)
  • The URL used https

Answer: The input was not valid JSON (e.g. an HTML error page or empty body). json_decode returns null on invalid JSON. Check the status code first, then json_last_error() to see what went wrong.

Where should API keys and tokens be stored?

  • Hard-coded in the source file
  • In environment variables, read with getenv()
  • In a public config.js
  • Committed to git for the team

Answer: In environment variables, read with getenv(). Never hard-code or commit secrets. Read them from the environment with getenv() and keep them in a .gitignored .env file.

How should you send a Bearer token for authentication?

  • As a URL query parameter
  • In CURLOPT_POSTFIELDS
  • As a cookie only
  • In an Authorization: Bearer <token> request header

Answer: In an Authorization: Bearer <token> request header. The common pattern is an Authorization: Bearer <token> header, with the token read from the environment.

What should you do when an API responds with HTTP 429?

  • Immediately retry in a tight loop
  • Read the Retry-After header and wait that many seconds before retrying
  • Switch to file_get_contents
  • Ignore it and continue

Answer: Read the Retry-After header and wait that many seconds before retrying. 429 means too many requests. Respect rate limits: read Retry-After and back off before trying again; cache to avoid re-requesting.

Why must you always set CURLOPT_TIMEOUT?

  • It speeds up the request
  • It enables HTTPS
  • Without it, cURL waits indefinitely for a dead server and can freeze your app
  • It validates the JSON

Answer: Without it, cURL waits indefinitely for a dead server and can freeze your app. With no timeout, cURL waits forever for a slow or dead server. Always set CURLOPT_TIMEOUT so a slow API fails fast.