Customer Files
Manage sales and billing dossiers with initial charges, recurring subscriptions, and licence line items.
Customer files are the central sales and billing dossiers. A file belongs to either a Customer or a Prospect (polymorphic fileable). Each file can have three types of line items:
- Initials (
customer-files/initials): one-time charges - Recurrings (
customer-files/recurrings): periodic subscriptions - Licences (
customer-files/licences): licence-based billing
Model Properties
Customer File (Main)
| Property | Type | Required | Description |
|---|---|---|---|
id |
integer | auto | Unique identifier |
fileable_type |
string | Yes | Owning entity type: customer or prospect (converted to PHP class on save) |
fileable_id |
integer | Yes | ID of the owning customer or prospect |
user_id |
integer | auto | FK to users. Set to the authenticated user |
name |
string | No | Label for this file (e.g. project or site name) |
site |
string | No | Site description or identifier |
status_id |
integer | No | FK to customer_file_statuses. Default: 4 (in progress) |
payer_id |
integer | No | FK to customers. The entity that pays the invoices (if different from the fileable) |
payer_reference |
string | No | Reference used on the payer's invoices |
payer_amount |
decimal | No | Fixed amount billed to the payer |
salesRep_id |
integer | No | FK to users. Assigned sales representative |
techRep_id |
integer | No | FK to users. Assigned technical representative |
salesAdmin_id |
integer | No | FK to users. Assigned sales administrator |
manager_id |
integer | No | FK to users. Assigned manager |
technicalManager_id |
integer | No | FK to users. Assigned technical manager |
businessFinder_id |
integer | No | FK to users. The user who brought in this business |
batch_id |
integer | No | FK to batches. Billing batch assignment |
contact_ids |
array | No | Array of contact IDs to sync to this file (not stored as a column, handled via pivot) |
paymentMethod_id |
integer | No | FK to payment_methods. Default payment method |
mandate_identification |
string | No | SEPA mandate reference |
mandate_signature_date |
date | No | Date of mandate signature |
customer_bank_details_id |
integer | No | FK to customer_bank_details |
services_start |
date | No | Date when services start |
services_stop |
date | No | Date when services end |
first_invoice |
date | No | Date of the first invoice |
billing_next |
date | No | Next scheduled billing date |
billing_frequency |
integer | No | Billing frequency in months (values: 1, 2, 3, 4, 6, 12, 24, 36) |
technical_start_date |
date | No | Technical go-live date |
rate_land_line |
decimal | No | Rate multiplier for landline calls (default: 1) |
rate_mobile |
decimal | No | Rate multiplier for mobile calls (default: 1) |
rate_special |
decimal | No | Rate multiplier for special numbers (default: 1) |
rate_fax |
decimal | No | Rate multiplier for fax calls (default: 1.2) |
rate_international_land_line |
decimal | No | Rate multiplier for international landline calls (default: 2) |
rate_international_mobile |
decimal | No | Rate multiplier for international mobile calls (default: 1.4) |
price_min_land_line |
decimal | No | Minimum per-minute price for landline calls |
price_min_mobile |
decimal | No | Minimum per-minute price for mobile calls |
price_min_special |
decimal | No | Minimum per-minute price for special numbers |
price_min_fax |
decimal | No | Minimum per-minute price for fax |
price_min_international |
decimal | No | Minimum per-minute price for international calls |
charge_over60min |
boolean | No | Whether to charge calls over 60 minutes (default: true) |
charge_over99numbers |
boolean | No | Whether to charge when there are more than 99 destination numbers |
charge_over99file_level |
boolean | No | Apply the 99-number rule at file level (not line level) |
credit |
decimal | No | Credit balance for this file |
show_consumptions_on_invoices |
boolean | No | Whether to show call consumptions on invoices (default: true) |
comment |
text | No | Internal notes |
finance_option1_duration |
integer | No | Duration (months) for finance option 1 |
finance_option1_amount |
decimal | No | Amount for finance option 1 |
finance_option2_duration |
integer | No | Duration (months) for finance option 2 |
finance_option2_amount |
decimal | No | Amount for finance option 2 |
finance_option3_duration |
integer | No | Duration (months) for finance option 3 |
finance_option3_amount |
decimal | No | Amount for finance option 3 |
finance_option4_duration |
integer | No | Duration (months) for finance option 4 |
finance_option4_amount |
decimal | No | Amount for finance option 4 |
finance_option5_duration |
integer | No | Duration (months) for finance option 5 |
finance_option5_amount |
decimal | No | Amount for finance option 5 |
created_at |
datetime | auto | Creation timestamp |
updated_at |
datetime | auto | Last update timestamp |
Customer File Initial (One-time Charges)
| Property | Type | Required | Description |
|---|---|---|---|
id |
integer | auto | Unique identifier |
customer_file_id |
integer | Yes | FK to customer_files |
item_id |
integer | Yes | FK to items (catalog item) |
quantity |
numeric | Yes | Quantity (must be > 0) |
label |
string | No | Custom label. Defaults to the item description if not set |
line_key |
string | auto | Unique line key linking this item to its invoice line. Read-only |
invoice_id |
integer | auto | FK to invoices. Set when the item is invoiced. Read-only |
buying_price_without_tax |
decimal | No | Buying price (cost) per unit, excl. tax |
exploitation_fees |
decimal | No | Additional exploitation/service fees |
selling_price_without_tax |
decimal | No | Selling price per unit, excl. tax |
discount_rate |
decimal | No | Discount rate (e.g. 0.1 = 10%) |
guarantee_expiration_date |
date | No | Date when the product guarantee expires |
delivered_at |
date | No | Actual delivery date |
dispatched_at |
date | No | Dispatch/shipping date |
dob |
date | No | Date of birth (used for certain insurance or age-related products) |
charge_after_date |
date | No | Do not invoice before this date |
paused |
boolean | No | Whether billing for this item is paused |
report |
boolean | No | Whether this item is reported to the next billing cycle |
has_dispatch |
boolean | No | Whether this item requires dispatch |
has_delivery |
boolean | No | Whether this item requires delivery |
dispatched |
boolean | No | Whether the item has been dispatched |
delivered |
boolean | No | Whether the item has been delivered |
created_at |
datetime | auto | Creation timestamp |
updated_at |
datetime | auto | Last update timestamp |
Customer File Recurring (Subscriptions)
| Property | Type | Required | Description |
|---|---|---|---|
id |
integer | auto | Unique identifier |
customer_file_id |
integer | Yes | FK to customer_files |
item_id |
integer | Yes | FK to items (catalog item) |
quantity |
numeric | Yes | Quantity (must be > 0) |
label |
string | No | Custom label. Defaults to the item description if not set |
line_key |
string | auto | Unique line key. Read-only |
service_start |
date | No | Planned service start date |
service_start_real |
date | No | Actual service start date |
service_stop |
date | No | Service end date (when terminated) |
first_invoice |
date | No | Date of the first invoice for this recurring item |
last_invoice |
date | No | Date of the last invoice for this recurring item |
current_month |
date | No | Current billing month marker |
month_minus1 |
date | No | Previous month billing marker |
month_minus2 |
date | No | Two months prior billing marker |
month_minus3 |
date | No | Three months prior billing marker |
dispatched_at |
date | No | Dispatch/shipping date |
delivered_at |
date | No | Delivery date |
commitment_expiry_date |
date | No | Date when the commitment period ends |
billing_frequency |
integer | No | Billing frequency in months (overrides the file-level frequency if set) |
commitment |
integer | No | Commitment duration in months |
active |
boolean | No | Whether this recurring item is active |
paused |
boolean | No | Whether billing for this item is paused |
has_dispatch |
boolean | No | Whether this item requires dispatch |
has_delivery |
boolean | No | Whether this item requires delivery |
dispatched |
boolean | No | Whether dispatched |
delivered |
boolean | No | Whether delivered |
use_file_dates |
boolean | No | Whether to use the file-level service dates instead of item-level dates |
create_sale_if_charged_at_zero |
boolean | No | Create an invoice line even when the amount is zero |
under_rental_agreement |
boolean | No | Whether this item is under a rental agreement |
buying_price_without_tax |
decimal | No | Buying/cost price per unit per billing period, excl. tax |
selling_price_without_tax |
decimal | No | Selling price per unit per billing period, excl. tax |
discount_rate |
decimal | No | Discount rate |
gratuity_quantity |
integer | No | Gratuity (free) quantity threshold |
black_and_white_copies_gratuity |
date | No | Gratuity period end for B/W copies (copier billing) |
colour_copies_gratuity |
date | No | Gratuity period end for colour copies |
colour1_copies_gratuity |
date | No | Gratuity period end for colour type 1 |
colour2_copies_gratuity |
date | No | Gratuity period end for colour type 2 |
colour3_copies_gratuity |
date | No | Gratuity period end for colour type 3 |
created_at |
datetime | auto | Creation timestamp |
updated_at |
datetime | auto | Last update timestamp |
Customer File Licence (Licence-based Billing)
| Property | Type | Required | Description |
|---|---|---|---|
id |
integer | auto | Unique identifier |
customer_file_id |
integer | Yes | FK to customer_files |
item_id |
integer | Yes | FK to items (catalog item) |
quantity |
numeric | Yes | Licence quantity (must be > 0) |
label |
string | No | Custom label. Defaults to the item description if not set |
line_key |
string | auto | Unique line key. Read-only |
activation_date |
date | No | Date when the licence was activated |
renewal_date |
date | No | Date when the licence is due for renewal |
last_invoice_date |
date | auto | Date of the last invoice for this licence. Read-only |
active |
boolean | No | Whether this licence is active |
buying_price_without_tax |
decimal | No | Buying/cost price, excl. tax |
selling_price_without_tax |
decimal | No | Selling price, excl. tax |
frequency |
integer | No | Renewal frequency in months |
created_at |
datetime | auto | Creation timestamp |
updated_at |
datetime | auto | Last update timestamp |
Customer File (Main)
Base URL: /api/v1/customer-files
Auth required: Yes (auth:api)
GET /v1/customer-files
List all files for a given fileable entity (customer or prospect).
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
fileable_type |
string | Yes | prospect or customer |
fileable_id |
integer | Yes | ID of the owning entity |
Response 200: Array of customer file objects.
Examples:
curl -X GET "https://your-instance.bluerocktel.net/api/v1/customer-files?fileable_type=customer&fileable_id=42" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
import requests
response = requests.get(
"https://your-instance.bluerocktel.net/api/v1/customer-files",
params={"fileable_type": "customer", "fileable_id": 42},
headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
files = response.json()
$response = Http::withToken('YOUR_API_TOKEN')
->get('https://your-instance.bluerocktel.net/api/v1/customer-files', [
'fileable_type' => 'customer',
'fileable_id' => 42,
]);
$files = $response->json();
const response = await fetch(
"https://your-instance.bluerocktel.net/api/v1/customer-files?fileable_type=customer&fileable_id=42",
{
headers: {
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json"
}
}
);
const files = await response.json();
POST /v1/customer-files
Create a new customer file. Auto-sets fileable_type, fileable_id, and user_id. Optionally syncs contact_ids.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
fileable_type |
string | Yes | prospect or customer |
fileable_id |
integer | Yes | ID of the owning entity |
Body (JSON): File attributes validated via model. Optional: contact_ids (array of contact IDs to sync).
Response 201: Created file object. Response 422: Validation error.
Examples:
curl -X POST "https://your-instance.bluerocktel.net/api/v1/customer-files?fileable_type=customer&fileable_id=42" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Main contract", "contact_ids": [1, 5]}'
import requests
response = requests.post(
"https://your-instance.bluerocktel.net/api/v1/customer-files",
params={"fileable_type": "customer", "fileable_id": 42},
json={"name": "Main contract", "contact_ids": [1, 5]},
headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
created_file = response.json()
$response = Http::withToken('YOUR_API_TOKEN')
->post('https://your-instance.bluerocktel.net/api/v1/customer-files', [
'fileable_type' => 'customer',
'fileable_id' => 42,
'name' => 'Main contract',
'contact_ids' => [1, 5],
]);
$createdFile = $response->json();
const response = await fetch(
"https://your-instance.bluerocktel.net/api/v1/customer-files?fileable_type=customer&fileable_id=42",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({ name: "Main contract", contact_ids: [1, 5] })
}
);
const createdFile = await response.json();
GET /v1/customer-files/{id}
Get a single customer file with all relations: fileable, licences, initial, recurring, telephony lines, assigned users, contacts.
URL parameters:
| Parameter | Type | Description |
|---|---|---|
id |
integer | Customer file ID |
Response 200: Customer file with full relations. Response 404: Not found.
PUT /v1/customer-files/{id}
Update a customer file. Syncs contact_ids if provided. Sets user_id to current user.
URL parameters:
| Parameter | Type | Description |
|---|---|---|
id |
integer | Customer file ID |
Body (JSON): File attributes. Optional: contact_ids (array).
Response 201: Updated file object. Response 404: Not found. Response 422: Validation error.
DELETE /v1/customer-files/{id}
Delete a customer file.
URL parameters:
| Parameter | Type | Description |
|---|---|---|
id |
integer | Customer file ID |
Response 200: Success message. Response 404: Not found.
GET /v1/customer-files/{id}/resources
Get all phone line resources for a customer file (from recurring items and telephony lines).
URL parameters:
| Parameter | Type | Description |
|---|---|---|
id |
integer | Customer file ID |
Response 200: Array of phone line objects.
GET /v1/fileables/number/{number}
Find a customer file by phone number.
URL parameters:
| Parameter | Type | Description |
|---|---|---|
number |
string | Phone number |
Response 200: Customer file object. Response 404: Not found.
Customer File Initials
Base URL: /api/v1/customer-files/initials
One-time charge line items on a customer file.
GET /v1/customer-files/initials
List initial items with filtering, sorting, and pagination (Spatie QueryBuilder).
Query parameters:
| Parameter | Type | Description |
|---|---|---|
filter[label] |
string | Filter by label |
filter[id] |
integer | Filter by ID |
filter[customer_file_id] |
integer | Filter by customer file |
filter[item_id] |
integer | Filter by catalog item |
filter[invoice_id] |
integer | Filter by invoice |
filter[line_key] |
string | Filter by line key |
filter[paused] |
boolean | Filter paused items |
filter[quantity] |
string | Quantity range filter |
filter[invoiced] |
boolean | Invoiced scope |
sort |
string | Field (id, created_at, updated_at, quantity, buying_price_without_tax, selling_price_without_tax) |
include |
string | Comma-separated relations (invoice, file, item) |
per_page |
integer | Items per page (default 20) |
Response 200: Paginated list of initial items.
Examples:
curl -X GET "https://your-instance.bluerocktel.net/api/v1/customer-files/initials?filter[customer_file_id]=10&include=file,item&per_page=50" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
import requests
response = requests.get(
"https://your-instance.bluerocktel.net/api/v1/customer-files/initials",
params={
"filter[customer_file_id]": 10,
"include": "file,item",
"per_page": 50
},
headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
initials = response.json()
$response = Http::withToken('YOUR_API_TOKEN')
->get('https://your-instance.bluerocktel.net/api/v1/customer-files/initials', [
'filter[customer_file_id]' => 10,
'include' => 'file,item',
'per_page' => 50,
]);
$initials = $response->json();
const response = await fetch(
"https://your-instance.bluerocktel.net/api/v1/customer-files/initials?filter[customer_file_id]=10&include=file,item&per_page=50",
{
headers: {
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json"
}
}
);
const initials = await response.json();
POST /v1/customer-files/initials
Create a new initial line item.
Body (JSON): Validated via customer_file_initial::attributes('common', 'store').
Date fields (format Y-m-d): guarantee_expiration_date, delivered_at, dispatched_at, dob, charge_after_date.
Response 201: Created item. Response 422: Validation/DB error. Response 500: Server error.
GET /v1/customer-files/initials/{id}
Get a single initial item with relations (file, invoice, item).
Response 200: Initial item object. Response 404: Not found.
PUT /v1/customer-files/initials/{id}
Update an initial line item.
Body (JSON): Validated via customer_file_initial::attributes('common').
Same date fields as store.
Response 201: Updated item. Response 404: Not found.
DELETE /v1/customer-files/initials/{id}
Delete an initial line item.
Response 200: Success message. Response 404: Not found.
Customer File Recurrings
Base URL: /api/v1/customer-files/recurrings
Periodic subscription line items on a customer file.
GET /v1/customer-files/recurrings
List recurring items with filtering, sorting, and pagination.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
filter[label] |
string | Filter by label |
filter[id] |
integer | Filter by ID |
filter[customer_file_id] |
integer | Filter by customer file |
filter[item_id] |
integer | Filter by catalog item |
filter[line_key] |
string | Filter by line key |
filter[paused] |
boolean | Filter paused items |
filter[active] |
boolean | Filter active items |
filter[delivered] |
boolean | Filter delivered items |
filter[billing_frequency] |
string | Filter by billing frequency |
filter[quantity] |
string | Quantity range filter |
sort |
string | Field (id, created_at, updated_at, quantity, buying_price_without_tax, selling_price_without_tax) |
include |
string | Relations (file, item, sales) |
per_page |
integer | Items per page (default 20) |
Response 200: Paginated list of recurring items (includes sales count).
Examples:
curl -X GET "https://your-instance.bluerocktel.net/api/v1/customer-files/recurrings?filter[customer_file_id]=10&filter[active]=true&include=file,item" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
import requests
response = requests.get(
"https://your-instance.bluerocktel.net/api/v1/customer-files/recurrings",
params={
"filter[customer_file_id]": 10,
"filter[active]": "true",
"include": "file,item"
},
headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
recurrings = response.json()
$response = Http::withToken('YOUR_API_TOKEN')
->get('https://your-instance.bluerocktel.net/api/v1/customer-files/recurrings', [
'filter[customer_file_id]' => 10,
'filter[active]' => true,
'include' => 'file,item',
]);
$recurrings = $response->json();
const response = await fetch(
"https://your-instance.bluerocktel.net/api/v1/customer-files/recurrings?filter[customer_file_id]=10&filter[active]=true&include=file,item",
{
headers: {
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json"
}
}
);
const recurrings = await response.json();
POST /v1/customer-files/recurrings
Create a new recurring line item.
Body (JSON): Validated via customer_file_recurring::attributes('common', 'store').
Date fields (format Y-m-d): service_start, service_start_real, service_stop, first_invoice, last_invoice, current_month, month_minus1, month_minus2, month_minus3, dispatched_at, delivered_at, commitment_expiry_date, black_and_white_copies_gratuity, colour_copies_gratuity, colour1_copies_gratuity, colour2_copies_gratuity, colour3_copies_gratuity.
Response 201: Created item. Response 422/500: Error.
GET /v1/customer-files/recurrings/{id}
Get a single recurring item with relations (file, item, sales).
Response 200: Recurring item object.
PUT /v1/customer-files/recurrings/{id}
Update a recurring line item.
Response 201: Updated item.
DELETE /v1/customer-files/recurrings/{id}
Delete a recurring line item.
Response 200: Success message.
Customer File Licences
Base URL: /api/v1/customer-files/licences
Licence-based billing line items on a customer file.
GET /v1/customer-files/licences
List licence items with filtering, sorting, and pagination.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
filter[label] |
string | Filter by label |
filter[item.description] |
string | Filter by item description |
filter[id] |
integer | Filter by ID |
filter[item.id] |
integer | Filter by item ID |
filter[customer_file_id] |
integer | Filter by customer file |
filter[item_id] |
integer | Filter by catalog item |
filter[line_key] |
string | Filter by line key |
filter[active] |
boolean | Filter active licences |
filter[frequency] |
string | Filter by frequency |
filter[quantity] |
string | Quantity range filter |
sort |
string | Field (id, created_at, updated_at, quantity, buying_price_without_tax, selling_price_without_tax) |
include |
string | Relations (invoice, file, item, sales, renewals) |
per_page |
integer | Items per page (default 20) |
Response 200: Paginated list of licence items.
Examples:
curl -X GET "https://your-instance.bluerocktel.net/api/v1/customer-files/licences?filter[customer_file_id]=10&filter[active]=true&include=file,item" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
import requests
response = requests.get(
"https://your-instance.bluerocktel.net/api/v1/customer-files/licences",
params={
"filter[customer_file_id]": 10,
"filter[active]": "true",
"include": "file,item"
},
headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
licences = response.json()
$response = Http::withToken('YOUR_API_TOKEN')
->get('https://your-instance.bluerocktel.net/api/v1/customer-files/licences', [
'filter[customer_file_id]' => 10,
'filter[active]' => true,
'include' => 'file,item',
]);
$licences = $response->json();
const response = await fetch(
"https://your-instance.bluerocktel.net/api/v1/customer-files/licences?filter[customer_file_id]=10&filter[active]=true&include=file,item",
{
headers: {
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json"
}
}
);
const licences = await response.json();
POST /v1/customer-files/licences
Create a new licence line item.
Body (JSON): Validated via customer_file_licence::attributes('common', 'store').
Date fields (format Y-m-d): activation_date, renewal_date.
Response 201: Created item.
GET /v1/customer-files/licences/{id}
Get a single licence item with relations (file, item, sales).
Response 200: Licence item object.
PUT /v1/customer-files/licences/{id}
Update a licence line item.
Response 201: Updated item.
DELETE /v1/customer-files/licences/{id}
Delete a licence line item.
Response 200: Success message.
On this page