Skip to Content
API ReferenceCustomers API

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/customers

Query Parameters

ParameterTypeDescription
codestringFilter by customer code (partial match)
namestringFilter by customer name (partial match)
eoristringFilter by EORI number (partial match)
countrystringFilter by country code (exact, ISO 3166-1 alpha-2)
portal_accessbooleanFilter by portal access status
sortstringSort field: customer_code, customer_name, customer_country_code, created_at (default: customer_name)
directionstringasc or desc (default: asc)
per_pageintegerResults 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/customers

Request Body

Identity

FieldRequiredTypeDescription
customer_codeYesstringUnique customer code (max 50 chars)
customer_nameYesstringCustomer name (max 255 chars)
customer_addressNostringStreet name
customer_address_numberNostringHouse number
customer_postal_codeNostringPostal code
customer_cityNostringCity
customer_country_codeNostringISO 3166-1 alpha-2 country code
customer_eori_numberNostringEORI number
customer_vat_numberNostringVAT number
customer_vat_countryNostringCountry of VAT registration
currencyNostringBilling currency for this customer’s invoices, ISO 4217 (e.g. EUR, USD). Defaults to EUR.

Customs Roles

FieldRequiredTypeDescription
representation_typeNostringCustoms representation type (1 = direct, 2 = indirect)
customs_declaration_officeNostringDefault customs office of declaration
default_customs_office_of_declarationNostringDefault customs office override
is_senderNobooleanCan act as sender in declarations
is_importerNobooleanCan act as importer
is_addresseeNobooleanCan act as addressee
is_exporterNobooleanCan act as exporter
is_declarantNobooleanIs a declarant (customs agent)
is_carrierNobooleanCan act as carrier
is_invoice_toNobooleanCan be invoiced
is_freight_forwarderNobooleanActs as freight forwarder
declarant_customer_idNointegerID of the linked declarant customer
parent_customer_idNointegerID of the parent freight forwarder
default_invoice_to_customer_idNointegerDeprecated. 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

FieldRequiredTypeDescription
warehouse_licenceNostringWarehouse licence number
warehouse_licence_typeNostringWarehouse licence type code
dms_41_placement_licenceNostringDMS 4.1 placement licence
poa_valid_untilNodatePower of Attorney expiry (YYYY-MM-DD)
atr_license_numberNostringATR licence number

Postbus Numbers (Declarants)

Only relevant when is_declarant = true.

FieldRequiredTypeDescription
postbusNostringDefault DMS postbus (H1–H5, B1–B4)
postbus_cidNostringCID postbus (VAT Reverse Charge queries)
postbus_transitNostringNCTS5 transit postbus
postbus_mswNostringMaritime Single Window postbus
postbus_emcsNostringEMCS excise movements postbus

DMS Surety

FieldRequiredTypeDescription
surety_sync_enabledNobooleanEnable automatic surety balance sync

DVA Transit Holder Defaults

FieldRequiredTypeDescription
dva_holder_eoriNostringEORI of the DVA transit holder
dva_holder_nameNostringName of the DVA transit holder
dva_holder_addressNostringAddress
dva_holder_postal_codeNostringPostal code
dva_holder_cityNostringCity
dva_holder_countryNostringCountry code
dva_holder_contact_nameNostringContact person name
dva_holder_contact_phoneNostringContact phone
dva_holder_contact_emailNostringContact email
dva_authorized_consignor_permitNostringToegelaten afzender permit number
dva_authorized_consignee_permitNostringToegelaten geadresseerde permit number

DVA Guarantee

FieldRequiredTypeDescription
dva_guarantee_typeNostringGuarantee type code (0–9)
dva_guarantee_grnNostringGuarantee Reference Number (GRN)
dva_guarantee_access_codeNostringGuarantee access code (write-only, never returned)
dva_guarantee_sync_enabledNobooleanEnable automatic DVA guarantee sync
dva_volgnummerNostringDVA sequence number

VAT Reverse Charge (Article 23)

FieldRequiredTypeDescription
vat_numberNostringVAT number used for FR7 reverse charge queries
vat_reverse_charge_eligibleNobooleanOverride eligibility (normally set by automated check)
article_23_permitNobooleanOverride Article 23 permit status

Portal Access

FieldRequiredTypeDescription
portal_access_enabledNobooleanGrant access to the customer portal
portal_show_declarationsNobooleanShow declarations in the portal
portal_show_draftsNobooleanShow draft declarations
portal_show_item_masterNobooleanShow item master
portal_show_poaNobooleanShow Power of Attorney section
portal_show_file_importNobooleanShow file import
portal_show_mapping_templatesNobooleanShow mapping templates
portal_allow_user_managementNobooleanAllow user management in portal
portal_show_invoicesNobooleanShow invoices in portal

Invoicing

FieldRequiredTypeDescription
invoice_emailNostringEmail address for invoice delivery
invoice_auto_sendNobooleanAutomatically send invoices by email
prepayment_thresholdNonumberPrepayment threshold amount

Other Settings

FieldRequiredTypeDescription
notifications_enabledNobooleanEnable event notifications
submit_dec_when_validNobooleanAuto-submit declarations when valid
save_when_invalidNobooleanSave declarations even when invalid
enable_allocation_fallbackNobooleanEnable allocation fallback
forfait_enabledNobooleanEnable forfait handling
dossier_prefixNostringPrefix for auto-generated dossier numbers
to_declaration_completed_emailNostringEmail 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}/contacts
curl 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
FieldRequiredTypeDescription
nameYesstringFull name (max 255 chars)
emailNostringEmail address
phoneNostringPhone number
positionNostringJob title/position
departmentNostringDepartment
is_primaryNobooleanMark as primary contact
receives_approvalsNobooleanReceives declaration approval emails
receives_notificationsNobooleanReceives event notifications
notification_preferencesNoarrayList of event types to notify
languageNostringPreferred language code (e.g. nl, en)
notesNostringInternal 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}/authorizations
curl 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
FieldRequiredTypeDescription
typeYesstringAuthorization type code (e.g. CW, AEO, IPR)
descriptionNostringHuman-readable description
identificationNostringPermit/licence identification number
authorisation_holderNostringName 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}/locations
curl 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
FieldRequiredTypeDescription
nameYesstringLocation name
addressNostringStreet name
address_numberNostringHouse number
postcodeNostringPostal code
cityNostringCity
country_codeNostringISO 3166-1 alpha-2 country code
vergunningtypeNostringAssociated licence type code
vergunningnummerNostringAssociated licence number
is_defaultNobooleanSet 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-check

The 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:

FieldTypeDescription
vat_reverse_charge_check_statusstringpending, verified
vat_reverse_charge_eligibleboolean|nulltrue = FR7 eligible, false = not eligible, null = unchecked
article_23_permitboolean|nulltrue = Article 23 permit granted, null = not applicable
vat_reverse_charge_checked_atdatetimeTimestamp of last completed check

Next Steps

Last updated on