Categories
Groups for organizing items. Purely organizational — a category has no effect on pricing, tax, or invoice totals.
Fields you can set
A category is deliberately small — three settable fields, two of which fill themselves in.
namestringRequiredcolorstringA color name. Auto-assigned from Blue, Amber, Violet, Green, Cyan, Pink, or Orange if omitted.
key_letterstringThe 2-letter chip shown in the app. Auto-derived from name (uppercased) if omitted.
Read-only fields
Returned on every category but set by the system.
_idstring (id)The category's public id, e.g. cat_4b91fa. Pass it as an item's category.
companystring (id)Your company — scoping is automatic.
Created Date, Modified DatedateISO timestamps maintained automatically.
- Leave
key_letterunset the first time — the auto-derived initials usually look right, and you can alwaysPATCHit later if two categories collide. - Create categories before the items that reference them —
item.categoryneeds a real id, so there's no "create both at once" shortcut. - Keep the list short and stable. Categories are meant to be a handful of durable groupings, not a tag per item — if you find yourself creating one per item, an item field like
skuis probably the better fit.
- Don't delete a category before reassigning its items. Delete is blocked (409) while any item still references it — there's no cascade or force-delete option, by design.
- Don't assume
key_letteris unique. Nothing enforces it — two categories can end up with the same two-letter chip if you let both auto-derive from similar names. - Don't build a "category per client" or "category per invoice" pattern. Categories only ever attach to items — there's no client- or invoice-level equivalent.
List categories
limitquery param, numberDefault 25, max 100.
cursorquery param, stringFrom the previous page's pagination.next_cursor.
curl https://api.biflus.com/v1/categories \ -H "Authorization: Bearer sk_test_YOUR_API_KEY"
import requests
resp = requests.get(
"https://api.biflus.com/v1/categories",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/categories", {
headers: { "Authorization": "Bearer sk_test_YOUR_API_KEY" }
});
const data = await res.json();using System.Net.Http;
using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.biflus.com/v1/categories");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "sk_test_YOUR_API_KEY");
var response = await client.SendAsync(request);
var data = await response.Content.ReadAsStringAsync();package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.biflus.com/v1/categories", nil)
req.Header.Set("Authorization", "Bearer sk_test_YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.biflus.com/v1/categories"))
.header("Authorization", "Bearer sk_test_YOUR_API_KEY")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); require 'net/http'
require 'json'
uri = URI("https://api.biflus.com/v1/categories")
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer sk_test_YOUR_API_KEY'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){ "data": [ { "_id": "cat_4b91fa", "name": "General Services", "key_letter": "GS", "color": "Violet" } ], "pagination": { "count": 1, "remaining": 0, "next_cursor": null } }
Get a category
idpath param, stringRequiredThe category's _id.
curl https://api.biflus.com/v1/categories/cat_4b91fa \ -H "Authorization: Bearer sk_test_YOUR_API_KEY"
import requests
resp = requests.get(
"https://api.biflus.com/v1/categories/cat_4b91fa",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/categories/cat_4b91fa", {
headers: { "Authorization": "Bearer sk_test_YOUR_API_KEY" }
});
const data = await res.json();using System.Net.Http;
using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.biflus.com/v1/categories/cat_4b91fa");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "sk_test_YOUR_API_KEY");
var response = await client.SendAsync(request);
var data = await response.Content.ReadAsStringAsync();package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.biflus.com/v1/categories/cat_4b91fa", nil)
req.Header.Set("Authorization", "Bearer sk_test_YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.biflus.com/v1/categories/cat_4b91fa"))
.header("Authorization", "Bearer sk_test_YOUR_API_KEY")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); require 'net/http'
require 'json'
uri = URI("https://api.biflus.com/v1/categories/cat_4b91fa")
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer sk_test_YOUR_API_KEY'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){ "data": { "_id": "cat_4b91fa", "name": "General Services", "key_letter": "GS", "color": "Violet" } }
{ "error": "itemscategory not found" }
Create a category
key_letter defaults to the first letters of each word in name ("General Services" → "GS"), or the first two letters of a single word.
curl -X POST https://api.biflus.com/v1/categories \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "General Services"}'import requests
resp = requests.post(
"https://api.biflus.com/v1/categories",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
json={"name": "General Services"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/categories", {
method: "POST",
headers: {
"Authorization": "Bearer sk_test_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({ name: "General Services" })
});
const data = await res.json();using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.biflus.com/v1/categories");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "sk_test_YOUR_API_KEY");
request.Content = new StringContent("{"name": "General Services"}", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var data = await response.Content.ReadAsStringAsync();package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"name": "General Services"}`)
req, _ := http.NewRequest("POST", "https://api.biflus.com/v1/categories", body)
req.Header.Set("Authorization", "Bearer sk_test_YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.biflus.com/v1/categories"))
.header("Authorization", "Bearer sk_test_YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{"name": "General Services"}"))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); require 'net/http'
require 'json'
uri = URI("https://api.biflus.com/v1/categories")
req = Net::HTTP::Post.new(uri)
req['Authorization'] = 'Bearer sk_test_YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{"name": "General Services"}'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){ "data": { "_id": "cat_4b91fa", "name": "General Services", "key_letter": "GS", "color": "Violet" } }
Update a category
Only send the field(s) you're changing — name, color, and key_letter can each be updated independently.
curl -X PATCH https://api.biflus.com/v1/categories/cat_4b91fa \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Professional Services"}'import requests
resp = requests.patch(
"https://api.biflus.com/v1/categories/cat_4b91fa",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
json={"name": "Professional Services"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/categories/cat_4b91fa", {
method: "PATCH",
headers: {
"Authorization": "Bearer sk_test_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({ name: "Professional Services" })
});
const data = await res.json();using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Patch, "https://api.biflus.com/v1/categories/cat_4b91fa");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "sk_test_YOUR_API_KEY");
request.Content = new StringContent("{"name": "Professional Services"}", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var data = await response.Content.ReadAsStringAsync();package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"name": "Professional Services"}`)
req, _ := http.NewRequest("PATCH", "https://api.biflus.com/v1/categories/cat_4b91fa", body)
req.Header.Set("Authorization", "Bearer sk_test_YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.biflus.com/v1/categories/cat_4b91fa"))
.header("Authorization", "Bearer sk_test_YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("PATCH", HttpRequest.BodyPublishers.ofString("{"name": "Professional Services"}"))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); require 'net/http'
require 'json'
uri = URI("https://api.biflus.com/v1/categories/cat_4b91fa")
req = Net::HTTP::Patch.new(uri)
req['Authorization'] = 'Bearer sk_test_YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{"name": "Professional Services"}'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){ "data": { "_id": "cat_4b91fa", "name": "Professional Services", "key_letter": "GS", "color": "Violet" } }
Delete a category
Reassign or delete the items using this category first.
curl -X DELETE https://api.biflus.com/v1/categories/cat_4b91fa \ -H "Authorization: Bearer sk_test_YOUR_API_KEY"
import requests
resp = requests.delete(
"https://api.biflus.com/v1/categories/cat_4b91fa",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/categories/cat_4b91fa", {
method: "DELETE",
headers: { "Authorization": "Bearer sk_test_YOUR_API_KEY" }
});
const data = await res.json();using System.Net.Http;
using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Delete, "https://api.biflus.com/v1/categories/cat_4b91fa");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "sk_test_YOUR_API_KEY");
var response = await client.SendAsync(request);
var data = await response.Content.ReadAsStringAsync();package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.biflus.com/v1/categories/cat_4b91fa", nil)
req.Header.Set("Authorization", "Bearer sk_test_YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.biflus.com/v1/categories/cat_4b91fa"))
.header("Authorization", "Bearer sk_test_YOUR_API_KEY")
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); require 'net/http'
require 'json'
uri = URI("https://api.biflus.com/v1/categories/cat_4b91fa")
req = Net::HTTP::Delete.new(uri)
req['Authorization'] = 'Bearer sk_test_YOUR_API_KEY'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){ "deleted": true, "id": "cat_4b91fa" }
{ "error": "4 item(s) still use this category — reassign them to a different category first" }