Skip to main content
CRM & Sales

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.