How To Make API Calls With Python in 2025

Learn modern GET/POST techniques, parse JSON, and leverage SDKs for efficient Python API calls.
13 min read
How to make API calls using Python blog image

In this guide, we’ll walk through the following concepts of API usage with Python:

  1. What is HTTP?
  2. What is a REST API?
  3. How to make a GET request
  4. How to make a POST request
  5. How to use an SDK

What Is HTTP?

HTTP (Hypertext Transfer Protocol) is the standard for how most data travels the web. You’ve probably heard that databases make up the backend of most websites—and this is true, but there are nuances in how our client (browser or Python script) actually interacts with the database. HTTP is the communication layer between the client and the backend server.

When using HTTP for scraping and web APIs, these are the methods you’re most likely to use.

  • GET: The most commonly used method by far. Whenever you visit a site, your browser performs a GET for the HTML, and then renders the page for you to view.
  • POST: This is the second most common method. POST is used to transfer larger bodies of data securely—and most often to add something to a database. When you complete forms and surveys or post on social media, you’re performing a POST request.
  • PUT: PUT requests are used to update existing items in a database. When you edit a social media post, PUT gets used under the hood.
  • DELETE: If you wish to delete a social media post (or anything else from a database), your browser sends a DELETE request to the server to remove it.

HTTP and Its Lack of Return Standards

For all its simplicity, HTTP lacks a universal return standard. Some servers return HTML by default, while others spit back JSON or even legacy data structures like XML and plaintext.

First, let’s make a basic GET request. If you don’t already have Python Requests installed, you can install it via pip.

pip install requests

Once you’ve got Requests installed, you can run the following code to make a simple GET. Pay attention to the terminal output.

import requests

response = requests.get("https://quotes.toscrape.com")

print(response.text)

After running the code, you should notice that we’ve got an HTML page. This is great for viewing in the browser, but in the terminal, it’s pretty ugly. The output below has been trimmed, but you get the idea.

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>Quotes to Scrape</title>
    <link rel="stylesheet" href="/static/bootstrap.min.css">
    <link rel="stylesheet" href="/static/main.css">


</head>
<body>
    <div class="container">
        <div class="row header-box">
            <div class="col-md-8">
                <h1>
                    <a href="/" style="text-decoration: none">Quotes to Scrape</a>
                </h1>
            </div>
            <div class="col-md-4">
                <p>

                    <a href="/login">Login</a>

                </p>
            </div>
        </div>


<div class="row">
    <div class="col-md-8">

    <div class="quote" itemscope itemtype="http://schema.org/CreativeWork">
        <span class="text" itemprop="text">“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”</span>
        <span>by <small class="author" itemprop="author">Albert Einstein</small>
        <a href="/author/Albert-Einstein">(about)</a>
        </span>
        <div class="tags">
            Tags:
            <meta class="keywords" itemprop="keywords" content="change,deep-thoughts,thinking,world" /    >

            <a class="tag" href="/tag/change/page/1/">change</a>

            <a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a>

            <a class="tag" href="/tag/thinking/page/1/">thinking</a>

            <a class="tag" href="/tag/world/page/1/">world</a>

        </div>
    </div>

    <div class="quote" itemscope itemtype="http://schema.org/CreativeWork">
        <span class="text" itemprop="text">“It is our choices, Harry, that show what we truly are, far more than our abilities.”</span>
        <span>by <small class="author" itemprop="author">J.K. Rowling</small>
        <a href="/author/J-K-Rowling">(about)</a>
        </span>
        <div class="tags">
            Tags:
            <meta class="keywords" itemprop="keywords" content="abilities,choices" /    >

            <a class="tag" href="/tag/abilities/page/1/">abilities</a>

            <a class="tag" href="/tag/choices/page/1/">choices</a>

        </div>
    </div>

HTML pages are meant to be read and rendered by browsers. They’re not designed for you to read or integrate into your code.

How REST (Representational State Transfer) Fixes This

REST APIs give us a design standard for data pipelines. JSON is by far the most popular return type with REST APIs. It’s flexible and easy to read. This clear, readable syntax also makes it easy to parse from your programming environment.

Take a look below to see what JSON actually looks like. Remember, we use a REST API to get this type of data structure.

{
    "name": "Jake",
    "age": 34,
    "professions": ["writing", "coding"]
}

