Data API

The Data API allows one-click creation of a RESTful interface to some or all of your application's data. You can let yourself or your users read, modify, and delete individual data items, search for data using a flexible query language, and create and bulk upload new things. Access to the API is controlled via Bubble's privacy rules, which provide flexible controls over who can do what. The Data API is turned off by default. To enable it, check the the box 'This app exposes a Data API' in the API section of the Settings Tab. Once checked, you will see a list of all custom types in your app, and you can select them one-by-one to expose them via the API. Privacy rules are applied in the context of the authentication you're using. If you're making calls with an API Token, you will be reading the data as an admin user and can access all fields for a given thing. If you're making a call using a token obtained via a sign in call, or via the OAuth 2.0 flow, what you can see and do via the API is limited by the rules in the Privacy section of the data tab. This lets you safely share your API with your users without given them more access than they should have. When viewing data in the API, the privacy rules that govern which items will show up in searches, and which fields on those items are visible, are the same as the rules for viewing data when building your app in the editor: the 'Find this in searches' permission governs which items will show up in queries, and the 'View all fields' permission grants access to fields. When modifying data via the API, there are three new permissions that only become visible once a data type is exposed: 'Modify via API', 'Delete via API', and 'Create via API'. These permissions only govern the Data api; they do not have any impact on the Workflow API. They are turned off by default, so to let a user modify data via the API, you must explicitly grant them via a privacy rule. (If you are accessing the API as an administrator, you have all permissions by default, including these).

General Data Endpoint

The general endpoint to get data from Bubble follows this pattern: https://appname.bubbleapps.io/api/1.1/obj/typename or https://yourdomain.com/api/1.1/obj/typename obj is for object. typename is the type of thing you want to retrieve. The general rule to figure out the typename for a given type is as follows: – Remove the spaces of the caption. – Use lowercase letters. For example, if a type of thing is defined in the Bubble Editor as 'Rental Unit,' make calls to https://appname.bubbleapps.io/api/1.1/obj/rentalunit When two types in the app share a similar caption, the first one that matches the typename of the endpoint will be used. We strongly recommend using unique, non-ambiguous captions for each data type, especially when using the Bubble Data API. You can either get a given thing with an ID or perform a search. The field names for Things queried through the Data endpoint will depend on the "Display fields instead of id for key names" checkbox in the API Settings tab. - If you are using Display fields, then the field names will match a sanitized version of the Display name for your fields. - Otherwise, they will be a bubble-generated ID resembling "fieldname_fieldtype" This setting also affects the field names used when modifying things or creating things, and might result in an error if using a field name that does not match the right formatting.

Retrieve a thing by ID

If you already know the unique_id of a thing, perhaps from a previous call, you can get the thing from the server using this endpoint. A unique ID usually looks like 1449154312665x293260311940684900. GET https://appname.bubbleapps.io/api/1.1/obj/typename/unique_id This will return the raw JSON object after going through the privacy rules. If the case where unique_id doesn't exist in the application database, the call will return a 400 error, 'MISSING_DATA.'

Note: Our GET API calls have a limit of 50,000 items (10 million for Dedicated).

Modify a thing by ID

To modify a thing, send a PATCH request to the same endpoint you use to retrieve it. The body of the request should be a JSON object with a list of keys and values to modify. The keys should match the names of the keys returned via a GET request, and the values should be in the format described in the Sending Data section. PATCH https://appname.bubbleapps.io/api/1.1/obj/typename/unique_id { "key1": value, "key2": value } Using this endpoint requires the 'Modify via API' permission. The privacy rule will be checked both before the modification to confirm that the user has permission to modify this thing, and after the modification to confirm that the modification was valid. We do not permit a user to modify a thing in a way that would take away that user's ability to perform further modifications. If the modification is successful, Bubble will respond with a 204 status code, and no body.

Replace a thing by ID

