Clients
The people or companies you invoice. Every invoice, and every category an item can reference, hangs off a client or is scoped to your company the same way — clients are usually the first thing you create.
Fields you can set
These are the fields you can send on create and update. A client object also carries read-only fields the app fills in.
company_namestringRequiredThe client's own name (doubles as a person's name when type is Individual).
type"Individual" | "Company"RequiredDetermines which other fields make sense — see the note below.
emailstringphonestringcontact_phonestringOnly accepted when type is Company — rejected on Individual clients.
colorstringAuto-assigned for Company clients if omitted. Not auto-assigned for Individuals.
address, city, postal_code, countrystringtax_idstringVAT / tax number.
Read-only fields
Returned on every client but not settable through the API — they're managed inside the Biflus app or by the system.
_idstring (id)The client's public id, e.g. client_a8f291. Use it to address this client in every other call.
companystring (id)The company this client belongs to — always your own; scoping is automatic.
contact_name, contact_emailstringA named contact person, set in the app. (contact_phone above is writable.)
streetstringA separate street line kept alongside address, set in the app.
logo/imgstring (url)The client's logo image, if one was uploaded in the app.
invoicesarray of idsEvery invoice belonging to this client, as inv_… ids.
flaggedbooleanSet by the system's content check; you can't write it.
Created Date, Modified DatedateISO timestamps maintained automatically.
- Send only the fields you're changing on
PATCH— everything else is left as-is, so there's no need to re-fetch and resend the whole record. - Set
typebefore anything else in your create call — it changes which other fields are valid, and Company clients get a free auto-assigned color if you skip it. - Store the returned
_idon your side — it's what every invoice, and this client's own future updates, will reference.
- Don't set
contact_phoneon an Individual. Create silently drops it; update rejects it with a 400 — the two write paths behave differently on purpose, but it's easy to be surprised by create's silence. - Don't try to delete a client with any invoice history. Even a single old Draft blocks it (409) — delete or reassign the invoices first, not the other way around.
- Don't assume every write goes through instantly. Every client write runs the same content-moderation check as the main app; a 422 means it was flagged, not that your request was malformed.
List clients
Returns every client belonging to your company. See Pagination for limit/cursor.
limitquery param, numberDefault 25, max 100.
cursorquery param, stringFrom the previous page's pagination.next_cursor.
curl https://api.biflus.com/v1/clients?limit=2 \ -H "Authorization: Bearer sk_test_YOUR_API_KEY"
import requests
resp = requests.get(
"https://api.biflus.com/v1/clients",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
params={"limit": 2},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/clients?limit=2", {
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/clients?limit=2");
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/clients?limit=2", 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/clients?limit=2"))
.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/clients?limit=2")
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": "client_a8f291", "company_name": "Acme Corp", "type": "Company" /* … */ }, { "_id": "client_9c72de", "company_name": "Marina Popescu", "type": "Individual" /* … */ } ], "pagination": { "count": 2, "remaining": 6, "next_cursor": "Mg==" } }
Get a client
404s if the id belongs to a different account, not just if it doesn't exist — the same response either way, so a wrong key never reveals whether a record exists.
idpath param, stringRequiredThe client's _id from a create or list call.
curl https://api.biflus.com/v1/clients/client_a8f291 \ -H "Authorization: Bearer sk_test_YOUR_API_KEY"
import requests
resp = requests.get(
"https://api.biflus.com/v1/clients/client_a8f291",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/clients/client_a8f291", {
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/clients/client_a8f291");
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/clients/client_a8f291", 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/clients/client_a8f291"))
.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/clients/client_a8f291")
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": "client_a8f291", "company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK", "color": "Indigo" } }
{ "error": "client not found" }
Create a client
Only company_name and type are required. Every write runs through the same content-moderation gate the main app and Flus AI use — see 422.
company_namebody, stringRequiredtypebody, enumRequired"Individual" or "Company".
email, phone, address…body, stringAll optional. See the full field reference above.
curl -X POST https://api.biflus.com/v1/clients \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK"}'import requests
resp = requests.post(
"https://api.biflus.com/v1/clients",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
json={"company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/clients", {
method: "POST",
headers: {
"Authorization": "Bearer sk_test_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
company_name: "Acme Corp",
type: "Company",
email: "billing@acme.com",
country: "UK"
})
});
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/clients");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "sk_test_YOUR_API_KEY");
request.Content = new StringContent("{"company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK"}", 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(`{"company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK"}`)
req, _ := http.NewRequest("POST", "https://api.biflus.com/v1/clients", 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/clients"))
.header("Authorization", "Bearer sk_test_YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{"company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK"}"))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); require 'net/http'
require 'json'
uri = URI("https://api.biflus.com/v1/clients")
req = Net::HTTP::Post.new(uri)
req['Authorization'] = 'Bearer sk_test_YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{"company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK"}'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){ "data": { "_id": "client_a8f291", "company_name": "Acme Corp", "type": "Company", "email": "billing@acme.com", "country": "UK", "color": "Indigo" } }
{ "error": "This has been sent for manual review and cannot be created automatically right now." }
Update a client
Only send the fields you're changing; everything else is left as-is. Only the fields listed in the table above are ever accepted.
curl -X PATCH https://api.biflus.com/v1/clients/client_a8f291 \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "newbilling@acme.com", "phone": "+44 20 7946 0958"}'import requests
resp = requests.patch(
"https://api.biflus.com/v1/clients/client_a8f291",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
json={"email": "newbilling@acme.com", "phone": "+44 20 7946 0958"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/clients/client_a8f291", {
method: "PATCH",
headers: {
"Authorization": "Bearer sk_test_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({ email: "newbilling@acme.com", phone: "+44 20 7946 0958" })
});
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/clients/client_a8f291");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "sk_test_YOUR_API_KEY");
request.Content = new StringContent("{"email": "newbilling@acme.com", "phone": "+44 20 7946 0958"}", 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(`{"email": "newbilling@acme.com", "phone": "+44 20 7946 0958"}`)
req, _ := http.NewRequest("PATCH", "https://api.biflus.com/v1/clients/client_a8f291", 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/clients/client_a8f291"))
.header("Authorization", "Bearer sk_test_YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("PATCH", HttpRequest.BodyPublishers.ofString("{"email": "newbilling@acme.com", "phone": "+44 20 7946 0958"}"))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); require 'net/http'
require 'json'
uri = URI("https://api.biflus.com/v1/clients/client_a8f291")
req = Net::HTTP::Patch.new(uri)
req['Authorization'] = 'Bearer sk_test_YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{"email": "newbilling@acme.com", "phone": "+44 20 7946 0958"}'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){ "data": { "_id": "client_a8f291", "company_name": "Acme Corp", "email": "newbilling@acme.com", "phone": "+44 20 7946 0958" /* … unchanged fields */ } }
Delete a client
A client with any invoice history — draft or otherwise — can't be deleted. Remove or reassign those invoices first.
curl -X DELETE https://api.biflus.com/v1/clients/client_a8f291 \ -H "Authorization: Bearer sk_test_YOUR_API_KEY"
import requests
resp = requests.delete(
"https://api.biflus.com/v1/clients/client_a8f291",
headers={"Authorization": "Bearer sk_test_YOUR_API_KEY"},
)
print(resp.json())const res = await fetch("https://api.biflus.com/v1/clients/client_a8f291", {
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/clients/client_a8f291");
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/clients/client_a8f291", 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/clients/client_a8f291"))
.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/clients/client_a8f291")
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": "client_a8f291" }
{ "error": "3 invoice(s) still exist for this client — a client with any invoice history can't be deleted" }