REST APIs use endpoints, parameters and HTTP methods to control the return data and its format.

Making Your First API Request

Now that you know what a REST API is supposed to do, let’s try actually using one. Quotes to Scrape also has a REST API. Instead of simply fetching the home page, now we’ll access their API. We’re communicating with the server through endpoints.

Our full endpoint /api/quotes can be broken into two pieces.

  1. /api: This tells the server that we want structured API data, not HTML pages.
  2. /quotes: We want the API to return data from the quotes endpoint.

Making The Request

Go ahead and run the code like you did before.

import requests
import json

response = requests.get("https://quotes.toscrape.com/api/quotes")

print(json.dumps(response.json(), indent=4))

Our data now comes back clean and structured. It’s easy to parse—and from there, we can do just about anything with it.

{
    "has_next": true,
    "page": 1,
    "quotes": [
        {
            "author": {
                "goodreads_link": "/author/show/9810.Albert_Einstein",
                "name": "Albert Einstein",
                "slug": "Albert-Einstein"
            },
            "tags": [
                "change",
                "deep-thoughts",
                "thinking",
                "world"
            ],
            "text": "\u201cThe world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/1077326.J_K_Rowling",
                "name": "J.K. Rowling",
                "slug": "J-K-Rowling"
            },
            "tags": [
                "abilities",
                "choices"
            ],
            "text": "\u201cIt is our choices, Harry, that show what we truly are, far more than our abilities.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/9810.Albert_Einstein",
                "name": "Albert Einstein",
                "slug": "Albert-Einstein"
            },
            "tags": [
                "inspirational",
                "life",
                "live",
                "miracle",
                "miracles"
            ],
            "text": "\u201cThere are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/1265.Jane_Austen",
                "name": "Jane Austen",
                "slug": "Jane-Austen"
            },
            "tags": [
                "aliteracy",
                "books",
                "classic",
                "humor"
            ],
            "text": "\u201cThe person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/82952.Marilyn_Monroe",
                "name": "Marilyn Monroe",
                "slug": "Marilyn-Monroe"
            },
            "tags": [
                "be-yourself",
                "inspirational"
            ],
            "text": "\u201cImperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/9810.Albert_Einstein",
                "name": "Albert Einstein",
                "slug": "Albert-Einstein"
            },
            "tags": [
                "adulthood",
                "success",
                "value"
            ],
            "text": "\u201cTry not to become a man of success. Rather become a man of value.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/7617.Andr_Gide",
                "name": "Andr\u00e9 Gide",
                "slug": "Andre-Gide"
            },
            "tags": [
                "life",
                "love"
            ],
            "text": "\u201cIt is better to be hated for what you are than to be loved for what you are not.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/3091287.Thomas_A_Edison",
                "name": "Thomas A. Edison",
                "slug": "Thomas-A-Edison"
            },
            "tags": [
                "edison",
                "failure",
                "inspirational",
                "paraphrased"
            ],
            "text": "\u201cI have not failed. I've just found 10,000 ways that won't work.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/44566.Eleanor_Roosevelt",
                "name": "Eleanor Roosevelt",
                "slug": "Eleanor-Roosevelt"
            },
            "tags": [
                "misattributed-eleanor-roosevelt"
            ],
            "text": "\u201cA woman is like a tea bag; you never know how strong it is until it's in hot water.\u201d"
        },
        {
            "author": {
                "goodreads_link": "/author/show/7103.Steve_Martin",
                "name": "Steve Martin",
                "slug": "Steve-Martin"
            },
            "tags": [
                "humor",
                "obvious",
                "simile"
            ],
            "text": "\u201cA day without sunshine is like, you know, night.\u201d"
        }
    ],
    "tag": null,
    "top_ten_tags": [
        [
            "love",
            14
        ],
        [
            "inspirational",
            13
        ],
        [
            "life",
            13
        ],
        [
            "humor",
            12
        ],
        [
            "books",
            11
        ],
        [
            "reading",
            7
        ],
        [
            "friendship",
            5
        ],
        [
            "friends",
            4
        ],
        [
            "truth",
            4
        ],
        [
            "simile",
            3
        ]
    ]
}

Making an Authenticated Request

Now that we’ve seen how to request public data, let’s look at authenticated APIs. In many cases, you’ll need an API key to get your data. Most API servers require an Authorization header with your API key to authenticate your request.