To replace a thing, send a PUT request to the same endpoint you use to retrieve it. The body of the request should be a JSON object to replace the existing object with. The keys should match the names of the keys returned via a GET request, and the values should be in the format described in the Sending Data section. Note that any field not included in the PUT request will be deleted, included built in fields such as 'Created Date', so use with caution. See also 'Modify a thing by ID' above for a way of just changing specific fields. PUT https://appname.bubbleapps.io/api/1.1/obj/typename/unique_id { "key1": value, "key2": value } Using this endpoint requires the 'Modify via API' permission. The privacy rule will be checked both before the replacement to confirm that the user has permission to modify this thing, and after the replacement to confirm that the new thing is valid. We do not permit a user to modify a thing in a way that would take away that user's ability to perform further modifications. If the replace is successful, Bubble will respond with a 204 status code, and no body.

Delete a thing by ID

To delete a thing, send a DELETE request to the same endpoint you use to retrieve it. DELETE https://appname.bubbleapps.io/api/1.1/obj/typename/unique_id Using this endpoint requires the 'Delete via API' permission. If the deletion is successful, Bubble will respond with a 204 status code, and no body.

Create a new thing

To create a thing, send a POST request to the /typename endpoint for the type of thing you want to create. The body of the request should be a JSON object to use as the new thing. The keys should match the names of the keys returned via a GET request for that type of thing, and the values should be in the format described in the Sending Data section. Bubble will automatically add built-in fields such as 'Created Date', as well as any default values defined for fields that were not explicitly initialized. When creating a new user, there are two special fields, 'email' and 'password', that initialize the user's log in information. 'email' is a required field; 'password' is optional. POST https://appname.bubbleapps.io/api/1.1/obj/typename { "key1": value, "key2": value } Using this endpoint requires the 'Create via API' permission. The privacy rule will be checked on the new data for the thing, and the creation attempt will be rejected if Bubble does not find a matching privacy rule that allows the creation to happen. If the creation is successful, Bubble will respond with a 201 status code, and a body consisting of a JSON object with a 'status' field set to 'success' and a 'id' field set to the unique id of the newly created object.

Bulk create new things

If you need to create many new things in a single operation, you can do it more efficiently via sending a POST request to the /typename/bulk endpoint. The body of this request should be a text document with one new object to create per line. The objects should be in JSON format, without any newlines; the keys and values should be the same as when creating a single thing. Note that the 'Content-Type' header of the request should be text/plain, not application/json. The maximum number of items that can be created via a single bulk request is currently 1000. There is also a limit of 4 minutes for the request to complete; if it takes longer than 4 minutes, items that have not yet been created will be marked as errors in the response. Creation speed is determined by the amount of available capacity your app has, as well as the size of the items that you are creating. Note that bulk creation can consume a lot of application capacity, so we recommend that if your app is being used in production and capacity is limited, that you test bulk creation in smaller chunks and work your way up. POST https://appname.bubbleapps.io/api/1.1/obj/typename/bulk {"key1": value, "key2": value} {"key1": value, "key2": value} Using this endpoint requires the 'Create via API' permission. The privacy rule will be checked on the new data for each new thing, and the creation attempt will be rejected if Bubble does not find a matching privacy rule that allows the creation to happen. If some things are rejected and some are accepted, the accepted items will be created. The response body from this call is a text/plain document with one line per thing in the original request. Each line consists of a JSON object, with a 'status' field indicating whether or not the creation was successful. On success, the status will be 'success', and the object will contain an 'id' field with the id of the newly-created object. On failure, the status will be 'error', and the object will contain additional fields indicating why the creation attempt failed. If every object in the original request was successfully created, the status code of the response will be 200; if at least one creation attempt failed, the status code will be an error status code. Note that under certain circumstances, like an overall system failure or the app being completely out of capacity, you may get a generic error response that does not have individual lines for each object.

Getting a list of things and search

Use this call to retrieve a list of things of a given type, optionally using search constraints. The general URL looks like https://appname.bubbleapps.io/api/1.1/obj/typename Add parameters directly in the URL as a querystring. It can be limit, cursor (Pagination), constraints (Search constraints), sort_field, and descending (Sorting options). In most search requests, you will use field names. The logic behind the match between field names in the Bubble app and in the request is similar to the one that applies to types. The general rule to figure out the field_name for a given field is as follows: – Remove the spaces of the caption. – Use lowercase letters. You can also use the name of the field that is returned in the objects. This is the way the field is represented in the app behind the scenes. In the case where no field matches the field_name of the request, the server will return a 400 error. If two fields for the current type match the field_name, the first one will be used.

