Blue has an API (Application Programming Interface), so you can build your own integrations if required.
Blue has 100% API coverage. This means that anything that you can do in any of our apps, you can do programmatically. We have a powerful GraphQL API that has a full playground where you can test your queries and is fully documented.
You can try the playground here:
api.blue.cc
The Blue API Playground where you can test your queries
We have also made a video tutorial that explains how you can leverage the Blue API.
To start using our API, click on your profile on the top right, and under the profile menu, you'll find the API tab.
In the API tab, click on the button "Generate a Token":
Provide a name for the token and set an expiration date if desired. If you set an expiration date, the API token will automatically stop working after that date.
After generation, you'll receive a Token ID and a Secret ID. The Token ID is your unique identifier for API access, while the Secret ID acts as a password, ensuring secure communication with Blue's API. Remember, the Secret ID is shown only once for security reasons, so store it safely to maintain access to your data through the API.
The Security Token is only shown once, so make sure you save it securely.
You have now successfully generated an API token developers can use for custom integrations into Blue.
Blue offers an API Playground to experiment with and test your API queries.
After generating your token, use the ▶️ button to enter the playground:
Press ▶️ to enter the API Playground
Next, you will have to enter your Secret Key, alongside the CompanyID and ProjectID:
Add your details under HTTP Headers
To find your CompanyID and ProjectID, you can check the URL of any project you can access. Both IDs are within the URL, as shown below:
https://app.blue.cc/company/{CompanyID}/projects/{ProjectID}/todo
Blue's APIs are self-documenting based on your custom data structure.
The API documentation and schema are seamlessly integrated within the playground, conveniently on the right side. This feature enables users to access comprehensive information about the API's capabilities, including available queries and mutations. A search function is provided for enhanced usability, allowing for quick and efficient query lookup. Users can also download the schema in JSON or SDL formats, facilitating offline reference and further analysis. This integration of documentation within the playground aims to provide developers a comprehensive and user-friendly experience.
The Blue API Documentation is build right into the playground
mutation CreateRecord {
createTodo(
input: {
todoListId:"TODOLISTID",
title: "Test",
position: 65535
}
) {
id
title
position
}
}
# Toggle Record Done Status
mutation ToggleRecordDoneStatus {
updateTodoDoneStatus(todoId: "ENTER RECORD ID") {
id
uid
position
title
text
html
startedAt
duedAt
timezone
color
cover
done
}
}
# Move Record To Another List
mutation MoveRecordToAnotherList {
editTodo(input: { todoId: "ENTER RECORD ID", todoListId: "ENTER LIST ID" }) {
id
uid
position
title
text
html
startedAt
duedAt
timezone
color
cover
done
todoList {
id
}
}
}
# Update Record Due Date
mutation UpdateRecordDueDate {
updateTodoDueDate(
todoId: "ENTER RECORD ID"
duedAt: "2024-03-08T16:59:59.999Z"
startedAt: "2024-03-04T17:00:00.000Z"
) {
id
uid
position
title
text
html
startedAt
duedAt
timezone
color
cover
done
todoList {
id
}
}
}
# Get List of Projects
query ProjectListQuery {
projectList(filter: { companyIds: ["ENTER COMPANY ID"] }) {
items {
id
uid
slug
name
description
archived
color
icon
createdAt
updatedAt
allowNotification
position
unseenActivityCount
todoListsMaxPosition
lastAccessedAt
isTemplate
automationsCount
totalFileCount
totalFileSize
todoAlias
}
pageInfo {
totalPages
totalItems
page
perPage
hasNextPage
hasPreviousPage
}
}
}
# Delete a Record
mutation DeleteARecord {
deleteTodo(input: { todoId: "ENTER RECORD ID" }) {
success
}
}
# Get List of Records Between a Start and Due Date
query ListOfRecordsBetweenAStartAndDueDate {
todoQueries {
todos(
filter: {
companyIds: ["ENTER COMPANY ID"],
startedAt: "2024-04-07T17:00:00.000Z"
dueEnd: "2024-04-10T16:59:59.999Z"
}
skip: 20
limit: 20
sort: [position_ASC]
) {
items {
id
uid
position
title
text
html
startedAt
duedAt
timezone
color
cover
done
}
pageInfo {
totalPages
totalItems
page
perPage
hasNextPage
hasPreviousPage
}
}
}
}
Get list of users in organisation
query GetListOfUsersInOrganisation {
companyUserList(companyId: "ENTER COMPANY ID") {
users {
id
uid
username
email
dateOfBirth
phoneNumber
firstName
lastName
fullName
isEmailVerified
jobTitle
locale
lastActiveAt
createdAt
updatedAt
isOnline
timezone
theme
}
pageInfo {
totalPages
totalItems
page
perPage
hasNextPage
hasPreviousPage
}
}
}
# Get List of Tags within Projects
query ListOfTagsWithinProjects {
tagList(filter: { projectIds: ["ENTER PROJECT ID"], excludeArchivedProjects: false }) {
items {
id
uid
title
color
project {
id
name
}
createdAt
updatedAt
}
pageInfo {
totalPages
totalItems
page
perPage
hasNextPage
hasPreviousPage
}
}
}
# Get List of Records within Project
query ListOfRecordsWithinProject {
todoQueries {
todos(
filter: { companyIds: ["ENTER COMPANY ID"], projectIds: ["ENTER PROJECT ID"] }
skip: 20
limit: 20
sort: [position_ASC]
) {
items {
id
uid
position
title
text
html
startedAt
duedAt
timezone
color
cover
done
}
pageInfo {
totalPages
totalItems
page
perPage
hasNextPage
hasPreviousPage
}
}
}
}
# Update Existing Record (Add Tag)
mutation UpdateExistingRecordAddTag {
setTodoTags(
input: {
todoId: "RECORDID"
tagIds: ["TAGID1", "TAGID2"]
}
)
}
# Get all records assigned to a specific user across all projects
query GetAllRecordsAssignedToASpecificUserAcrossAllProjects {
todoQueries {
todos(
filter: {
companyIds: ["ENTER COMPANY ID"]
assigneeIds: ["ENTER ASSIGNEE ID"]
}
skip: 20
limit: 20
sort: [position_ASC]
) {
items {
id
uid
position
title
text
html
startedAt
duedAt
timezone
color
cover
done
}
pageInfo {
totalPages
totalItems
page
perPage
hasNextPage
hasPreviousPage
}
}
}
}
# Update Existing Record (Single Line Text Custom Field)
mutation UpdateExistingRecordSingleLineTextCustomField {
setTodoCustomField(
input: {
todoId: "clmu9ec9301k4n01gz8v2n10u"
customFieldId: "cltzkh0wi02mv10w3f6t3sv6k"
text: "Test"
}
)
}
To get started with the Blue API, you need to set up the API endpoint in your code. The Blue API uses a GraphQL endpoint for making requests, which is typically https://api.blue.cc/graphql
. This endpoint URL should be used when making API requests to interact with the Blue API.
Authentication is required to access the Blue API. You'll need to obtain the necessary API keys, which include the X-Bloo-Token-ID
(your Blue token ID), X-Bloo-Token-Secret
(your Blue token secret), X-Bloo-Company-ID
(the ID or slug of your company), and X-Bloo-Project-ID
(the ID or slug of your project). These keys should be included in the headers of your API requests to authenticate and authorize your access to the Blue API.
The Blue API uses GraphQL, a query language that allows you to define specific queries and mutations to interact with the data. Queries are used to retrieve data from the API, while mutations are used to modify data. You need to define the necessary queries and mutations based on your requirements. For example, to retrieve a list of todos, you can use a query like:
query ListOfRecordsWithinProject {
todoQueries {
todos(
filter: { companyIds: ["your-company-id"], projectIds: ["your-project-id"] }
limit: 100
sort: [position_ASC]
) {
items {
id
title
}
}
}
}
To interact with the Blue API, you need to make HTTP requests to the GraphQL endpoint. Typically, you'll use the POST
method to send GraphQL queries and mutations. Include the necessary headers, including the authentication keys, in your requests. The request payload should include the GraphQL query or mutation and any required variables. Here's an example of making a request using Python's requests
library:
import requests
endpoint = "https://api.blue.cc/graphql"
headers = {
"X-Bloo-Token-ID": "your-token-id",
"X-Bloo-Token-Secret": "your-token-secret",
"X-Bloo-Company-ID": "your-company-id",
"X-Bloo-Project-ID": "your-project-id"
}
payload = {
"query": "your-graphql-query",
"variables": {"variable1": "value1", "variable2": "value2"}
}
response = requests.post(endpoint, json=payload, headers=headers)
After making a request to the Blue API, you'll receive a response containing JSON data with the requested information or the result of the mutation. Parse the JSON response to extract the relevant data and handle any errors or exceptions that may occur during the API request.
The Blue API supports pagination and filtering options for queries. You can use the limit
and skip
parameters to control the number of results returned and the starting point of the result set. Additionally, you can use the filter
parameter to specify criteria for filtering the results based on attributes like companyIds
and projectIds
.
Below is the code for a sample Python app that gets the complete list of records from a project, asks you to pick one, then gives you the list of tags and asks you to choose a tag. The record is then updated in Blue with the selected tag.
import requests
# Define your GraphQL endpoint
endpoint = "https://api.blue.cc/graphql"
# Define your GraphQL queries and mutation
query_todos = """
query ListOfRecordsWithinProject {
todoQueries {
todos(
filter: { companyIds: ["COMPANYID"], projectIds: ["PROJECTID"] }
limit: 100
sort: [position_ASC]
) {
items {
id
title
}
}
}
}
"""
query_tags = """
query ListOfTagsWithinProjects {
tagList(filter: { projectIds: ["PROJECTID"], excludeArchivedProjects: false }) {
items {
id
title
}
}
}
"""
mutation_update_todo = """
mutation UpdateExistingRecordAddTag($todoId: String!, $tagIds: [String!]!) {
setTodoTags(
input: {
todoId: $todoId
tagIds: $tagIds
}
)
}
"""
# Define the request payload
payload_todos = {
"query": query_todos
}
payload_tags = {
"query": query_tags
}
# Define the authentication headers
headers = {
"X-Bloo-Token-ID": "TOKENID",
"X-Bloo-Token-Secret": "TOKEN-SECRET",
"X-Bloo-Company-ID": "COMPANY-ID",
"X-Bloo-Project-ID": "PROJECT-ID"
}
# Make the POST request to the GraphQL endpoint with authentication headers
response_todos = requests.post(endpoint, json=payload_todos, headers=headers)
response_tags = requests.post(endpoint, json=payload_tags, headers=headers)
# Check the response status code
if response_todos.status_code == 200 and response_tags.status_code == 200:
# Request was successful
data_todos = response_todos.json()
data_tags = response_tags.json()
# Extract the 'items' list from the response data
items_todos = data_todos['data']['todoQueries']['todos']['items']
items_tags = data_tags['data']['tagList']['items']
# Print the list of todos
print("List of Todos:")
for index, item in enumerate(items_todos, start=1):
print(f"{index}. {item['title']}")
# Ask the user to choose a todo
todo_choice = int(input("Enter the number of the todo you want to categorize: "))
selected_todo = items_todos[todo_choice - 1]
# Print the list of tags
print("\nList of Tags:")
for index, item in enumerate(items_tags, start=1):
print(f"{index}. {item['title']}")
# Ask the user to choose tags
tag_choices = input("Enter the numbers of the tags you want to assign (comma-separated): ")
selected_tag_ids = [items_tags[int(choice) - 1]['id'] for choice in tag_choices.split(",")]
# Print the selected todo and tags
print("\nSelected Todo:")
print(selected_todo['title'])
print("\nSelected Tags:")
for tag_id in selected_tag_ids:
tag = next(item for item in items_tags if item['id'] == tag_id)
print(tag['title'])
# Update the selected todo with the selected tags
mutation_variables = {
"todoId": str(selected_todo['id']),
"tagIds": [str(tag_id) for tag_id in selected_tag_ids]
}
payload_update_todo = {
"query": mutation_update_todo,
"variables": mutation_variables
}
response_update_todo = requests.post(endpoint, json=payload_update_todo, headers=headers)
if response_update_todo.status_code == 200:
print("\nTodo updated successfully with the selected tags.")
else:
print("\nFailed to update the todo with the selected tags.")
print("Response:", response_update_todo.json())
else:
# Request failed
print("Request failed with status code:", response_todos.status_code, response_tags.status_code)