B
Biflus Docs
biflus.com Get API key

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_namestringRequired

The client's own name (doubles as a person's name when type is Individual).

type"Individual" | "Company"Required

Determines which other fields make sense — see the note below.

emailstring
phonestring
contact_phonestring

Only accepted when type is Company — rejected on Individual clients.

colorstring

Auto-assigned for Company clients if omitted. Not auto-assigned for Individuals.

address, city, postal_code, countrystring
tax_idstring

VAT / 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_emailstring

A named contact person, set in the app. (contact_phone above is writable.)

streetstring

A 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 ids

Every invoice belonging to this client, as inv_… ids.

flaggedboolean

Set by the system's content check; you can't write it.

Created Date, Modified Datedate

ISO timestamps maintained automatically.

Best practices
  • 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 type before 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 _id on your side — it's what every invoice, and this client's own future updates, will reference.
Common mistakes
  • Don't set contact_phone on 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

GET/v1/clients available Paginated

Returns every client belonging to your company. See Pagination for limit/cursor.

limitquery param, number

Default 25, max 100.

cursorquery param, string

From 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)
Response
{
  "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

GET/v1/clients/:id available Fetch one 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, stringRequired

The 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)
Response
{
  "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

POST/v1/clients available 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, stringRequired
typebody, enumRequired

"Individual" or "Company".

email, phone, address…body, string

All 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)
Response
{
  "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

PATCH/v1/clients/:id available Partial update

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)
Response
{
  "data": {
    "_id": "client_a8f291",
    "company_name": "Acme Corp",
    "email": "newbilling@acme.com",
    "phone": "+44 20 7946 0958" /* … unchanged fields */
  }
}

Delete a client

DELETE/v1/clients/:id available Blocked if any invoice references this 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)
Response
{
  "deleted": true,
  "id": "client_a8f291"
}
{
  "error": "3 invoice(s) still exist for this client — a client with any invoice history can't be deleted"
}
This page is updated as the API changes. If something here doesn't match what you're seeing, that's a bug worth flagging to the Biflus team.