Pagination

By default, all GET requests return the first 100 items in the list. Our API supports the parameters cursor and limit for pagination. Use limit to specify the number of items you want in the response. The default and maximum allowed is 100. Use cursor to specify where to start. At the end of each GET response, three values are returned that let you know where you are in the list: – cursor: This is the rank of the first item in the list. It equals the cursor you sent, if any. – count: This is the number of items in the current response. It is the minimum between the actual length of the list and the limit you sent or 100 if you did not specify a limit. – remaining: This is the number of remaining items after the current response. Use this for the next call.

Search constraints

Refine the list that is returned by the Data API with search constraints, exactly as you define a search in Bubble. To do so, pass a constraints parameter with the request. This parameter should be an array of constraints, e.g., objects with a key, constraint_type, and most of the time a value. If it is in the URL, it should be stringified and URL-encoded. key: This is the field name the constraint applies to. You can also use the reserved key _all for a full-text search in the database. constraint_type: This is the type of constraint you want to apply. It can be: – equals or not equal Use to test strict equality, for all field types. – is_empty or is_not_empty Use to test whether a thing's given field is empty or not, for all field types. – text contains or not text contains Use to test whether a text field contains a string, for text fields only. – greater than or less than Use to compare a thing's field value relative to a string or number, for text, number, and date fields. – in or not in Use to test whether a thing's field is in a list or not, for all field types. – contains or not contains Use to test whether a list field contains an entry or not, for list fields only. – empty or not empty Use to test whether a list field is empty or not, for list fields only. – geographic_search Use to test if the current thing is within a radius from a central address. To use this, the value sent with the constraint must have an address and a range. See below. value: This is the value the constraint should compare to. It can be a string, number, list, etc., depending on the field type defined by the key in the current constraint. If the type of the value isn't correct, Bubble returns a 400 error, 'INVALID_DATA.' A particular case of a key of type address and a constraint_type set to geographic_search, the value should be an object with the following keys: –origin_address: The central address that defines the center of the search, which should be a string address. –range: The range of the radius, defined in miles or kilometers, depending on the unit. –unit: The unit to use for the search. It can be miles (default) or km. Constraints with an undefined value are ignored. Do not use '_id' as a key for a constraint. Instead, use the call that retrieves a thing by ID. See above. For example, if you're looking for all 'coffeeshops' located within 10 miles of New York, whose 'name' contains 'cafe,' you will send a constraint parameter as follows: constraints = [ { "key": "name", "constraint_type": "text contains", "value": "cafe" } , { "key": "address", "constraint_type": "geographic_search", "value": { "range":10, "origin_address":"New York" } } ] or URL-encoded: constraints=%5B%7B%22key%22%3A%22name%22%2C%22constraint_type%22%3A%22text%20contains%22%2C%20%22value%22%3A%22cafe%22%7D%2C%7B%22key%22%3A%22address%22%2C%22constraint_type%22%3A%22geographic_search%22%2C%22value%22%3A%7B%22range%22%3A10%2C%22origin_address%22%3A%22New%20York%22%7D%7D%5D The full URL would look like: https://coffeesearcher.bubbleapps.io/api/1.1/obj/coffeeshops?api_token=YOUR_API_TOKEN&constraints=%5B%7B%22key%22%3A%22name%22%2C%22constraint_type%22%3A%22text%20contains%22%2C%20%22value%22%3A%22cafe%22%7D%2C%7B%22key%22%3A%22address%22%2C%22constraint_type%22%3A%22geographic_search%22%2C%22value%22%3A%7B%22range%22%3A10%2C%22origin_address%22%3A%22New%20York%22%7D%7D%5D&sort_field=name

Sorting options

You can control how the list is sorted using two parameters: sort_field and descending. sort_field: Specify the field to use for sorting. Either use a field defined for the current type or use _random_sorting to get the entries in a random order. When the field's type is geographic address, you need to add another parameter geo_reference and provide an address as a string. See Sending data for more information. descending: This parameter can either be true or false (default). To define more than one sorting field, add an array additional_sort_fields, which should contain objects of the similar type as above, i.e., with sort_field and descending. If the first sort setting is random, the entries in the array additional_sort_fields will be ignored.