How API Calls are structured in Bubble.io

Follow me:

Using the Data API, API Connector and API Workflows in Bubble.io opens up serious possibilities in your application. This is the moment when your app transitions from pretty database platform to citizen of the world: the language of APIs let’s you talk to every other system and app out there and exchange data, processing and workflows across a plethora of different services.

In the first part in our guide on using APIs in Bubble.io, we talked about the different types of connections that Bubble offers and the scenarios in which they are useful. We talked about API endpoints, the difference between incoming and outgoing API connections and looked at what an actual API query and response can look like.

Now, a video tutorial or guide on a particular API can help you set up that specific API – but when I do Bubble coaching sessions it often becomes apparent that while the student was successful at setting it up, they still sometimes lack the understanding of why it works – and are afraid to touch anything for fear of the whole setup collapsing like a house of cards.

So let’s dive into what exactly is going on with REST API calls.

What does REST API mean?

An API is a collection of protocols and definitions that establish a relationship of exchange between a Client that makes a request and a Rerver that returns a response. You can see this as a kind of contract between the Client and the Server: the Server let’s the Client know what exactly they need in order to send back a response.

If you’d like to download weather information for example, the Client may let you know that you need to specify a date and some map coordinates for the Server to know what information to send. In addition, the Server may tell you that you need to authenticate yourself to get any data at all.

In other words, if you want to interact with an external system to get some information, process data or start a workflow, an API helps you communicate what you want to that system so it can understand and fulfill the request.

Resources and endpoints

The purpose of any API is to reach some specific resource in the external system. A resource can be anything that the server lets you have access to. In a Bubble API that could be Data Types, like a User, or an API Workflow. Each of these resources have a unique identifier, which makes up its endpoint. As we discussed in the last article, the endpoint is the URL that leads an external system to the right resource. And guess what: URL stands for Uniform Resource Locator – makes sense, don’ it?

And we’re just getting started talking about familiar web browser references.


The Bubble API system is organized around REST. REST is not in itself a protocol, but a pattern of design: it gives API developers a set of constraints that make their service easier to use. Since they follow a predictable pattern of setup and documentation, most developers (regardless of programming language or framework) will find it easy to learn and test.

That’s why you as a Bubble API developer in learning may find the first API difficult to set up and understand, but once you get the hang of it it’s smooth sailing. Systems could communicate in any weird way they see fit, as long as both parties agree, but thanks to architectures like REST and OpenAPI it’s pretty predictable how they all talk to each other.

REST is an acronym for REpresentational State Transfer. It’s not exactly an approachable, roll-of-the-tongue name, but it’s not gibberish either. Basically, it means that when you make a request to the API, it will respond with a representation of the current state of the resource you are requesting.

In English, this means that each call is completely independent: each request and response provides all the information required to complete the interaction. The server interprets every request as if he’s never seen you before – any prior requests that a Client has made have no effect on the current one. One of the consequences of this is that you need to authenticate yourself every time you make a call: the server will not remember who you are for the next one.

One of the reasons this approach works so well is that it’s very friendly to the capacity of the Server. Since there’s no pileup of data that the server would need to retrieve from memory, every call is equally lightweight and predictable to complete, making it highly scaleable.


Technically, REST APIs can be set up using any kind of transfer protocol, but in the majority of cases they use HTTP. The HTTP protocol was created when the internet was born as a way for your computer to request data from a server in the form of a web page, and the URL was the locator for that page (or resource). The REST API design pattern was inspired by the simplicity of the HTTP protocol, and thus, most REST APIs use that protocol to communicate – including Bubble.

What is HTTP?

When we talk about a protocol, we mean a strategy of communication. Think about it: when you interact with different types of media on the web, like web pages, videos, live streaming, online meetings and gaming, they all have one thing in common: data needs to be transferred from a server to your device in a format that the application you are using will recognize.

