# Retrieving customer data
The /api/customers/
endpoint enables you to retrieve customer data.
The endpoint allows you to get data for all your customers, which is sometimes very useful. However, if you have a lot of customers and need to get their data synchronized to another system many times a day, you cannot use this API endpoint. Instead check the section on synchronizing data.
# Parameters
The endpoint uses GET and currently supports the following parameters, all optional:
"id" - a comma-separated list of customer IDs, e.g.
?id=12345,42312
. If left out, information on all customers is returned."fields" - a comma-separated list of fields to return in the JSON, e.g.
?fields=data,subscriptions
. The default is "data,active_subscriptions". You can choose between:- "data" - all fields directly on the customer, such as name and email address.
- "active_subscriptions" - summary of currently active subscriptions
- "subscriptions" - all subscriptions with data on each subscription and also information about periods, begin/end dates and products received
- "subscriptions.current_period" - include
current_period
which contains the currently active period, the value isnull
if there is no active period, e.g. a stopped subscription or a subscription starting in the future - "subscriptions.begin" - include
begin
timestamp for each subscription - "subscriptions.cancelled" - include
cancelled
boolean on each subscription,cancelled
is true if a request has been made to stop the subscription - "subscriptions.stop_requested" - include
stop_requested
timestamp on each subscription with the time a request was made to stop the subscription, if any - "subscriptions.price" - include the
price
on each subscription, if set - "subscriptions.payment_agreement" - include a
payment_agreement
on each subscription, if set - "invoices" - invoices for the customer
- "invoices.download_url" - include a
download_url
on each invoice - "invoices.payment_url" - include a
payment_url
on invoices that can be paid - "invoices.lines" - include
lines
on each invoice with information on what is invoiced - "estimated_invoicings" - simulate future processing of the subscriptions for the customer and estimate the invoice lines that would result in
- "history" - log of events related to the customer
- "password" - used in combination with "data" field, this will add the hashed customer password to the data returned
- "password_url" - used in combination with "data" field, for customers without a password this will add a URL where the customer can set their password
- "preauth_token" - used in combination with "data" field, this adds a pre-auth token to each customer making it possible to automatically log them into embedded Iteras components
"max_results" - how many customers to retrieve at most, e.g.
max_results=1000
. If there are more results available, anext_url
is returned which you can use to grab the next page. "max_results" is currently clipped to be between 1-10000. If left out, 10000 will be assumed."iframe" - set if returned URLs are intended to go in an iframe, e.g.
iframe=1
"preauthseconds" - if set, URLs that go to the self-service get a pre-auth token valid for this many seconds so that the customer does not have to login to view that page, e.g.
preauthseconds=3600
makes the URLs valid for an hour-
"estimated_invoicings_until" - extends the simulation in
estimated_invoicings
until this date, e.g.?estimated_invoicings_until=2025-01-08
(max is currently 2 years in the future) - you can also specify a relative date with+3m
for "3 months from now" -
"filter" - a set of conditions to filter the returned customers by, in JSON, e.g.
?filter=[{ "condition_type": "customer:field", "field": ":Custom field", "operator": "filledin" }]
-
"extrafield" - can be repeated to get additional computed fields, e.g.
?extrafield=delivered_to:formatted&extrafield=delivered_to:address:postcode
Some parameters, e.g. filter
and extrafield
,
contain special characters - remember to URL encode them.
# Return value
The data returned is an object with an array of customer information (possibly empty array).
Note that the content of the "data" fields depends on what fields have been set up inside Iteras and filled in on a given customer and subscription. In general, only filled-in fields are returned, so for instance if a customer doesn't have a particular field set, it won't show up in that customer's data.
Try calling the API on a known customer and see what you get back. Here's an example with a few extra fields:
GET /api/customers/?id=12345,12346&fields=data,active_subscriptions
{
"customers": [
{
"id": "12345",
"data": {
"name": "Test Person",
"email": "someone@example.com",
"formatted_address": "Test Person\nRådhuspladsen 2, 3. th.\n1550 København V\nDenmark",
"location": "Rådhuspladsen 2, 3. th.\n1550 København V", // address without name or country
"country_name": "Denmark",
"country_code": "DK",
"created": "2024-07-08T21:03:07.202945",
":Custom field": "Some value"
},
"active_subscriptions": [
{
"campaign_name": "3 issues",
"campaign_customer_facing_name": "Beautiful 3 issues",
"campaign_id": "3i",
"group": "recipient", // "recipient", "admin" or "admin+recipient"
"group_customer_id": "123456", // filled in if it's a recipient subscription
"group_subscription_id": "654321" // points to the admin subscription
}
]
},
...
]
}
Note that Iteras internally has more processing information about the customers and subscriptions - subscription management can be relatively complex. If you need more than what's currently available, please contact us.
# Subscriptions
Here's an example where subscriptions are requested:
GET /api/customers/?id=12345,12346&fields=subscriptions,subscriptions.price,subscriptions.payment_agreement
{
"customers": [
{
"id": "12345",
"subscriptions": [
{
"id": "32134123",
"state": "active" // or suspended/ended/stopped
"data": {
":Custom subscription field": "Value here"
},
"price": 99.95, // included if "subscriptions.price" specified
"currency": "EUR", // included if "subscriptions.price" specified
"products": [ // only filled in if there are individual products assigned to the subscription itself
{
"id": "9976483", // id of product assignment
"name": "Name",
"external_id": "External ID",
"data": {
":Custom product field": "Product value",
}
}
],
"group": "admin", // "recipient", "admin" or "admin+recipient"
"periods": [
{
"campaign_name": "3 issues",
"campaign_customer_facing_name": "Beautiful 3 issues",
"campaign_id": "3i",
"begin": "2024-08-08",
"end": null,
"current": true, // if the period is currently active
"subscribed_to": [
{
"name": "Subscription Product Name",
"external_id": "External ID"
}
],
"products": [ // products assigned to the period, e.g. issues contained in the subscription
{
"id": "19976483", // id of product assignment
"name": "Name",
"date": "2024-09-08",
"external_id": "External ID"
}
]
}
],
"payment_agreement": { // included if "subscriptions.payment_agreement" specified
"text": "Mastercard: XX...XX2451 (10/2026)"
}
}
]
},
...
]
}
# Invoices
Here's an example where invoices are requested:
GET /api/customers/?id=12345,12346&fields=invoices,invoices.download_url,invoices.payment_url,invoices.lines&iframe=1&preauthseconds=3600
{
"customers": [
{
"id": "12345",
...
"invoices": [
{
"invoice_number": "1001",
"invoice_type": "invoice",
"invoice_date": "2024-07-08",
"due": "2024-07-22",
"to_pay": 120.95, // amount not yet paid (0 if it has been paid)
"download_url": "https://app.iteras.dk/example/iframe/invoice/1001/pdf/?...",
"payment_url": "https://app.iteras.dk/example/iframe/ordering/summary/?invoice=...",
"lines": [
{
"text": "Subscription 1 year",
"amount": 120.95,
"tax_rate": 0.25,
"quantity": 2,
"period_campaign_id": "1y",
"period_begin": "2024-07-08T21:03:07.207850",
"period_end": null,
}
]
},
{
"invoice_number": "1005",
"invoice_type": "reminder",
"invoice_date": "2024-07-29",
"reminder": 1,
"due": "2024-08-12",
"to_pay": 170.95,
"to_be_paid": true, // whether to show this as an invoice to pay, see below
"download_url": "https://app.iteras.dk/example/iframe/invoice/1004/pdf/?...",
"payment_url": "https://app.iteras.dk/example/iframe/ordering/summary/?invoice=...",
"lines": [
{
"text": "Reminder fee",
"amount": 50.0,
"tax_rate": 0,
}
]
}
]
},
...
]
}
The to_be_paid
field on an invoice is set if the
invoice should be presented to be paid. Now, you might think that
you can simply inspect the to_pay
amount, but in case
the customer didn't pay an invoice and is sent a reminder, you may
want to show that reminder instead of the invoice (it could have a
reminder fee to be paid). To make this easier to do,
to_be_paid
is set for the most recent due
invoices/reminders.
If you request a download URL with invoices.download_url
,
you can use preauthseconds
to
get a token appended to the download links to make them work without
logging in for as long as specified.
# Estimated invoicings
You can ask the system to run a simulation of how it would
invoice in the future for the customer and get back an estimate of
that as an approximate timestamp and the associated invoice lines.
You'll usually want to set estimated_invoicings_until
your
time horizon (e.g. 3 months). Here's an example:
GET /api/customers/?id=12345,12346&fields=estimated_invoicings&estimated_invoicings_until=2025-01-08
{
"customers": [
{
"id": "12345",
"estimated_invoicings": [
{
"at": "2024-12-03T21:03:07.210069",
"lines": [
{
"text": "Subscription 1 year",
"amount": 120.95,
"tax_rate": 0.25,
"subscription_id": "4321",
"period_campaign_id": "1y"
}
]
}
]
},
...
]
}
The estimated_invoicings
is
left out if the estimation does not find any future invoicings for the customer.
# History
Here's an example where history is requested:
GET /api/customers/?id=12345,12346&fields=history
{
"customers": [
{
"id": "12345",
...
"history": [
{
"text": "Something else happened",
"timestamp": "2024-06-08T21:03:07.211242",
"by": "System"
},
{
"text": "Something happened",
"timestamp": "2024-07-08T21:03:07.211296",
"by": "somebody@example.com"
}
]
},
...
]
}
# Extra fields
Some fields have extra formatting options you can use. You
request them with an extrafield
parameter. The format
is field_name:formattingoption
. In case you want to
avoid having a field with a ":" in it, you can name the resulting
field with "=" like
field_name:formattingoption=formatted_field_name
. You
can specify extrafield
multiple times to add more fields.
Here's an example:
GET /api/customers/?id=12345&extrafield=delivered_to%3Aformatted&extrafield=delivered_to%3Apostcode%3Dpostcode
{
"customers": [
{
"id": "12345",
"data": {
"delivered_to:formatted": "John Doe\nSome Road 123\n1000 København K\nDanmark",
"postcode": "1000",
...
}
}
]
}
Currently address fields support the following formatting options:
- "formatted" - multi-line textual representation of name, company, address and country
- "postcode" - use the address parser in Iteras to try to extract the postcode
- "address:split" - use the address parser in Iteras to try to split the address itself into components
# Pagination
To avoid having to handle a too large JSON document both in the
sending and receiving end, the results are divided into pages. You
can set the page size with max_results
. If a query
finds more results than what fits into the first page, the returned
result contains a next_url
where you can retrieve the
next page, which may in turn have a next_url
. Here's
an example with 103 customers and a page size of 100:
GET /api/customers/?max_results=100
{
"customers": [customer1, customer2, ..., customer100],
"next_url": "https://app.iteras.dk/api/customers/?max_results=100&from=101"
}
Then when you query next_url
, you get the remaining
customers - note that since this is the end of the results, there
is no next_url
in
the last page:
GET /api/customers/?max_results=100&from=101
{
"customers": [customer101, customer102, customer103]
}
If you write code that may return a lot of customers, you should set max_results
to
a low value while you test your code to make sure you can handle
the pagination correctly.
# Filtering
The filter
parameter can either be a single condition or an array of conditions.
Each condition has a type condition_type
which specifies
what will be filtered on:
-
"customer:field": Customer must have a custom field matching the condition, e.g.
?filter=[{ "condition_type": "customer:field", "field": ":Custom field", "operator": "filledin" }]
.The field id is provided as
field
, andoperator
is one of:- "filledin" or "notfilledin" - satisfied/not satisfied if the field has a value (not an empty string or false)
- "equal" or "notequal" - satisfied/not satisfied if the field has the value specified by
value
, e.g.?filter=[{ "condition_type": "customer:field", "field": "email", "operator": "equal", "value": "customer@example.com" }]
-
"subscription:field": Customer must have a subscription with a field matching the condition. The field condition work as in the same manner as "customer:field".
-
"subscription:state": Customer must have a subscription in the given
state
, e.g.?filter=[{ "condition_type": "subscription:state", "state": "active" }]
.Currently,
state
can be "active".
Note that a subscription filter besides filtering which customers are returned also filters the subscriptions returned on those customers.
# Synchronizing data
In order to synchronize data to another system continuously, you need to setup the Iteras webhook infrastructure. This way you will be notified when a customer has changed and get sent their new data.
Once you have a webhook setup and tested, you can use this API endpoint to get all the data to get in sync, and then simply rely on the webhook to tell you what's changed. In this way, the latency between a change happening and it being available in your end is minimal, with little load.
The webhooks are fault-tolerant so if something bad happens you will just get the changes resent. If something went wrong in your end, you can also rewind the webhooks a bit, or do a full resync through this API endpoint.
Just be aware that unless you have very few customers, or only resync infrequently, you do need to use the webhooks. We do not support using this API endpoint for frequent large synchronizations.