Customers API
The Customers API provides full CRUD operations for managing customer master data, contacts, authorizations (vergunningen), and physical locations, including VAT Reverse Charge (Article 23) eligibility checks.
Required Scope: customers:read, customers:write, customers:delete
List Customers
Retrieve a paginated list of customers with optional filters.
GET /api/v1/customersQuery Parameters
| Parameter | Type | Description |
|---|---|---|
code | string | Filter by customer code (partial match) |
name | string | Filter by customer name (partial match) |
eori | string | Filter by EORI number (partial match) |
country | string | Filter by country code (exact, ISO 3166-1 alpha-2) |
portal_access | boolean | Filter by portal access status |
sort | string | Sort field: customer_code, customer_name, customer_country_code, created_at (default: customer_name) |
direction | string | asc or desc (default: asc) |
per_page | integer | Results per page (default: 25, max: 100) |
Example Request
curl https://app.borderbolt.com/api/v1/customers \
-H "Authorization: Bearer {token}" \
-G \
--data-urlencode "country=NL" \
--data-urlencode "portal_access=true"Example Response
{
"data": [
{
"id": 1001,
"customer_code": "CUST001",
"customer_name": "Example B.V.",
"customer_eori_number": "NL123456789",
"customer_country_code": "NL",
"portal_access_enabled": true,
"created_at": "2025-06-01T10:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 3,
"per_page": 25,
"total": 62
}
}Get Customer
Retrieve a single customer with all details, contacts, authorizations, and locations.
GET /api/v1/customers/{id}curl https://app.borderbolt.com/api/v1/customers/1001 \
-H "Authorization: Bearer {token}"Get Customer by Code
Retrieve a single customer by their unique customer code.
GET /api/v1/customers/code/{code}curl https://app.borderbolt.com/api/v1/customers/code/CUST001 \
-H "Authorization: Bearer {token}"Example Response
{
"data": {
"id": 1001,
"customer_code": "CUST001",
"customer_name": "Example B.V.",
"customer_address": "Voorbeeldstraat",
"customer_address_number": "1",
"customer_postal_code": "1234AB",
"customer_city": "Amsterdam",
"customer_country_code": "NL",
"customer_eori_number": "NL123456789",
"customer_vat_number": "NL123456789B01",
"customer_vat_country": "NL",
"currency": "EUR",
"representation_type": "2",
"customs_declaration_office": "NL000396",
"default_customs_office_of_declaration": "NL000396",
"is_sender": false,
"is_importer": true,
"is_addressee": true,
"is_exporter": false,
"is_declarant": false,
"is_carrier": false,
"is_invoice_to": false,
"is_freight_forwarder": false,
"declarant_customer_id": 1,
"warehouse_licence": null,
"warehouse_licence_type": null,
"dms_41_placement_licence": null,
"poa_valid_until": "2027-01-01",
"postbus": null,
"postbus_cid": null,
"postbus_transit": null,
"postbus_msw": null,
"postbus_emcs": null,
"surety_sync_enabled": false,
"dva_holder_eori": null,
"dva_holder_name": null,
"dva_holder_address": null,
"dva_holder_postal_code": null,
"dva_holder_city": null,
"dva_holder_country": null,
"dva_holder_contact_name": null,
"dva_holder_contact_phone": null,
"dva_holder_contact_email": null,
"dva_authorized_consignor_permit": null,
"dva_authorized_consignee_permit": null,
"dva_guarantee_type": null,
"dva_guarantee_grn": null,
"dva_guarantee_sync_enabled": false,
"dva_volgnummer": null,
"vat_number": "NL123456789B01",
"vat_reverse_charge_eligible": true,
"article_23_permit": true,
"vat_reverse_charge_check_status": "verified",
"vat_reverse_charge_checked_at": "2026-03-20T08:00:00.000000Z",
"portal_access_enabled": true,
"portal_show_declarations": true,
"portal_show_drafts": false,
"portal_show_item_master": true,
"portal_show_poa": false,
"portal_show_file_import": false,
"portal_show_mapping_templates": false,
"portal_allow_user_management": false,
"portal_show_invoices": false,
"invoice_email": "invoices@example.com",
"invoice_auto_send": false,
"prepayment_threshold": null,
"notifications_enabled": true,
"contacts": [],
"authorizations": [],
"locations": [],
"created_at": "2025-06-01T10:00:00.000000Z",
"updated_at": "2026-03-20T08:00:00.000000Z"
}
}dva_guarantee_access_code is never returned by the API for security reasons.
Create Customer
Create a new customer.
POST /api/v1/customersRequest Body
Identity
| Field | Required | Type | Description |
|---|---|---|---|
customer_code | Yes | string | Unique customer code (max 50 chars) |
customer_name | Yes | string | Customer name (max 255 chars) |
customer_address | No | string | Street name |
customer_address_number | No | string | House number |
customer_postal_code | No | string | Postal code |
customer_city | No | string | City |
customer_country_code | No | string | ISO 3166-1 alpha-2 country code |
customer_eori_number | No | string | EORI number |
customer_vat_number | No | string | VAT number |
customer_vat_country | No | string | Country of VAT registration |
currency | No | string | Billing currency for this customer’s invoices, ISO 4217 (e.g. EUR, USD). Defaults to EUR. |
Customs Roles
| Field | Required | Type | Description |
|---|---|---|---|
representation_type | No | string | Customs representation type (1 = direct, 2 = indirect) |
customs_declaration_office | No | string | Default customs office of declaration |
default_customs_office_of_declaration | No | string | Default customs office override |
is_sender | No | boolean | Can act as sender in declarations |
is_importer | No | boolean | Can act as importer |
is_addressee | No | boolean | Can act as addressee |
is_exporter | No | boolean | Can act as exporter |
is_declarant | No | boolean | Is a declarant (customs agent) |
is_carrier | No | boolean | Can act as carrier |
is_invoice_to | No | boolean | Can be invoiced |
is_freight_forwarder | No | boolean | Acts as freight forwarder |
declarant_customer_id | No | integer | ID of the linked declarant customer |
parent_customer_id | No | integer | ID of the parent freight forwarder |
default_invoice_to_customer_id | No | integer | Deprecated. This field is still accepted for backward compatibility but no longer affects which company gets billed. Manage the customer’s invoice-to allow-list (including its default entry) from the customer’s edit page instead. |
Invoice-to billing is now controlled by an allow-list: Which companies can be billed for a customer, and which one is billed by default, is configured on the customer’s edit page rather than through this field. This API does not yet expose a way to manage that allow-list — use the web interface.
Licences & Permits
| Field | Required | Type | Description |
|---|---|---|---|
warehouse_licence | No | string | Warehouse licence number |
warehouse_licence_type | No | string | Warehouse licence type code |
dms_41_placement_licence | No | string | DMS 4.1 placement licence |
poa_valid_until | No | date | Power of Attorney expiry (YYYY-MM-DD) |
atr_license_number | No | string | ATR licence number |
Postbus Numbers (Declarants)
Only relevant when is_declarant = true.
| Field | Required | Type | Description |
|---|---|---|---|
postbus | No | string | Default DMS postbus (H1–H5, B1–B4) |
postbus_cid | No | string | CID postbus (VAT Reverse Charge queries) |
postbus_transit | No | string | NCTS5 transit postbus |
postbus_msw | No | string | Maritime Single Window postbus |
postbus_emcs | No | string | EMCS excise movements postbus |
DMS Surety
| Field | Required | Type | Description |
|---|---|---|---|
surety_sync_enabled | No | boolean | Enable automatic surety balance sync |
DVA Transit Holder Defaults
| Field | Required | Type | Description |
|---|---|---|---|
dva_holder_eori | No | string | EORI of the DVA transit holder |
dva_holder_name | No | string | Name of the DVA transit holder |
dva_holder_address | No | string | Address |
dva_holder_postal_code | No | string | Postal code |
dva_holder_city | No | string | City |
dva_holder_country | No | string | Country code |
dva_holder_contact_name | No | string | Contact person name |
dva_holder_contact_phone | No | string | Contact phone |
dva_holder_contact_email | No | string | Contact email |
dva_authorized_consignor_permit | No | string | Toegelaten afzender permit number |
dva_authorized_consignee_permit | No | string | Toegelaten geadresseerde permit number |
DVA Guarantee
| Field | Required | Type | Description |
|---|---|---|---|
dva_guarantee_type | No | string | Guarantee type code (0–9) |
dva_guarantee_grn | No | string | Guarantee Reference Number (GRN) |
dva_guarantee_access_code | No | string | Guarantee access code (write-only, never returned) |
dva_guarantee_sync_enabled | No | boolean | Enable automatic DVA guarantee sync |
dva_volgnummer | No | string | DVA sequence number |
VAT Reverse Charge (Article 23)
| Field | Required | Type | Description |
|---|---|---|---|
vat_number | No | string | VAT number used for FR7 reverse charge queries |
vat_reverse_charge_eligible | No | boolean | Override eligibility (normally set by automated check) |
article_23_permit | No | boolean | Override Article 23 permit status |
Portal Access
| Field | Required | Type | Description |
|---|---|---|---|
portal_access_enabled | No | boolean | Grant access to the customer portal |
portal_show_declarations | No | boolean | Show declarations in the portal |
portal_show_drafts | No | boolean | Show draft declarations |
portal_show_item_master | No | boolean | Show item master |
portal_show_poa | No | boolean | Show Power of Attorney section |
portal_show_file_import | No | boolean | Show file import |
portal_show_mapping_templates | No | boolean | Show mapping templates |
portal_allow_user_management | No | boolean | Allow user management in portal |
portal_show_invoices | No | boolean | Show invoices in portal |
Invoicing
| Field | Required | Type | Description |
|---|---|---|---|
invoice_email | No | string | Email address for invoice delivery |
invoice_auto_send | No | boolean | Automatically send invoices by email |
prepayment_threshold | No | number | Prepayment threshold amount |
Other Settings
| Field | Required | Type | Description |
|---|---|---|---|
notifications_enabled | No | boolean | Enable event notifications |
submit_dec_when_valid | No | boolean | Auto-submit declarations when valid |
save_when_invalid | No | boolean | Save declarations even when invalid |
enable_allocation_fallback | No | boolean | Enable allocation fallback |
forfait_enabled | No | boolean | Enable forfait handling |
dossier_prefix | No | string | Prefix for auto-generated dossier numbers |
to_declaration_completed_email | No | string | Email to notify on declaration completion |
Example Request
curl -X POST https://app.borderbolt.com/api/v1/customers \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"customer_code": "CUST002",
"customer_name": "New Company B.V.",
"customer_eori_number": "NL987654321",
"customer_vat_number": "NL987654321B01",
"customer_country_code": "NL",
"is_importer": true,
"is_addressee": true,
"declarant_customer_id": 1
}'Example Response
{
"data": {
"id": 1002,
"customer_code": "CUST002",
"customer_name": "New Company B.V.",
"created_at": "2026-03-25T10:00:00.000000Z"
},
"message": "Customer created successfully."
}HTTP 201 is returned on success. HTTP 422 is returned if customer_code already exists.
Update Customer
Update an existing customer. All fields are optional — only fields present in the request body are updated.
PUT /api/v1/customers/{id}Same fields as Create Customer, except customer_code cannot be changed.
curl -X PUT https://app.borderbolt.com/api/v1/customers/1001 \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"poa_valid_until": "2028-01-01",
"portal_access_enabled": true,
"portal_show_declarations": true
}'Delete Customer
Delete a customer.
DELETE /api/v1/customers/{id}curl -X DELETE https://app.borderbolt.com/api/v1/customers/1001 \
-H "Authorization: Bearer {token}"Contacts
List Contacts
GET /api/v1/customers/{id}/contactscurl https://app.borderbolt.com/api/v1/customers/1001/contacts \
-H "Authorization: Bearer {token}"Example Response
{
"data": [
{
"id": 201,
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31612345678",
"position": "Import Manager",
"department": "Logistics",
"is_primary": true,
"receives_approvals": true,
"receives_notifications": true,
"notification_preferences": ["declaration.accepted", "declaration.released"],
"language": "nl",
"notes": null,
"created_at": "2026-01-10T09:00:00.000000Z"
}
]
}Add Contact
POST /api/v1/customers/{id}/contacts| Field | Required | Type | Description |
|---|---|---|---|
name | Yes | string | Full name (max 255 chars) |
email | No | string | Email address |
phone | No | string | Phone number |
position | No | string | Job title/position |
department | No | string | Department |
is_primary | No | boolean | Mark as primary contact |
receives_approvals | No | boolean | Receives declaration approval emails |
receives_notifications | No | boolean | Receives event notifications |
notification_preferences | No | array | List of event types to notify |
language | No | string | Preferred language code (e.g. nl, en) |
notes | No | string | Internal notes |
curl -X POST https://app.borderbolt.com/api/v1/customers/1001/contacts \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Maria Bakker",
"email": "maria@example.com",
"position": "Finance",
"is_primary": false,
"receives_notifications": true
}'HTTP 201 is returned on success.
Update Contact
PUT /api/v1/contacts/{id}Same fields as Add Contact (all optional).
curl -X PUT https://app.borderbolt.com/api/v1/contacts/201 \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"phone": "+31698765432"
}'Delete Contact
DELETE /api/v1/contacts/{id}curl -X DELETE https://app.borderbolt.com/api/v1/contacts/201 \
-H "Authorization: Bearer {token}"Authorizations
Authorizations (vergunningen) represent customs permits and licences linked to a customer.
List Authorizations
GET /api/v1/customers/{id}/authorizationscurl https://app.borderbolt.com/api/v1/customers/1001/authorizations \
-H "Authorization: Bearer {token}"Example Response
{
"data": [
{
"id": 301,
"type": "CW",
"description": "Customs Warehouse Licence",
"identification": "NL-CW-12345",
"authorisation_holder": "Example B.V.",
"created_at": "2025-09-01T00:00:00.000000Z"
}
]
}Add Authorization
POST /api/v1/customers/{id}/authorizations| Field | Required | Type | Description |
|---|---|---|---|
type | Yes | string | Authorization type code (e.g. CW, AEO, IPR) |
description | No | string | Human-readable description |
identification | No | string | Permit/licence identification number |
authorisation_holder | No | string | Name of the authorization holder |
curl -X POST https://app.borderbolt.com/api/v1/customers/1001/authorizations \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"type": "AEO",
"description": "Authorised Economic Operator",
"identification": "NLAEO0000123456"
}'HTTP 201 is returned on success.
Update Authorization
PUT /api/v1/authorizations/{id}Same fields as Add Authorization (all optional except type).
curl -X PUT https://app.borderbolt.com/api/v1/authorizations/301 \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"identification": "NLAEO0000123457"
}'Delete Authorization
DELETE /api/v1/authorizations/{id}curl -X DELETE https://app.borderbolt.com/api/v1/authorizations/301 \
-H "Authorization: Bearer {token}"Locations
Locations represent physical storage or inspection locations linked to a customer.
List Locations
GET /api/v1/customers/{id}/locationscurl https://app.borderbolt.com/api/v1/customers/1001/locations \
-H "Authorization: Bearer {token}"Example Response
{
"data": [
{
"id": 401,
"name": "Warehouse Rotterdam",
"address": "Havenstraat",
"address_number": "10",
"postcode": "3011AA",
"city": "Rotterdam",
"country_code": "NL",
"vergunningtype": "CW",
"vergunningnummer": "NL-CW-12345",
"is_default": true,
"created_at": "2025-09-01T00:00:00.000000Z"
}
]
}Add Location
POST /api/v1/customers/{id}/locations| Field | Required | Type | Description |
|---|---|---|---|
name | Yes | string | Location name |
address | No | string | Street name |
address_number | No | string | House number |
postcode | No | string | Postal code |
city | No | string | City |
country_code | No | string | ISO 3166-1 alpha-2 country code |
vergunningtype | No | string | Associated licence type code |
vergunningnummer | No | string | Associated licence number |
is_default | No | boolean | Set as default location |
curl -X POST https://app.borderbolt.com/api/v1/customers/1001/locations \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Warehouse Amsterdam",
"address": "Keizersgracht",
"address_number": "100",
"postcode": "1015CS",
"city": "Amsterdam",
"country_code": "NL",
"is_default": false
}'HTTP 201 is returned on success.
Update Location
PUT /api/v1/locations/{id}Same fields as Add Location (all optional except name).
curl -X PUT https://app.borderbolt.com/api/v1/locations/401 \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"is_default": false
}'Delete Location
DELETE /api/v1/locations/{id}curl -X DELETE https://app.borderbolt.com/api/v1/locations/401 \
-H "Authorization: Bearer {token}"VAT Reverse Charge Check
Trigger an asynchronous VAT Reverse Charge (Article 23 / BTW Verlegging) eligibility check for a customer via the NL Customs CI (Comfort Information) interface.
POST /api/v1/customers/{id}/vat-reverse-charge-checkThe check sends a CI function code 90 query to NL Customs, which verifies:
- AIQ: whether the customer’s VAT number is linked to their EORI (FR7 eligible)
- AAX: whether the customer holds an Article 23 permit
The result is delivered asynchronously via webhook. Once received, vat_reverse_charge_eligible, article_23_permit, and vat_reverse_charge_check_status on the customer record are updated automatically.
The customer must have both customer_eori_number and customer_vat_number set, and a linked declarant customer with a postbus_cid configured.
curl -X POST https://app.borderbolt.com/api/v1/customers/1001/vat-reverse-charge-check \
-H "Authorization: Bearer {token}"Example Response
{
"message": "VAT Reverse Charge check initiated. Result will be delivered asynchronously via webhook.",
"data": {
"customer_id": 1001,
"status": "pending",
"reference": "CI1a2b3c4d5e6f7a8b9c"
}
}HTTP 422 is returned if the check cannot be initiated (missing EORI, VAT number, or declarant postbus).
VAT Reverse Charge Fields
After the async response is received, the following fields on the customer record reflect the result:
| Field | Type | Description |
|---|---|---|
vat_reverse_charge_check_status | string | pending, verified |
vat_reverse_charge_eligible | boolean|null | true = FR7 eligible, false = not eligible, null = unchecked |
article_23_permit | boolean|null | true = Article 23 permit granted, null = not applicable |
vat_reverse_charge_checked_at | datetime | Timestamp of last completed check |
Next Steps
- Dossiers API — Link customers to dossiers
- Declarations API — Use customers in declarations
- Guarantees API — Monitor customer guarantee balances