This is where protocols come in. HTTP is a protocol that dictates how information about (among other things) a website is transferred from a server to a browser. HTTP is a pull protocol, meaning that it is always initiated by a Client request – an API Server will never send you anything unless you ask for it.

api series.drawio
The Client makes an HTTP request, and the Server sends an HTTP response back – the Client is pulling the information.

As you can see from the illustration above, the full circle of an API interaction does not consist of one HTTP data transfer, but two: the request and response.

HTTP Methods

Ok, so one machine wants data from another machine. Naturally, we need specify somehow how we want to interact with the data on the remote Server. In Bubble you constantly Create, Read, Update and Delete records in your database, and with an API you’re doing the same thing, except the database is not your own.

So if we make a request to an external database using an HTTP request, we need to tell the server what we want to do. This is where HTTP methods come in.

You may already be familiar with the four most widely used HTTP methods used in REST APIs:

MethodWhat it’s used forBubble equivalent
GETRetrieve dataDo a Search for
POSTCreate new DataCreate a new Thing
PUT/PATCHEdit dataMake changes to a Thing
DELETEDelete DataDelete a Thing

You’ll recognize the similarities to Bubble: they’re interacting with a database just like the data sources and workflows you set up in your app.

HTTP Headers

The purpose of the Header in a http request and response is to provide all the metadata needed for the interaction to be successful. Metadata, in short, is data about data. It provides the structured information needed both in the request and the response for the Server and Client to understand each other.

Each line in this section is called a header, and consists of a key and a value. In the header you’ll find the HTTP method, the URL of the resource, the server we want to reach and other pieces of meta data,


The Body, both in the request and the response, contains the actual data being transferred. For the request, the body might contain information about some data you want to create: if you are creating a new Company, you may want to supply a name and an address for example.

For the response, the body will contain the data you asked for in a given format: usually JSON.

What the API interaction looks like

Now that we know that the API communicates with the HTTP protocol, and we know the different methods we can use, let’s check out what the actual request and response looks like: what information does the Client actually send to the server in order to get a response?

We’ll pretend we’re communicating with a CRM built on Bubble and we want to download a list of Companies from by making an API request to the Bubble.io server.

Keep in mind before we begin that the purpose of this section is not to teach you how to set up the call: we’ll get into that later. What we’re looking at now is what the different parts of the Request and Response actually mean. Also, both the request and response actually contain more data than this, but I want to avoid it getting too technical. We’ll finish each section with what the info might look like in a regular human interaction, to illustrate the simplicity of the http structure.

The Request

As the http request is a pull protocol, the initial step is the Client making the request to the Server:

API http request
The first stage of the interaction is the request.


The Authentication

The first part of the request is the Authorization. This point can be a little bit confusing: technically, we’re authenticating here (as we discussed in the previous article). But from the perspective of the Server it makes sense: we’d like to server to fetch the authorization (what this User has access to) for the Bearer of this token.

The Authorization header consists of the key Authorization: and a value combining the authorization type and the token.

Authorization: Bearer f9b5e00a0a54b39ab8da8758575d2bf2
GET /version-test/api/1.1/obj/company HTTP/1.1
Host: mybubbleapp.bubbleapps.io
User-Agent: PostmanRuntime/7.29.0
Accept: */*

The Bubble Data API uses Bearer token for authentication, and this value is created in the app’s API Settings:

bubble generate api token
Generating a token that gives full admin access to your Data API in Bubble is easily done in the app’s API settings.

Human equivalent: Hi, I’m Petter and this is my ID. Please give me access.

The path

The second part of the request consist of the METHOD followed by the the resource we want to reach. As we discussed in the previous article, Bubble automatically generates an endpoint for each Data Type exposed in the API settings. To make sure both the Client and the Server are using the exact same protocol, the HTTP version is added, and then the Server (host) we want to reach:

Authorization: Bearer f9b5e00a0a54b39ab8da8758575d2bf2
GET /version-test/api/1.1/obj/company HTTP/1.1
Host: mybubbleapp.bubbleapps.io
User-Agent: PostmanRuntime/7.29.0
Accept: */*