Making a basic GET request is pretty easy. Now, we’ll try making a POST request. POST requests are used to handle larger payloads of information securely. In the code below, we use the Web Unlocker API to parse the page and return markdown.

import requests

API_KEY = "your-api-key"
ZONE = "web_unlocker1"

url = "https://api.brightdata.com/request"
headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}
payload = {
    "url": "https://quotes.toscrape.com/",
    "zone": ZONE,
    "format": "raw",
    "data_format": "markdown"
}

response = requests.post(url, headers=headers, json=payload)

print(response.text)

This time, our request is going to https://api.brightdata.com/request. Everything is controlled by our headers and payload.

Here are our headers:

  • "Authorization": f"Bearer {API_KEY}": This ties the request to your Bright Data account.
  • "Content-Type": "application/json": This tells the server that we’re sending data in JSON format.

Now, take a look at the payload:

  • "url": The url we wish to access with Web Unlocker.
  • "zone": The zone name that you gave your instance of Web Unlocker.
  • "format": The response format we want (in this case raw)
  • "data_format": We use “markdown”—this tells Bright Data that we want the page parsed into markdown format. It’s not quite as flexible as JSON, but it can be converted to JSON easily.

Here’s the terminal output now that the page is converted to markdown.

# [Quotes to Scrape](/)

[Login](/login)

“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.” by Albert Einstein [(about)](/author/Albert-Einstein)

 Tags: [change](/tag/change/page/1/) [deep-thoughts](/tag/deep-thoughts/page/1/) [thinking](/tag/thinking/page/1/) [world](/tag/world/page/1/)

“It is our choices, Harry, that show what we truly are, far more than our abilities.” by J.K. Rowling [(about)](/author/J-K-Rowling)

 Tags: [abilities](/tag/abilities/page/1/) [choices](/tag/choices/page/1/)

“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.” by Albert Einstein [(about)](/author/Albert-Einstein)

 Tags: [inspirational](/tag/inspirational/page/1/) [life](/tag/life/page/1/) [live](/tag/live/page/1/) [miracle](/tag/miracle/page/1/) [miracles](/tag/miracles/page/1/)

“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.” by Jane Austen [(about)](/author/Jane-Austen)

 Tags: [aliteracy](/tag/aliteracy/page/1/) [books](/tag/books/page/1/) [classic](/tag/classic/page/1/) [humor](/tag/humor/page/1/)

“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.” by Marilyn Monroe [(about)](/author/Marilyn-Monroe)

 Tags: [be-yourself](/tag/be-yourself/page/1/) [inspirational](/tag/inspirational/page/1/)

“Try not to become a man of success. Rather become a man of value.” by Albert Einstein [(about)](/author/Albert-Einstein)

 Tags: [adulthood](/tag/adulthood/page/1/) [success](/tag/success/page/1/) [value](/tag/value/page/1/)

“It is better to be hated for what you are than to be loved for what you are not.” by André Gide [(about)](/author/Andre-Gide)

 Tags: [life](/tag/life/page/1/) [love](/tag/love/page/1/)

“I have not failed. I've just found 10,000 ways that won't work.” by Thomas A. Edison [(about)](/author/Thomas-A-Edison)

 Tags: [edison](/tag/edison/page/1/) [failure](/tag/failure/page/1/) [inspirational](/tag/inspirational/page/1/) [paraphrased](/tag/paraphrased/page/1/)

“A woman is like a tea bag; you never know how strong it is until it's in hot water.” by Eleanor Roosevelt [(about)](/author/Eleanor-Roosevelt)

 Tags: [misattributed-eleanor-roosevelt](/tag/misattributed-eleanor-roosevelt/page/1/)

“A day without sunshine is like, you know, night.” by Steve Martin [(about)](/author/Steve-Martin)

 Tags: [humor](/tag/humor/page/1/) [obvious](/tag/obvious/page/1/) [simile](/tag/simile/page/1/)

* [Next →](/page/2/)

## Top Ten tags

