API Documentation
Welcome to the {{BRAND_NAME}} API documentation. This API allows you to programmatically manage customers, services, billing, invoicing, and telecom operations.
Base URL
All requests use HTTPS. The API returns JSON by default.
Open Interactive API Explorer (Swagger UI)Quick Start
To start using the API you need:
- A user account with "Is allowed to login to the API" enabled
- Your reseller's IP whitelist configured to include your application's IP
- Your client ID
A client ID must be activated once by your platform provider. After activation, you can find it on your own customer page under Details as "API secret (client_id)". Contact your provider if you don't see it yet.
# 1. Get a token
curl -X POST {{BASE_URL}}/authentication-token \
-H "Content-Type: application/json" \
-d '{
"email": "your-api-user@example.com",
"password": "your-password",
"client_id": "your-client-id"
}'
# 2. Use the token
curl {{BASE_URL}}/customers \
-H "Authorization: Bearer YOUR_TOKEN"
$client = new GuzzleHttp\Client([
'base_uri' => '{{BASE_URL}}',
]);
// 1. Get a token
$response = $client->post('/authentication-token', [
'json' => [
'email' => 'your-api-user@example.com',
'password' => 'your-password',
'client_id' => 'your-client-id',
],
]);
$token = json_decode($response->getBody(), true)['token'];
// 2. Use the token
$response = $client->get('/customers', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$customers = json_decode($response->getBody(), true);
Versioning & Changes
The API does not use URL-based versioning (no /v1/ or /v2/ prefix). New fields and endpoints may be added without notice — your integration should ignore unknown fields in responses to remain forward-compatible. Existing fields and endpoints are not removed or renamed without prior communication.
Documentation last updated: April 2026
Authentication
The API supports two authentication methods.
Option 1: JWT Token (recommended)
Request a token by posting your credentials. The token is then used in the Authorization header.
curl -X POST {{BASE_URL}}/authentication-token \
-H "Content-Type: application/json" \
-d '{
"email": "your-api-user@example.com",
"password": "your-password",
"client_id": "your-client-id"
}'
# Response: { "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." }
# Use in subsequent requests:
curl {{BASE_URL}}/customers \
-H "Authorization: Bearer eyJ0eXAiOiJKV1Qi..."
use GuzzleHttp\Client;
$client = new Client(['base_uri' => '{{BASE_URL}}']);
$response = $client->post('/authentication-token', [
'json' => [
'email' => 'your-api-user@example.com',
'password' => 'your-password',
'client_id' => 'your-client-id',
],
]);
$token = json_decode($response->getBody(), true)['token'];
// All subsequent requests:
$response = $client->get('/customers', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
Option 2: Static API Key
Use CLIENT-ID and AUTH-TOKEN headers directly. Simpler but less flexible.
curl {{BASE_URL}}/customers \
-H "CLIENT-ID: your-client-id" \
-H "AUTH-TOKEN: your-auth-token"
$response = $client->get('/customers', [
'headers' => [
'CLIENT-ID' => 'your-client-id',
'AUTH-TOKEN' => 'your-auth-token',
],
]);
Token Lifetime
JWT tokens expire after 1 hour. There is no refresh token endpoint — when a token expires, request a new one by posting credentials to /authentication-token again.
401 Unauthorized response. Do not request a new token before every API call.Rate Limiting
The API uses a sliding window rate limiter with two simultaneous limits:
| Window | Headers | Description |
|---|---|---|
| 1 hour | X-RateLimit-1H-* | Short-term burst protection |
| 24 hours | X-RateLimit-24H-* | Daily volume limit |
When you exceed a limit, the API returns 429 Too Many Requests. Check the Retry-After header for when to resume.
Webhooks & Real-Time Updates
The API does not support webhooks or push notifications. To detect changes (e.g., service order status updates, new invoices), you need to poll the relevant endpoints at a suitable interval. Use filters like date ranges or status fields to limit the result set.
Pagination & Errors
Response Format (JSON-LD / Hydra)
The API uses JSON-LD with Hydra vocabulary. This means responses have a specific envelope format that differs from plain JSON APIs.
... — real responses contain more fields than shown. The complete, always-current field list per resource lives in the Schemas section of the Swagger UI, which is generated directly from the API and never drifts. Use this page for concepts and workflows; use the Swagger schema as the authoritative field reference.
Single resource
Each resource includes @id (its IRI — a path like /customers/1234) and @type:
{
"@context": "/contexts/Customer",
"@id": "/customers/1234",
"@type": "Customer",
"id": 1234,
"name": "Acme BV",
"parent": "/customers/100",
"customerType": "/customer-types/1",
"reference": "ACM001",
...
}
Collection (list)
Collections are wrapped in a Hydra envelope. The actual items are in hydra:member:
{
"@context": "/contexts/Customer",
"@id": "/customers",
"@type": "hydra:Collection",
"hydra:totalItems": 42,
"hydra:member": [
{ "@id": "/customers/1234", "@type": "Customer", "id": 1234, "name": "Acme BV", ... },
{ "@id": "/customers/1235", "@type": "Customer", "id": 1235, "name": "Beta Corp", ... }
],
"hydra:view": {
"@id": "/customers?parentId=100&page=1",
"@type": "hydra:PartialCollectionView",
"hydra:first": "/customers?parentId=100&page=1",
"hydra:last": "/customers?parentId=100&page=2",
"hydra:next": "/customers?parentId=100&page=2"
}
}
"/customers/1234"), not by a numeric ID. When creating or updating resources, use IRI format: "parent": "/customers/100", not "parent": 100.Pagination
Collection endpoints paginate responses. Default: 50 items, maximum: 500. Use hydra:view to navigate pages.
GET /customers?page=2&itemsPerPage=100
| Parameter | Description |
|---|---|
page | Page number (1-based) |
itemsPerPage | Items per page (default: 50, max: 500 for most resources) |
hydra:totalItems to know the total count and hydra:view.hydra:next to check if more pages exist.Error Codes
| Code | Meaning |
|---|---|
200 | Success |
201 | Resource created |
400 | Bad request — check your parameters |
401 | Unauthorized — token expired or invalid |
403 | Forbidden — insufficient permissions or IP not whitelisted |
404 | Resource not found |
429 | Rate limit exceeded — wait and retry |
500 | Server error |
{
"type": "https://tools.ietf.org/html/rfc2616#section-10",
"title": "An error occurred",
"detail": "Access Denied.",
"status": 403
}
Domain Overview
The {{BRAND_NAME}} API serves the Dutch MSP and telecom reseller market. Understanding the business model is essential for using the API effectively.
The Reseller Model
The platform is a multi-tenant system where resellers sell telecom and IT services to their end customers under their own brand.
When authenticated, all data is scoped to the customer tree of the reseller that the API user belongs to.
Key Entities
| Entity | API Resource | What it represents |
|---|---|---|
| Customer | /customers | End customer, dealer, or wholesaler — hierarchically linked via parent |
| Order | /orders | An active service (internet, VoIP, mobile) — not a purchase order |
| Service Order | /service-orders | A provisioning request to create/change/terminate a service |
| Billing Deal | /billing-deals | A recurring subscription or one-time charge on an order |
| Billing Rule | /billing-rules | Intermediate calculation during invoice generation |
| Invoice | /invoices | Final billing document sent to a customer |
| CDR Total | /cdr-totals | Aggregated call/data/SMS usage per service per month |
| User | /users | Portal or API user belonging to a customer |
How Entities Connect
Customer Hierarchy
Customers are organized in a tree using parent references. All access control is based on this hierarchy.
Customer Types
| Type | Description |
|---|---|
| End Customer | Regular customer that uses services |
| Dealer | Commission partner — earns commission on end customer invoices |
| Wholesaler | Gets consolidated invoices for all their end customers |
Filtering by Hierarchy
| Parameter | What it does | Example |
|---|---|---|
inTreeOfCustomerId | All entities in the full subtree | /customers?inTreeOfCustomerId=1234 |
customer.id | Directly linked to this customer | /orders?customer.id=1234 |
includeTree | Expand customer.id to include subtree | /orders?customer.id=1234&includeTree=1 |
parentId | Direct children only | /customers?parentId=1234 |
invoiceOnCustomerId set, meaning invoices go to a different customer. Use invoiceeId (not customerId) when querying invoices.Billing Model
Billing Deal Types
type | billingType | What it is | Example |
|---|---|---|---|
| sales | recurring | Subscription revenue | VoIP trunk €49/mo |
| sales | one-time | One-time charge | Setup fee €150 |
| purchase | recurring | Recurring cost | Wholesale cost from supplier |
| purchase | one-time | One-time cost | Hardware purchase |
rateEnduser is always a per-month rate, regardless of billing period. A quarterly-billed deal with rateEnduser: 50 generates a €150 invoice line each quarter.Invoice Run Flow
When a billing deal's dateEnd is before billedUntil, the system automatically creates a credit on the next invoice.
CDR Totals (Usage)
dateTo: this field contains the last day of the month (e.g., 2026-03-31 = all of March 2026). Each unique dateTo value represents one complete month.When billingRuleId is set on a CDR total record, that usage has been invoiced.
Orders vs Service Orders
| Order | Service Order | |
|---|---|---|
| What is it? | An active service | A provisioning request |
| Analogy | Your internet subscription | The activation ticket |
| Lifecycle | Long-lived (months/years) | Short-lived (days/weeks) |
| Has billing? | Yes — billing deals + CDR totals | No |
| Endpoint | /orders | /service-orders |
To see what services a customer has, use GET /orders.
To request a new service, use POST /service-orders.
Known Issues & Quirks
The API has grown organically over time. Some naming conventions and parameter styles are inconsistent. This page documents the known inconsistencies so you don't waste time debugging them.
Customer ID Parameter Naming
The most common source of confusion: different endpoints use different parameter names for what is essentially the same thing — a customer ID.
| Parameter | Used on | Note |
|---|---|---|
customer.id | /orders, /service-orders | Dot notation — refers to the related customer entity |
customerId | /users, /tariffplans, /products/.../prices | camelCase — direct ID parameter |
customer_id | /call-logs | snake_case — legacy naming |
invoiceeId | /invoices | Not the customer who uses the service, but the one who receives the invoice |
invoicerId | /billing-deals | The reseller/invoicer — required parameter |
inTreeOfCustomerId | /customers, /orders | Hierarchy filter — includes all descendants |
inTreeOfInvoiceeId | /invoices | Same concept but for the invoicee hierarchy |
contractee | /contracts | No "Id" suffix — just the customer ID of the contractee |
parentId | /customers | Direct parent only — not a tree filter |
Resource ID Formats
Most resources use /resource/{id} with a numeric ID in the URL path. However, some resources deviate:
| Pattern | Example | Note |
|---|---|---|
/resource/{id} | /customers/1234 | Standard — most endpoints |
?invoiceId=X | /invoice-lines?invoiceId=9999 | Invoice lines require a query param, not a path |
?invoicerId=X | /billing-deals?invoicerId=1234 | Billing deals require invoicerId as query param |
/resource/{id}/action | /orders/5678/recurring-revenue | Sub-resource actions on an order |
Pagination Differences
| Resource | Default | Maximum |
|---|---|---|
| Most resources | 50 | 500 |
/cdr-totals | 50 | 50,000 |
/billing-rules | 50 | 50,000 |
/cdrs (CSV) | 50,000 | 50,000 (fixed) |
/raw-cdrs | 1,000 | 20,000 |
Date Field Quirks
| Field | Resource | Gotcha |
|---|---|---|
dateTo | /cdr-totals | Contains the last day of the month, not a date range end. 2026-03-31 = March 2026. |
billedUntil | /billing-deals | Moves forward each invoice run. If dateEnd < billedUntil, a credit is generated. |
rateEnduser | /billing-deals | Always a monthly rate, regardless of billing period (quarterly billing with rate 50 = €150/quarter). |
Invoice vs Customer
invoiceOnCustomerId set, redirecting invoices to a different customer (the "invoicee"). This means the customer using a service and the customer receiving the invoice can be different entities. When querying invoices, use invoiceeId — not customerId (which doesn't exist on invoices).PUT vs PATCH vs POST
The API uses these methods inconsistently in some places:
| Method | Typical Use | Quirk |
|---|---|---|
PUT | Full replace | On /customers and /billing-deals, PUT acts as a sync/upsert — it creates or updates based on a reference field |
PATCH | Partial update | Uses application/merge-patch+json content type, not standard JSON |
POST | Create new | Standard behavior |
Content Types
The default content type for most requests is application/json, but there are exceptions:
| Endpoint | Content Type |
|---|---|
| PATCH requests | application/merge-patch+json |
/cdrs | Returns text/csv |
/invoices/{id}/get-pdf | Returns application/pdf |
/uploads/{id}/download | Returns the original file's MIME type |
Portal GUI ↔ API Field Mapping
The portal GUI is translated (Dutch/English) and column or field labels do not always match the API field names. This table maps the most-asked GUI labels to the API resource and field they come from.
| GUI label (NL) | GUI label (EN) | Where in the portal | API resource | Field |
|---|---|---|---|---|
| Aangaande | Applies to | Column in the subscription lists (customer page → invoicing tab: recurring / one-time / inactive; service page) | /billing-deals |
computedRelatedDescription — read-only; derived from the linked entity (e.g. phone number, service label) unless overridden |
| Aangaande / extra omschrijving | Related description | Field on the billing-deal edit form; manual override of the column above. Not shown on invoices. | /billing-deals |
relatedDescription (writable) |
| Omschrijving op factuur | Invoice line label | Field on the billing-deal form; shown as the "Omschrijving" / "Description" column in subscription lists and on invoice lines | /billing-deals, /invoice-lines |
invoiceLineLabel |
| Gefactureerd (t/m) | Billed (until) | Column in the subscription lists; billing-deal detail page | /billing-deals |
billedUntil |
| Uw referentie | Your reference | Invoice page; the customer/PO reference printed on the invoice | /invoices |
yourReference |
| Betaalstatus | Payment state | Invoice lists; customer page → invoices tab | /invoices |
paymentStatus (paid, partial, unpaid) |
BillingDeal in the API, and a service ("dienst") is an Order. See Known Issues & Quirks for more naming history.Workflow: Monthly Invoice Sync
The most common integration scenario: periodically fetch new invoices and sync them to your accounting system, data warehouse, or client portal.
Overview
The flow consists of three steps: authenticate, fetch invoices for the target period, then retrieve the line-level detail for each invoice. You can optionally download the invoice PDF.
invoiceDateFrom / invoiceDateTo filters to fetch only the new period.Step 1 — Fetch invoices for a date range
Use GET /invoices with date filters. Add exclude[]=invoiceLines to keep the response lightweight when you only need the invoice headers first.
# Fetch invoices for March 2026
curl "{{BASE_URL}}/invoices?invoiceDateFrom=2026-03-01&invoiceDateTo=2026-03-31&exclude[]=invoiceLines&exclude[]=invoiceUploads" \
-H "Authorization: Bearer $TOKEN"
// Fetch invoices for March 2026
$response = $client->get('/invoices', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => [
'invoiceDateFrom' => '2026-03-01',
'invoiceDateTo' => '2026-03-31',
'exclude' => ['invoiceLines', 'invoiceUploads'],
],
]);
$invoices = json_decode($response->getBody(), true)['hydra:member'];
Step 2 — Get line-level detail per invoice
For each invoice, fetch the individual lines using GET /invoice-lines. Invoice lines contain the description, amounts, VAT, and product references.
# Get lines for invoice 9999
curl "{{BASE_URL}}/invoice-lines?invoiceId=9999" \
-H "Authorization: Bearer $TOKEN"
foreach ($invoices as $invoice) {
$invoiceId = $invoice['id'];
$response = $client->get('/invoice-lines', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['invoiceId' => $invoiceId],
]);
$lines = json_decode($response->getBody(), true)['hydra:member'];
// Process each line (description, amount, VAT, product, etc.)
foreach ($lines as $line) {
// Sync to your accounting system...
}
}
If you need more granular detail than invoice lines provide — for example, the underlying billing deal, calculation period, or per-unit breakdown — use
GET /billing-rules?invoiceId={id} instead of (or in addition to) invoice lines. Billing rules are the intermediate calculation records that explain how each line was computed. They support high pagination (up to 50,000 items per request).Step 3 (optional) — Download the PDF
If you need the rendered invoice document, download the PDF for each invoice.
curl "{{BASE_URL}}/invoices/9999/get-pdf" \
-H "Authorization: Bearer $TOKEN" \
-o invoice_9999.pdf
foreach ($invoices as $invoice) {
$invoiceId = $invoice['id'];
$pdf = $client->get("/invoices/{$invoiceId}/get-pdf", [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
file_put_contents("invoices/invoice_{$invoiceId}.pdf", $pdf->getBody());
}
Tips
| Topic | Recommendation |
|---|---|
| Idempotency | Store the invoice id in your system and skip duplicates on re-runs. |
| Hierarchy | Use inTreeOfInvoiceeId to fetch invoices for an entire customer tree in one call. |
| Excel export | Use /invoices/{id}/excel-specification for a detailed Excel breakdown per invoice. |
| Token expiry | Tokens expire after 1 hour. For large syncs, re-authenticate when you receive a 401 response. |
| Pagination | Invoice lists are paginated. Loop through hydra:view → hydra:next until there are no more pages. |
Customers
List customers
Query Parameters
| Parameter | Type | Description |
|---|---|---|
name | string | Search by name (partial match) |
reference | string | Filter by reference code |
debtorNumber | string | Filter by debtor number |
invoiceEmail | string | Filter by invoice email |
inTreeOfCustomerId | integer | All customers within this customer's hierarchy |
parentId | integer | Direct children of this customer |
phonenumberAnywhere | string | Search by phone number across services and users |
curl "{{BASE_URL}}/customers?inTreeOfCustomerId=1234" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/customers', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['inTreeOfCustomerId' => 1234],
]);
$customers = json_decode($response->getBody(), true);
Create a customer
curl -X POST "{{BASE_URL}}/customers" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "New Customer BV",
"parent": "/customers/1234",
"customerType": "/customer-types/1",
"reference": "NC001",
"invoiceEmail": "invoices@example.nl"
}'
$response = $client->post('/customers', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'json' => [
'name' => 'New Customer BV',
'parent' => '/customers/1234',
'customerType' => '/customer-types/1',
'reference' => 'NC001',
'invoiceEmail' => 'invoices@example.nl',
],
]);
/customers/1234, not just 1234.Example response
{
"@id": "/customers/1234",
"@type": "Customer",
"id": 1234,
"name": "Acme Telecom BV",
"reference": "ACM001",
"debtorNumber": "D10042",
"invoiceEmail": "facturen@acme-telecom.nl",
"parent": "/customers/100",
"customerType": "/customer-types/1",
"accountManager": "/users/56",
"isActive": true,
"invoiceOnCustomerId": null,
"visitLocation": { "street": "Keizersgracht", "houseNumber": "100", "zipcode": "1015AA", "city": "Amsterdam" },
"paymentMethod": "direct_debit",
"paymentTerm": 30,
"vatReversedCharge": false,
...
}
↳ Trimmed for brevity — see the Swagger UI (Schemas) for the complete, always-current field list.
Common errors when creating/updating customers
| Error | Cause | Fix |
|---|---|---|
400 "parent: This value should not be blank" | Missing parent reference | Include "parent": "/customers/{id}" in IRI format |
400 "customerType: This value should not be null" | Missing customer type | Include "customerType": "/customer-types/{id}" |
403 Access Denied | Parent customer not in your tree | Verify the parent ID is within your reseller's hierarchy |
400 "reference: This value is already used" | Duplicate reference code | Use a unique reference or use PUT to sync/upsert |
Orders (Services)
Get services for a customer
Query Parameters
| Parameter | Type | Description |
|---|---|---|
customer.id | integer | Filter by customer |
includeTree | integer | Set to 1 to include child customers' orders |
inTreeOfCustomerId | integer | All orders in this customer's hierarchy |
supplier.id | integer | Filter by supplier |
serviceType.id | integer | Filter by service type |
curl "{{BASE_URL}}/orders?customer.id=1234&includeTree=1" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/orders', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['customer.id' => 1234, 'includeTree' => 1],
]);
$orders = json_decode($response->getBody(), true);
Get monthly recurring revenue
curl "{{BASE_URL}}/orders/5678/recurring-revenue" \
-H "Authorization: Bearer $TOKEN"
# Response: { "activeRevenue": 149.95, "pendingRevenue": 25.00 }
$response = $client->get('/orders/5678/recurring-revenue', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$revenue = json_decode($response->getBody(), true);
// $revenue['activeRevenue'], $revenue['pendingRevenue']
Example response
{
"@id": "/orders/5678",
"@type": "Order",
"id": 5678,
"customer": "/customers/1234",
"serviceType": "/service-types/3",
"supplier": "/suppliers/10",
"label": "Internet 1Gbps Fiber",
"description": "Glasvezel aansluiting Keizersgracht 100",
"dateStart": "2024-01-15",
"dateEnd": null,
"isActive": true,
"costCenter": "HQ-NET",
"contract": "/contracts/89",
"location": { "street": "Keizersgracht", "houseNumber": "100", ... },
"orderDetailsGeneric": "/order-details-generics/5678",
"parentId": null,
"children": [],
...
}
↳ Trimmed for brevity — see the Swagger UI (Schemas) for the complete, always-current field list.
orderDetailsGeneric field points to the typed detail sub-resource. Depending on the service type, there may also be an orderDetailsX2voip, orderDetailsConnection, or another typed detail IRI.Grouped services (parent-child)
Services can be grouped in a 1-level parent-child hierarchy. Every order response includes two read-only fields:
| Field | Type | Parent service | Child service | Standalone service |
|---|---|---|---|---|
parentId | integer / null | null | ID of the parent order | null |
children | array of {id} | Non-empty — contains child IDs | [] | [] |
{
"id": 1200,
"description": "Bundled internet + VoIP",
"parentId": null,
"children": [
{ "id": 1201 },
{ "id": 1202 }
],
...
}
↳ Trimmed for brevity — see the Swagger UI (Schemas) for the complete, always-current field list.
{
"id": 1201,
"description": "VoIP add-on",
"parentId": 1200,
"children": [],
...
}
↳ Trimmed for brevity — see the Swagger UI (Schemas) for the complete, always-current field list.
Billing Deals
Get active subscriptions
Query Parameters
| Parameter | Type | Description |
|---|---|---|
invoicerId required | integer | The reseller/invoicer customer ID |
invoiceeId | integer | The customer being invoiced |
orderId | integer | Filter by order (service) |
type | string | sales or purchase |
onlyActive | boolean | Only return active deals |
costCenter | string | Filter by cost center |
relatedDescription | string | Filter by related description (substring match) |
# invoicerId is required
curl "{{BASE_URL}}/billing-deals?invoicerId=1234&onlyActive=true&type=sales" \
-H "Authorization: Bearer $TOKEN"
$deals = $client->get('/billing-deals', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => [
'invoicerId' => 1234,
'onlyActive' => true,
'type' => 'sales',
],
]);
// Sum rateEnduser for monthly recurring revenue
$data = json_decode($deals->getBody(), true);
$mrr = array_sum(array_column($data, 'rateEnduser'));
Example response
{
"@id": "/billing-deals/9001",
"@type": "BillingDeal",
"id": 9001,
"type": "sales",
"billingType": "recurring",
"orderId": 5678,
"invoicerId": 100,
"invoiceeId": 1234,
"product": "/products/42",
"billingDealPeriod": "/billing-deal-periods/1",
"rateEnduser": 49.95,
"ratePurchase": 32.50,
"dateStart": "2024-01-15",
"dateEnd": null,
"billedUntil": "2026-04-30",
"invoiceLineLabel": "Internet 1Gbps Fiber",
"costCenter": "HQ-NET",
"computedRelatedDescription": "Internet 1Gbps Fiber (KPN EZT-12345)",
"contract": "/contracts/89",
...
}
↳ Trimmed for brevity — see the Swagger UI (Schemas) for the complete, always-current field list.
computedRelatedDescription. It is read-only and derived from the entity the deal is linked to (e.g. a phone number or service label), unless a manual override is set via relatedDescription — the "Aangaande / extra omschrijving" field on the billing-deal edit form. The override is writable through POST/PATCH and is not shown on invoices, only in the portal GUI. See also Portal GUI ↔ API field mapping.rateEnduser and ratePurchase are always monthly rates. A quarterly billing deal with rateEnduser: 49.95 generates a €149.85 invoice line per quarter.Invoices
Get unpaid invoices
Query Parameters
| Parameter | Type | Description |
|---|---|---|
invoiceeId | integer | The customer who receives the invoice |
inTreeOfInvoiceeId | integer | All invoices in a customer hierarchy |
invoiceDateFrom | string | Start date (YYYY-MM-DD) |
invoiceDateTo | string | End date (YYYY-MM-DD) |
paymentStatus | string | paid, partial, or unpaid |
type | string | end-user, commission, or reseller |
exclude | array | Exclude: invoiceLines, invoiceUploads |
curl "{{BASE_URL}}/invoices?invoiceeId=1234&paymentStatus=unpaid" \
-H "Authorization: Bearer $TOKEN"
# Download PDF:
curl "{{BASE_URL}}/invoices/9999/get-pdf" \
-H "Authorization: Bearer $TOKEN" \
-o invoice_9999.pdf
$invoices = $client->get('/invoices', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => [
'invoiceeId' => 1234,
'paymentStatus' => 'unpaid',
],
]);
// Download PDF:
$pdf = $client->get("/invoices/9999/get-pdf", [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
file_put_contents('invoice.pdf', $pdf->getBody());
Example response
{
"@id": "/invoices/9999",
"@type": "Invoice",
"id": 9999,
"invoicerId": 100,
"invoiceeId": 1234,
"invoiceNumber": "INV-2026-0042",
"invoiceDate": "2026-04-01",
"type": "end-user",
"state": "invoiced",
"paymentStatus": "unpaid",
"amountExclVat": 149.85,
"amountVat": 31.47,
"amountInclVat": 181.32,
"amountPaid": 0,
"yourReference": "PO-2026-100",
"invoiceLines": [
{ "@id": "/invoice-lines/50001", "description": "Internet 1Gbps Fiber (jan-mrt)", "amountExclVat": 149.85, ... }
],
...
}
↳ Trimmed for brevity — see the Swagger UI (Schemas) for the complete, always-current field list.
Invoice Lines & Billing Rules
Both require invoiceId as parameter. Billing rules are read-only.
CDR Totals (Usage Data)
dateTo: This is the last day of the month (e.g., 2026-03-31 = all of March 2026). It represents the entire month, not a single day.Response Fields
| Property | Type | Description |
|---|---|---|
orderId | integer | The service this usage belongs to |
cli | string | Phone number (Calling Line ID) |
dateTo | string | Last day of month (= month identifier) |
calls | integer | Number of calls |
duration | integer | Total seconds |
cost1 / cost2 / cost3 | float | Cost tiers |
billingRuleId | integer/null | If set → usage has been invoiced |
Supports high pagination — up to 50,000 items per page.
curl "{{BASE_URL}}/cdr-totals?itemsPerPage=500" \
-H "Authorization: Bearer $TOKEN"
$cdrTotals = $client->get('/cdr-totals', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['itemsPerPage' => 500],
]);
$data = json_decode($cdrTotals->getBody(), true);
// Find unbilled usage:
$unbilled = array_filter($data, fn($c) => $c['billingRuleId'] === null);
Service Orders
Provisioning requests to create, modify, or terminate services.
Service orders have typed detail objects depending on the service type. Check the Swagger UI for the full list of POST examples per service type.
Check service order status
# Get service orders for a customer
curl "{{BASE_URL}}/service-orders?customer.id=1234" \
-H "Authorization: Bearer $TOKEN"
# Cancel a pending service order
curl -X POST "{{BASE_URL}}/service-orders/7890/cancel" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/service-orders', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['customer.id' => 1234],
]);
$orders = json_decode($response->getBody(), true);
// Cancel a pending service order
$client->post('/service-orders/7890/cancel', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
Common errors when creating service orders
| Error | Cause | Fix |
|---|---|---|
400 validation errors | Missing or invalid fields in the request body | Each service type requires different fields — check Swagger UI examples for the exact payload per type |
403 Access Denied | Customer not in your tree, or service orders not enabled | Verify customer access and that your reseller has service order permissions |
400 "customer: This value should not be null" | Missing customer IRI | Include "customer": "/customers/{id}" |
Service Order Tasks
Tasks associated with service orders. Each service order can have one or more tasks that track the individual steps required to complete the order (e.g., porting tasks, provisioning steps).
List tasks for a service order
curl "{{BASE_URL}}/service-order-tasks?serviceOrder=/service-orders/123" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/service-order-tasks', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['serviceOrder' => '/service-orders/123'],
]);
$tasks = json_decode($response->getBody(), true);
Service Order Products
Products attached to a service order. These represent the specific products that are being ordered, changed, or terminated as part of a service order.
Get product details for a service order
curl "{{BASE_URL}}/service-order-products/456" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/service-order-products/456', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$product = json_decode($response->getBody(), true);
Users
List users
Query Parameters
| Parameter | Type | Description |
|---|---|---|
customerId | integer | Filter by customer |
email | string | Filter by email address |
curl "{{BASE_URL}}/users?customerId=1234" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/users', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['customerId' => 1234],
]);
$users = json_decode($response->getBody(), true);
allowApiLogin = true to authenticate via the API. The IP whitelist is enforced unless bypassApiWhitelist = true.Contracts
Contracts define commercial terms between a contractor (reseller) and a contractee (customer). They can contain billing deal periods, cost centers, and date ranges.
Get contracts for a customer
Query Parameters
| Parameter | Type | Description |
|---|---|---|
contractee | integer | Filter contracts by contractee (customer) ID |
curl "{{BASE_URL}}/contracts?contractee=1234" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/contracts', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['contractee' => 1234],
]);
$contracts = json_decode($response->getBody(), true);
Contract Purchases
Contract purchases link purchase billing deals to contracts. They represent the cost side of a contract, tracking what the reseller pays the supplier for a specific contract.
Get purchases for a contract
curl "{{BASE_URL}}/contract-purchases?contract=/contracts/123" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/contract-purchases', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['contract' => '/contracts/123'],
]);
$purchases = json_decode($response->getBody(), true);
Groups
Groups allow organizing customers into logical collections. A group can be used for reporting, filtering, or applying shared configuration across multiple customers.
List groups
curl "{{BASE_URL}}/groups" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/groups', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$groups = json_decode($response->getBody(), true);
Invoice Lines
Invoice lines are the individual charges on an invoice, generated from billing rules during the invoice run. This is a read-only resource.
Get lines for an invoice
Query Parameters
| Parameter | Type | Description |
|---|---|---|
invoiceId required | integer | The invoice ID to retrieve lines for |
curl "{{BASE_URL}}/invoice-lines?invoiceId=9999" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/invoice-lines', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['invoiceId' => 9999],
]);
$lines = json_decode($response->getBody(), true);
Billing Rules
Billing rules are intermediate calculation records generated during the invoice run. They determine how billing deals translate into invoice lines. This is a read-only resource with high pagination support (up to 50,000 items).
accepted, forced, waiting, failed, skipped, ignored, processed.Get billing rules for an invoice
Query Parameters
| Parameter | Type | Description |
|---|---|---|
invoiceId | integer | Filter by invoice |
curl "{{BASE_URL}}/billing-rules?invoiceId=9999&itemsPerPage=500" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/billing-rules', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['invoiceId' => 9999, 'itemsPerPage' => 500],
]);
$rules = json_decode($response->getBody(), true);
CDRs (CSV Export)
Export raw Call Detail Records as a CSV file. This endpoint returns CSV data rather than JSON, suitable for bulk data processing. Pagination is fixed at 50,000 records.
text/csv format, not JSON. Use appropriate accept headers or handle the response as plain text.Export CDR records
curl "{{BASE_URL}}/cdrs" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/csv" \
-o cdrs_export.csv
$response = $client->get('/cdrs', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'text/csv',
],
]);
file_put_contents('cdrs_export.csv', $response->getBody());
Reports (CSV Export)
Run the portal's custom reports. First list the reports you are allowed to run, then download any of them as a CSV file. Which reports you see and may download is governed entirely by the portal — your reseller tree, your role/audience, per-report user-group restrictions, and a per-report API toggle. The API enforces no rules of its own; a report you are not entitled to simply does not appear in the list and returns 403 Forbidden on download.
List available reports
Returns the reports available to you. Each entry includes its id, name, description, category and the column headers the CSV will contain.
curl "{{BASE_URL}}/reports" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/reports', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$reports = json_decode($response->getBody(), true);
Example response:
[
{
"id": 42,
"name": "Monthly revenue per customer",
"description": "Recurring revenue grouped by customer",
"category": "Finance",
"headers": ["customer", "reference", "revenue"],
"csv_only": false
}
...
]
Download a report as CSV
Streams the chosen report as a CSV file. Values use a semicolon (;) column separator and a point (.) as the decimal separator. Pass the id from the list endpoint.
text/csv format, not JSON. Use appropriate accept headers or handle the response as plain text. If you are not allowed to run the report (or it is not exposed to the API), it responds with 403 Forbidden and a JSON error body.curl "{{BASE_URL}}/reports/42/export-csv" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/csv" \
-o report.csv
$response = $client->get('/reports/42/export-csv', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'text/csv',
],
]);
file_put_contents('report.csv', $response->getBody());
Raw CDRs
Access raw CDR/XDR data with detailed call-level information. Default pagination is 1,000 records, maximum 20,000. Requires superuser or wholesaler privileges.
Get raw CDR data
curl "{{BASE_URL}}/raw-cdrs?itemsPerPage=5000" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/raw-cdrs', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['itemsPerPage' => 5000],
]);
$rawCdrs = json_decode($response->getBody(), true);
Products
Products represent items from the product catalog that can be attached to billing deals. You can also look up pricing per customer and query KPN products available at a specific address.
Get product pricing for a customer
# Get price for product 42, customer 1234
curl "{{BASE_URL}}/products/42/prices/1234" \
-H "Authorization: Bearer $TOKEN"
# Response: { "finalPrice": 24.95, "isCustomerPrice": true }
$response = $client->get('/products/42/prices/1234', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$pricing = json_decode($response->getBody(), true);
// $pricing['finalPrice'], $pricing['isCustomerPrice']
Check KPN products at an address
curl "{{BASE_URL}}/products/getKpnProducts/1234AB/10/1234?houseNumberExtension=A" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/products/getKpnProducts/1234AB/10/1234', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['houseNumberExtension' => 'A'],
]);
$kpnProducts = json_decode($response->getBody(), true);
Tariff Plans
Tariff plans define pricing structures that can be assigned to customers. This is a read-only resource.
List tariff plans
Query Parameters
| Parameter | Type | Description |
|---|---|---|
customerId | integer | Get tariff plans managed by this customer |
curl "{{BASE_URL}}/tariffplans?customerId=1234" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/tariffplans', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['customerId' => 1234],
]);
$plans = json_decode($response->getBody(), true);
Product Categories
Product categories group products at a high level (e.g., "Mobile", "Fixed Line", "Hardware"). Categories contain product-category-products that link individual products.
List product categories
curl "{{BASE_URL}}/product-categories" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/product-categories', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$categories = json_decode($response->getBody(), true);
Product Groups
Product groups organize products for accounting and reporting purposes. They determine which ledger accounts are used when exporting billing deals to accounting software.
List product groups
curl "{{BASE_URL}}/product-groups" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/product-groups', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$groups = json_decode($response->getBody(), true);
Product Plans
Product plans define sets of products with specific pricing, assigned to customers via product-plan-invoicees. Products within a plan are managed via product-plan-products.
Product Plan Invoicees
Link product plans to specific customers (invoicees):
Product Plan Products
Manage products within a plan, including plan-specific pricing:
Get a product plan with its products
# List product plans
curl "{{BASE_URL}}/product-plans" \
-H "Authorization: Bearer $TOKEN"
# Get products in a plan
curl "{{BASE_URL}}/product-plan-products?productPlan=/product-plans/42" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/product-plans', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$plans = json_decode($response->getBody(), true);
// Get products in a specific plan
$response = $client->get('/product-plan-products', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['productPlan' => '/product-plans/42'],
]);
$planProducts = json_decode($response->getBody(), true);
Phone Numbers
Manage phone numbers linked to services (orders). You can filter by order, update cost center and description fields.
Get phone numbers for a service
Query Parameters
| Parameter | Type | Description |
|---|---|---|
orderId | integer | Get all phone numbers from this order (service) |
blockStart | integer | Get phone numbers starting with this number |
excludeOrders | integer | Set to 1 to exclude order data (faster response) |
curl "{{BASE_URL}}/phonenumbers?orderId=5678" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/phonenumbers', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['orderId' => 5678],
]);
$numbers = json_decode($response->getBody(), true);
Update cost center on a phone number
curl -X PATCH "{{BASE_URL}}/phonenumbers/123" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/merge-patch+json" \
-d '{"costCenter": "Sales", "description": "Reception line"}'
$response = $client->patch('/phonenumbers/123', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/merge-patch+json',
],
'json' => [
'costCenter' => 'Sales',
'description' => 'Reception line',
],
]);
SIM Cards
Manage SIM cards (including eSIMs) linked to mobile services. SIM cards contain ICC and IMSI identifiers and are linked to orders.
List SIM cards
curl "{{BASE_URL}}/simcards" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/simcards', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$simcards = json_decode($response->getBody(), true);
Number Blocks
Manage VoIP number blocks. Supports splitting blocks and managing cool-off periods. Requires superuser or wholesaler privileges.
List number blocks
Query Parameters
| Parameter | Type | Description |
|---|---|---|
excludedNumberPoolIds[] | array | Exclude specific number pool IDs |
curl "{{BASE_URL}}/number-blocks" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/number-blocks', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$blocks = json_decode($response->getBody(), true)['hydra:member'];
Split a number block
# Split block 456 into blocks of size 10
curl "{{BASE_URL}}/number-blocks/456/split/10" \
-H "Authorization: Bearer $TOKEN"
# End cool-off period for a number block
curl "{{BASE_URL}}/number-blocks/456/end-cool-off" \
-H "Authorization: Bearer $TOKEN"
// Split block 456 into blocks of size 10
$response = $client->get('/number-blocks/456/split/10', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
// End cool-off period
$response = $client->get('/number-blocks/456/end-cool-off', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
Area Codes
Read-only reference data for Dutch telephone area codes.
List area codes
curl "{{BASE_URL}}/areacodes" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/areacodes', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$areacodes = json_decode($response->getBody(), true);
Tracking Devices
Manage GPS tracking devices linked to services. Devices have unit codes and can be linked to SIM cards and orders.
List tracking devices
Query Parameters
| Parameter | Type | Description |
|---|---|---|
unit_code_filter | string | Filter by unit code |
curl "{{BASE_URL}}/tracking-devices" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/tracking-devices', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$devices = json_decode($response->getBody(), true);
Dashboard (MRR)
Retrieve Monthly Recurring Revenue (MRR) metrics and work-in-progress data for your reseller, specific users, or individual customers.
Endpoints
| Path | Description |
|---|---|
/dashboard/wip | Get WIP one-time and recurring revenue for the reseller |
/dashboard/user/{id} | Get MRR metrics for a specific user (account manager) |
/dashboard/customer/{id}/{filterField} | Get MRR for a customer. filterField can be id or zendesk_sell_id |
Get work-in-progress MRR
# Reseller-wide WIP metrics
curl "{{BASE_URL}}/dashboard/wip" \
-H "Authorization: Bearer $TOKEN"
# MRR for a specific customer
curl "{{BASE_URL}}/dashboard/customer/1234/id" \
-H "Authorization: Bearer $TOKEN"
# MRR by Zendesk Sell ID
curl "{{BASE_URL}}/dashboard/customer/99887766/zendesk_sell_id" \
-H "Authorization: Bearer $TOKEN"
// Reseller-wide WIP
$response = $client->get('/dashboard/wip', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$mrr = json_decode($response->getBody(), true);
// Contains: mrr, active_mrr, wip_mrr, agency_mrr, etc.
Search
Global search across customers, orders, and service orders using Elasticsearch. Returns results grouped by entity type with relevance scores.
Search for customers and services
Query Parameters
| Parameter | Type | Description |
|---|---|---|
query required | string | The search term |
entity | string | Limit to entity type: customer, order, or serviceOrder |
includeInactive | boolean | Include inactive customers in results |
exactMatch | boolean | Require exact match instead of fuzzy search |
# Search across all entities
curl "{{BASE_URL}}/search/getResults?query=acme" \
-H "Authorization: Bearer $TOKEN"
# Search only customers, include inactive
curl "{{BASE_URL}}/search/getResults?query=acme&entity=customer&includeInactive=true" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/search/getResults', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['query' => 'acme', 'entity' => 'customer'],
]);
$results = json_decode($response->getBody(), true);
// Each result: id, entity, customerName, keyword, esScore, etc.
Call Logs
CRM-style call log entries linked to customers. Record phone call subjects and notes.
List call logs
Query Parameters
| Parameter | Type | Description |
|---|---|---|
customer_id required | integer | Get call logs for this customer |
curl "{{BASE_URL}}/call-logs?customer_id=1234" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/call-logs', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['customer_id' => 1234],
]);
$logs = json_decode($response->getBody(), true)['hydra:member'];
Create a call log
curl -X POST "{{BASE_URL}}/call-logs" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customer_id": 1234,
"subject": "Contract renewal discussion",
"additional_information": "Customer wants to upgrade to 1Gbps",
"caller_name": "Jan de Vries"
}'
$response = $client->post('/call-logs', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'json' => [
'customer_id' => 1234,
'subject' => 'Contract renewal discussion',
'additional_information' => 'Customer wants to upgrade to 1Gbps',
'caller_name' => 'Jan de Vries',
],
]);
Uploads
Download files that have been uploaded in the portal (e.g., invoice attachments). This is a read-only resource.
Download an uploaded file
curl "{{BASE_URL}}/uploads/789/download" \
-H "Authorization: Bearer $TOKEN" \
-o downloaded_file.pdf
$response = $client->get('/uploads/789/download', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
file_put_contents('downloaded_file.pdf', $response->getBody());
Service Types
Service types categorize orders (services) into groups like Internet, VoIP, Mobile, etc. They determine which ledger accounts are used for usage exports to accounting software.
List service types
curl "{{BASE_URL}}/service-types" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/service-types', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$serviceTypes = json_decode($response->getBody(), true);
Suppliers
Read-only directory of suppliers (e.g., KPN, VodafoneZiggo) that provide services to resellers.
List all suppliers
curl "{{BASE_URL}}/suppliers" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/suppliers', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$suppliers = json_decode($response->getBody(), true);
Customer Types
Read-only reference data for customer types (e.g., end customer, dealer, wholesaler). Determines access level and billing behavior.
List customer types
curl "{{BASE_URL}}/customer-types" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/customer-types', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$types = json_decode($response->getBody(), true);
Contact Preferences
Manage customer contact preferences. This is one of the few resources that supports DELETE operations.
Manage contact preferences
# List contact preferences
curl "{{BASE_URL}}/contact-preferences" \
-H "Authorization: Bearer $TOKEN"
# Delete a contact preference
curl -X DELETE "{{BASE_URL}}/contact-preferences/123" \
-H "Authorization: Bearer $TOKEN"
// List contact preferences
$response = $client->get('/contact-preferences', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
// Delete a contact preference
$client->delete('/contact-preferences/123', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
Locations
Retrieve location data and ISRA (Infrastructure Standard Reference for Addresses) information for Dutch addresses. Useful for checking fiber/copper availability at a specific address.
ISRA Lookup Parameters
| Parameter | Type | Description |
|---|---|---|
zipcode (path) | string | Dutch postal code (e.g., 1234AB) |
housenumber (path) | string | House number |
housenumberExtension | string | House number extension (e.g., A, bis) |
xdfServiceId | string | Optional XDF service ID for specific service lookup |
Check infrastructure at an address
# Get ISRA information (fiber/copper availability)
curl "{{BASE_URL}}/locations/getIsraInformation/1234AB/10?housenumberExtension=A" \
-H "Authorization: Bearer $TOKEN"
# Response includes carrier type (COPPER/FIBER), FPI, SDF, MDF data
$response = $client->get('/locations/getIsraInformation/1234AB/10', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['housenumberExtension' => 'A'],
]);
$isra = json_decode($response->getBody(), true);
// $isra contains carrier type (COPPER/FIBER), FPI, SDF, MDF data
Order Details Overview
Each Order (service) has exactly one Order Details sub-resource that contains service-type-specific technical information. The type of detail depends on the service type of the order.
| Service Type | Detail Resource | Contains |
|---|---|---|
| Generic / other | /order-details-generics/{id} | Free-form custom fields |
| Internet (connection) | /order-details-connections/{id} | Circuit IDs, connection parameters |
| Odido Mobile | /order-details-odido-mobile/{id} | SIM, IMSI, phone number |
| X2VoIP | /order-details-x2voips/{id} | SIP credentials, trunk config, credit |
| X2Mobile | /order-details-x2mobiles/{id} | SIM, phone number, data usage |
| Youfone | /order-details-youfones/{id} | Network modules, SMS settings |
| KPN WBA | /order-details-kpn-wba-by-order/{orderId} | Line profile, circuit info |
| Allsetra Tracking | /order-details-tracked-objects/{id} | Tracking device, subscription |
How to find the detail for an order
When you GET /orders/{id}, the response includes an IRI reference to the typed detail resource (e.g., "orderDetailsGeneric": "/order-details-generics/5678"). Follow that IRI to retrieve the service-specific details.
/order-details-x2voip-numbers), eFaxes (/order-details-x2voip-efaxes), and scheduled forwards (/order-details-x2voip-numbers-scheduled-forwards).Order Details: Connections
Connection-level details for an order (service). Contains technical connection information such as circuit IDs and connection parameters.
Get connection details
curl "{{BASE_URL}}/order-details-connections/123" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/order-details-connections/123', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$connection = json_decode($response->getBody(), true);
Order Details: Generics
Generic order details for services that don't have a specialized detail type. Can contain free-form data and custom fields.
Get generic order details
curl "{{BASE_URL}}/order-details-generics/456" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/order-details-generics/456', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$details = json_decode($response->getBody(), true);
Order Details: Odido Mobile
Service-specific details for Odido (formerly T-Mobile) mobile subscriptions. Contains SIM, IMSI, phone number, and subscription-level configuration.
Get Odido mobile details
curl "{{BASE_URL}}/order-details-odido-mobile/789" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/order-details-odido-mobile/789', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$odido = json_decode($response->getBody(), true);
Order Details: X2VoIP
VoIP service details for X2VoIP accounts. Contains SIP credentials, trunk configuration, credit balance, and registration status. Supports listing, viewing, updating, and checking low credit accounts and SIP registration status.
List X2VoIP details and check registration
# List X2VoIP accounts
curl "{{BASE_URL}}/order-details-x2voips" \
-H "Authorization: Bearer $TOKEN"
# Check SIP registration status
curl "{{BASE_URL}}/order-details-x2voips/registration/123" \
-H "Authorization: Bearer $TOKEN"
# Get accounts with low credit
curl "{{BASE_URL}}/order-details-x2voips/low-credit-accounts" \
-H "Authorization: Bearer $TOKEN"
// List X2VoIP accounts
$response = $client->get('/order-details-x2voips', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$accounts = json_decode($response->getBody(), true);
// Check SIP registration
$response = $client->get('/order-details-x2voips/registration/123', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$registration = json_decode($response->getBody(), true);
Order Details: X2VoIP Numbers
Phone numbers assigned to X2VoIP accounts. Each number has routing, forwarding, and call handling configuration. Numbers can be split from blocks.
Get X2VoIP number details
curl "{{BASE_URL}}/order-details-x2voip-numbers/456" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/order-details-x2voip-numbers/456', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$number = json_decode($response->getBody(), true);
Order Details: X2VoIP eFaxes
eFax (electronic fax) numbers linked to X2VoIP accounts. Supports viewing and removing eFax numbers.
Get eFax details
curl "{{BASE_URL}}/order-details-x2voip-efaxes/789" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/order-details-x2voip-efaxes/789', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$efax = json_decode($response->getBody(), true);
Order Details: X2VoIP Scheduled Forwards
Manage time-based call forwarding schedules for X2VoIP numbers. Allows creating, updating, and deleting forwarding rules that activate at specific times.
Create a scheduled forward
# List scheduled forwards
curl "{{BASE_URL}}/order-details-x2voip-numbers-scheduled-forwards" \
-H "Authorization: Bearer $TOKEN"
# Create a scheduled forward
curl -X POST "{{BASE_URL}}/order-details-x2voip-numbers-scheduled-forwards" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"orderDetailsX2voipNumber": "/order-details-x2voip-numbers/456", "forwardTo": "0612345678"}'
// List scheduled forwards
$response = $client->get('/order-details-x2voip-numbers-scheduled-forwards', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$forwards = json_decode($response->getBody(), true);
// Create a scheduled forward
$response = $client->post('/order-details-x2voip-numbers-scheduled-forwards', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
],
'json' => [
'orderDetailsX2voipNumber' => '/order-details-x2voip-numbers/456',
'forwardTo' => '0612345678',
],
]);
$forward = json_decode($response->getBody(), true);
Order Details: X2Mobile
Mobile service details for X2Mobile SIM-based subscriptions. Contains SIM data, phone number, and data usage tracking. Supports checking current-month data usage per phone number.
Get X2Mobile details and data usage
# List X2Mobile services
curl "{{BASE_URL}}/order-details-x2mobiles" \
-H "Authorization: Bearer $TOKEN"
# Check current month data usage
curl "{{BASE_URL}}/order-details-x2mobile/current-month-data-usage/0612345678" \
-H "Authorization: Bearer $TOKEN"
// List X2Mobile services
$response = $client->get('/order-details-x2mobiles', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$mobiles = json_decode($response->getBody(), true);
// Check current month data usage
$response = $client->get('/order-details-x2mobile/current-month-data-usage/0612345678', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$usage = json_decode($response->getBody(), true);
Order Details: Youfone
Service details for Youfone mobile subscriptions. Supports viewing settings, changing network modules, managing email addresses, viewing operational actions, and managing SMS notifications.
Get Youfone service details
# Get Youfone details
curl "{{BASE_URL}}/order-details-youfones/123" \
-H "Authorization: Bearer $TOKEN"
# Get network modules
curl "{{BASE_URL}}/order-details-youfones/123/network-modules-details" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/order-details-youfones/123', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$youfone = json_decode($response->getBody(), true);
// Get network module details
$response = $client->get('/order-details-youfones/123/network-modules-details', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$modules = json_decode($response->getBody(), true);
Order Details: KPN WBA
KPN Wholesale Broadband Access (WBA) connection details for an order. Retrieve technical details such as line profile, connection status, and circuit information.
Get KPN WBA details by order
curl "{{BASE_URL}}/order-details-kpn-wba-by-order/789" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/order-details-kpn-wba-by-order/789', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$kpnWba = json_decode($response->getBody(), true);
Order Details: Tracked Objects
Allsetra tracked object details linked to an order. Supports creating, updating, activating subscriptions, moving objects to different customers, and terminating tracked objects.
Manage tracked objects
# List tracked objects
curl "{{BASE_URL}}/order-details-tracked-objects" \
-H "Authorization: Bearer $TOKEN"
# Activate a subscription for a tracked object
curl -X POST "{{BASE_URL}}/order-details-tracked-objects/123/activate-subscription" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"product": "/products/42"}'
// List tracked objects
$response = $client->get('/order-details-tracked-objects', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$objects = json_decode($response->getBody(), true);
// Activate a subscription
$response = $client->post('/order-details-tracked-objects/123/activate-subscription', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
],
'json' => ['product' => '/products/42'],
]);
$result = json_decode($response->getBody(), true);
Tracked Object Tracking Devices
Links between tracked objects and their physical tracking devices. Shows which device is installed in which tracked object.
List device assignments
curl "{{BASE_URL}}/tracked-object-tracking-devices" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/tracked-object-tracking-devices', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$devices = json_decode($response->getBody(), true);
Tracking Device Outages
Report and retrieve outage information for tracking devices. Useful for monitoring device health and connectivity.
Get outage report
curl "{{BASE_URL}}/tracking-device-outages/report" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/tracking-device-outages/report', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$outages = json_decode($response->getBody(), true);
Outports
Outport (number porting out) requests. When a customer is porting their phone numbers to another provider, these requests appear here. Supports approving or denying outport requests.
Handle outport requests
# List outport requests
curl "{{BASE_URL}}/outports" \
-H "Authorization: Bearer $TOKEN"
# Approve an outport
curl -X POST "{{BASE_URL}}/outports/accept-outport" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"id": 123}'
// List outport requests
$response = $client->get('/outports', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$outports = json_decode($response->getBody(), true);
// Approve an outport
$response = $client->post('/outports/accept-outport', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
],
'json' => ['id' => 123],
]);
$result = json_decode($response->getBody(), true);
X2VoIP Routes
Inbound call routes for X2VoIP accounts. Define how incoming calls are handled (ring group, IVR, voicemail, etc.).
List routes
curl "{{BASE_URL}}/x2voip-routes" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/x2voip-routes', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$routes = json_decode($response->getBody(), true);
X2VoIP Outbound Routes
Outbound call routing rules for X2VoIP accounts. Control how outgoing calls are routed through different trunks or carriers.
List outbound routes
curl "{{BASE_URL}}/x2voip-outbound-routes" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/x2voip-outbound-routes', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$outboundRoutes = json_decode($response->getBody(), true);
X2VoIP Call Barrings
Call barring rules for X2VoIP accounts. Define which call types should be blocked (e.g., international, premium rate).
List call barrings
curl "{{BASE_URL}}/x2voip-call-barrings" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/x2voip-call-barrings', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$barrings = json_decode($response->getBody(), true);
Horizon XDRs
Search Horizon SBC (Session Border Controller) eXtended Detail Records. Provides detailed call records for Horizon-based telephony services.
Search Horizon XDRs
curl "{{BASE_URL}}/horizon-xdrs/search?customerId=1234" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/horizon-xdrs/search', [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['customerId' => 1234],
]);
$xdrs = json_decode($response->getBody(), true);
Contact Person Types
Reference data for contact person types. Defines the roles a contact person can have (e.g., "Technical", "Billing", "Commercial"). Also includes user-specific contact person type assignments.
List contact person types
curl "{{BASE_URL}}/contact-person-types" \
-H "Authorization: Bearer $TOKEN"
$response = $client->get('/contact-person-types', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$types = json_decode($response->getBody(), true);