Hey, that wasn’t so hard! Even if you’re new to APIs, this is perfectly humanly readable and pretty easy to remember.

Human equivalent: Please send me information from this place using this line of communication

User-agent and Accept

Next up are some additional Headers that contain data that the Server might need in order to fulfill the request.

Authorization: Bearer f9b5e00a0a54b39ab8da8758575d2bf2
GET /version-test/api/1.1/obj/company HTTP/1.1
Host: mybubbleapp.bubbleapps.io
User-Agent: PostmanRuntime/7.29.0
Accept: */*

The User-Agent tells the Server what kind of application is making the request. In this example I’m using Postman, which is an application for working with and testing APIs. The User-agent consists of a <Product>/<Version> <extra info>. If I’m opening a website in a Firefox browser on my Mac right now, the User-agent in that HTTP request would be:

User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0

The reason this information is included is that the server sometimes needs to know the specific capabilities or limitations of the application sending the request in order to send a valuable response.

For example, when you visit a web page from a mobile device, the server will often send you to a separate mobile page instead of trying to show you the desktop version. If you make the request from an iPhone, the User-agent might look like this:

User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15

Human equivalent: I’m going to receive the information using this kind of software on this kind of device.

The Accept: */* tells the server what kind of content (expressed as MIME types) the Client is able to understand. The syntax of the request is <MIME type>/<MIME_subtype>. The asterisks in our example simply means we’ll accept anything (since the asterisk is a wildcard: we’ll accept any MIME type and any MIME subtype. Since we know that Bubble will respond with JSON, we don’t need to specify this, but if we wanted to, we could set this to Accept: application/json. Sometimes the server requires. that you specify this.

Human equivalent: I need the information to be written in this specific language.

Request summary

Awesome! So we’ve asked the server the following questions now:

  • Hi, I’m Petter and this is my passport. Please give me access. (Bearer token authentication)
  • Please send me information from this place using this line of communication (Method host/path protocol)
  • I’m going to receive the information using this kind of software on this kind of device (user-agent)
  • I need the information to be written in this specific language (application/json)

The response

Now let’s see what the server sends back. We’re now in this. part of the cycle:

API http response
The second stage of the interaction is the response.


Date: Fri, 21 Jan 2022 13:22:26 GMT
Content-Type: application/json

The two initial headers are pretty self-explanatory. The first line returns the datetime that the response was sent, and the second tells the Client that the body in the response is formatted as JSON.


Now, let’s check out what Bubble sent us back here:

    "response": {
        "cursor": 0,
        "results": [
                "Name": "Company 1",
                "ParentCompany": "1642462492940x820087251779539700",
                "Created Date": "2022-01-11T22:08:09.849Z",
                "Created By": "no_user",
                "Modified Date": "2022-01-21T13:21:40.175Z",
                "_id": "1641938889848x375174378968664770"
                "Name": "Company 2",
                "ParentCompany": "1642462492940x820087251779539700",
                "Created Date": "2022-01-11T22:08:17.444Z",
                "Created By": "no-user",
                "Modified Date": "2022-01-21T13:22:18.802Z",
                "_id": "1641938897444x315130275999650800"
                "Name": "Company 3",
                "Created Date": "2022-01-20T22:56:43.127Z",
                "Created By": "no_user",
                "Modified Date": "2022-01-21T13:21:56.049Z",
                "_id": "1642719403127x551877034548644800"
        "remaining": 0,
        "count": 3

Holy smokes, JSON is sweet! This is totally understandable. You’ll recognize the named fields from Bubble, including the unique ID that Bubble generates for each database record.

There are three terms in here that we can have a quick look at so as to understand everything in that response:

StringMeaningBubble equivalent
CursorShows the index of the first entry in the list, starting at zero (Company 1)Do a Search for:Companies:item#
RemainingThe number of entries remaining in the database after the last one (after Company 3)
CountThe total number of entries that match the query (including the ones displayed)Do a Search for:Companies:count

It quickly becomes obvious what these values are for: this can be used to set up pagination for the search result.

JavaScript objects

What we’re looking at here in the results array section the JSON format are JavaScript objects representing database entries in the Bubble database. They follow a logical hierarchical structure starting with an array (the list of Companies) that contains 3 objects (each Company) which again contains a list of names and values, such as:

"Name": "Company 2"

Again we can recognize the logic here. Since we’re fetching a list of Objects, Bubble’s endpoint points us towards the path obj for the Data API.

Also, since Bubble is built on JavaScript, Data Types are loaded into your browser as – you guessed it – JavaScript objects. What does that tell us? That the data returned from a JSON-friendly API will be formatted just like Bubble’s Data Type representation – in other words, the data is ready to be put to use anywhere in your app. If the Client in our example above was also a Bubble app, you would be able to source that data straight into a Repeating Group. Not because they’re both Bubble apps, but because Bubble already stores its data as JSON and is ready to accept data from almost any API source as a result.

We could take the data from our example above and put it straight into a Repeating Group using the API response as a Data Source:

Repeating Group showing data from the API Connector in a Bubble app.
Using the API Connector we can set the API response as a Data Source and view the Companies in a Repeating Group.


So you might ask; is there not a risk here? Doesn’t this mean that anyone can connect to the API and download data from my app. Well, yes and no. We do use the Bearer Authentication token to identify ourself as an authenticated User, and the Server authorizes us to access certain resources. It follows that this token needs to be kept absolutely secret – this is why you may have seen that API services offering tokens and/or API keys tend to make a big deal out of not showing it on the screen unless you ask for it.

But knowing that REST APIs are stateless and the authentication is sent every single time we make a request, the question then becomes: how do we know that it’s safe to transfer it via the internet? Isn’t it possible for someone to intercept the communication and steal the authentication token?

The answer to this goes back to the http protocol: when you visit a website, and whenever you use an API, you’ll see that the resource URL contains https. The s mean that the http request is encrypted with a TLS encryption (you may also know this as SSL, which is deprecated).

We go through this in-depth in the book The Ultimate Guide to Bubble Security, along with detailed guides on how to keep your Bubble.io app secure and private.

Ok, now that you know how a http-based REST API interaction is structured, let’s move on to the next part.

Support the site and keep it free ❤️

I love tech startups and the Bubble community, and have made it my mission to try and create content that’s valuable, easy to follow and entertaining.

Creating content next to full-time consulting work is time-consuming; if you’d like to support it and keep the site free for everyone, please consider buying me a coffee or becoming a supporting member.

Buy Me A Coffee

Follow me:
Bubble.io books

Learn Bubble the right way

Our professional Bubble books teach you how to plan, structure and build your applications right from the start.

5-star review stars

More Posts


January 20, 2023 at 21:23

Hi Peter,

I love your content! Your books are amazing – I am going through your performance book for the second time and it is just as good as the first time 6 months ago!

When using nested reusable elements within a page as well as utilizing multiple datasources in each one (inheriting from parent or pulling from URL), what is the best way to handle having multiple instances of the same API call in separate reusables? Do you recommend just having the call repeated in each or is there a way to only need to make the call once (assuming the data from parent element is not possible to pass all the way down from a common location)?


    Petter Amlie
    February 9, 2023 at 20:06

    Hi Tyler, sorry about the late reply, this was somehow marked as spam. Bubble is pretty clever about not repeating calls already made. Depending on what you’re sending it could be tricky to pass the information through multiple layers of reusable elements. I would guess Bubble handles it for you by only sending the call once.

Leave A Reply

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


Email icon

Useful articles and tips

Join the mailing list to get guides, opinions and articles on Bubble, no-code, automation and the tech industry.

We don't share your email address with anyone, and you can unsubscribe at any time.

You have successfully subscribed