[love](/tag/love/) [inspirational](/tag/inspirational/) [life](/tag/life/) [humor](/tag/humor/) [books](/tag/books/) [reading](/tag/reading/) [friendship](/tag/friendship/) [friends](/tag/friends/) [truth](/tag/truth/) [simile](/tag/simile/)

 Quotes by: [GoodReads.com](https://www.goodreads.com/quotes)

 M

Authentication uses a unique identifier—usually an API key. In this case, we gained access to Web Unlocker but the principle is the same—no matter which API service you’re using.

Handling The Response

Each response includes a status code. Status codes are used to relay different messages back to the client. In a perfect world, you’ll always receive a 200 status.

Sadly, the world isn’t perfect. If you receive a non-200 code, this means that something is wrong.

  • 400-499: These codes typically imply an error on the client side. Double check your API key and your request format.
  • 500-599: This range indicates a server error. Your request was fine, but the server couldn’t complete it for one reason or another.

You can learn more about status codes here. If you want to learn how to handle these status codes from Python, take a look at this guide on retry logic.

Skipping The Boilerplate With an SDK

An SDK (software development kit) allows us to connect to a REST API without having to write boilerplate for error handling and retry logic. The OpenAI API offers a full REST API as well. You can take a look at it here.

To install their SDK and skip the HTTP requests, run the following command.

pip install openai

Now, we import the OpenAI SDK. We fetch the plain old HTML page like we did initially. If you’re interested in parsing HTML manually, you can learn how to use Requests with BeautifulSoup. Once we’ve retrieved the HTML page, we use the SDK to pass the page into ChatGPT for parsing.

from openai import OpenAI
import requests

OPENAI_API_KEY = "sk-your-openai-api-key"

response = requests.get("https://quotes.toscrape.com")
html_page = response.text

client = OpenAI(api_key=OPENAI_API_KEY)

chat = client.chat.completions.create(
    messages=[
        {
            "role": "user",
            "content": f"Parse the quotes from the following page. I want JSON only--zero commentary from you, here's the page: {html_page}",
        }
    ],
    model="gpt-4o-mini",
)

reply = chat.choices[0].message.content
print(f"ChatGPT: {reply}")

Take a look at the output this time. Zero parsing required—just data inside of a json block.

[
    {
        "text": "The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.",
        "author": "Albert Einstein",
        "tags": ["change", "deep-thoughts", "thinking", "world"]
    },
    {
        "text": "It is our choices, Harry, that show what we truly are, far more than our abilities.",
        "author": "J.K. Rowling",
        "tags": ["abilities", "choices"]
    },
    {
        "text": "There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.",
        "author": "Albert Einstein",
        "tags": ["inspirational", "life", "live", "miracle", "miracles"]
    },
    {
        "text": "The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.",
        "author": "Jane Austen",
        "tags": ["aliteracy", "books", "classic", "humor"]
    },
    {
        "text": "Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.",
        "author": "Marilyn Monroe",
        "tags": ["be-yourself", "inspirational"]
    },
    {
        "text": "Try not to become a man of success. Rather become a man of value.",
        "author": "Albert Einstein",
        "tags": ["adulthood", "success", "value"]
    },
    {
        "text": "It is better to be hated for what you are than to be loved for what you are not.",
        "author": "André Gide",
        "tags": ["life", "love"]
    },
    {
        "text": "I have not failed. I've just found 10,000 ways that won't work.",
        "author": "Thomas A. Edison",
        "tags": ["edison", "failure", "inspirational", "paraphrased"]
    },
    {
        "text": "A woman is like a tea bag; you never know how strong it is until it's in hot water.",
        "author": "Eleanor Roosevelt",
        "tags": ["misattributed-eleanor-roosevelt"]
    },
    {
        "text": "A day without sunshine is like, you know, night.",
        "author": "Steve Martin",
        "tags": ["humor", "obvious", "simile"]
    }
]

SDKs give you the full power of a REST API without the need for manual HTTP management. If you’re interested in learning how to scrape with AI, take a look at our guides for Claude and DeepSeek.

Conclusion

Now that you know how to make basic API requests with Python, you can move on to bigger projects. You can use APIs to interact with various services to retrieve data and you can even utilize an SDK to automatically parse that data. In this tutorial, we used Web Unlocker, but Bright Data offers a variety of other products to help with your data needs.

  • Residential Proxies: Route your HTTP traffic through real devices with residential IP addresses.
  • Scraper API: Completely automate your scrape and download the results straight to your programming environment.
  • Scraping Browser: Bypass CAPTCHAs and control a real headless browser from right inside your Python script.

Sign up for a free trial and get started today!

No credit card required