Developer documentation

Retrieving data

get https://app.iteras.dk/api/customers/

This endpoint is the entry point for retrieving data for one or more customers. Besides the fields directly on the customer, it gives access to subscriptions, products, invoices, payments, temporary overrides, complaints and computed fields. Pick exactly which of you want with the fields parameter.

Note that if you have a lot of customers and need to get their data synchronized to another system, you should not use this API endpoint only. Instead check our guide on synchronizing data.

Parameters

All parameters are optional.

  • id string
    A comma-separated list of customer IDs, e.g. ?id=12345,42312. If left out, information on all customers is returned.
  • max_results integer Defaults to 10000
    How many customers to retrieve at most, e.g. max_results=1000 (example). If there are more results available, a next_url is returned which you can use to grab the next page. "max_results" is currently clipped to be between 1-10000.
  • fields string Defaults to data,active_subscriptions
    A comma-separated list of fields to return in the JSON, e.g. ?fields=data,subscriptions, see below for the list.
  • filter JSON
    A set of conditions to filter the returned customers by, e.g. ?filter=[{ "condition_type": "customer:field", "field": ":Custom field", "operator": "filledin" }] (example).
  • extrafield string
    Can be repeated to get additional computed fields, e.g. ?extrafield=delivered_to:formatted&extrafield=delivered_to:address:postcode.
  • iframe boolean
    Set if returned URLs are intended to go in an iframe, e.g. iframe=1.
  • preauthseconds integer
    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 date
    Extends the simulation in estimated_invoicings until this date, e.g. ?estimated_invoicings_until=2027-01-09 (max is currently 2 years in the future) - you can also specify a relative date with +3m for "3 months from now".
  • filter_from date
    Filter the various extra entries returned for a customer, omitting data older than this date, e.g. ?filter_from=2026-07-09 - you can also specify a relative date with -3m for "3 months ago". If this filter is used when fetching invoices, payments or history entries for customers, only invoices, payments or history entries created after the date is returned.

Some parameters, e.g. filter and extrafield, contain special characters - remember to URL encode them.

An invalid filter or extrafield, or a missing preauthseconds when requesting preauth_token, returns a plain text HTTP 400 error.

Available fields

  • 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 (example).
  • subscriptions.current_period
    Include current_period which contains the currently active period, the value is null if there is no active period, e.g. a stopped subscription or a subscription starting in the future.
  • subscriptions.begin
    Include subscription_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.end
    Include subscription_end timestamp on each subscription, if any can be deduced and it is to stop or has stopped.
  • subscriptions.invoice_lines_calculated_for_current_campaign
    Include list of invoice lines that would be invoiced on the current campaign for a full period on the subscription (the format is the same as for invoices, but with an additional campaign_id of the current campaign).
  • subscriptions.price
    Include the price field on each subscription, if filled in (this can only be done if dynamic pricing is enabled on the current campaign).
  • subscriptions.payment_agreement
    Include a payment_agreement on each subscription, if set.
  • subscriptions.allowed_complaints
    Include an allowed_complaint_dates list and an allowed_complaint_reason_codes list on each subscription, if set.
  • subscriptions.policy
    Include policy id and external_id on each subscription if any.
  • subscriptions.invoiced_by
    Include invoiced_by description on each subscription if any.
  • products
    Products that are assigned to the customer (example).
  • invoices
    Invoices, reminders and credit notes for the customer (example).
  • 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.
  • payments
    Payments made by the customer (example).
  • balance
    A list of the customer balance amount (paid - invoiced) for each business entity.
  • overrides
    Overrides for the customer, e.g. vacations or future changes (example).
  • complaints
    Distribution complaints by the customer (example).
  • segments
    Segments the customer is part of (example).
  • estimated_invoicings
    Simulate future processing of the subscriptions for the customer and estimate the invoice lines that would result in (example).
  • history
    Human readable log of history related to the customer (this should not be used for analytics, instead retrieve events directly).
  • 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.

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,balance{
  "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": "2026-07-09T01:38:53",
        ":Custom field": "Eksempeltekst",
        ":Custom date field": "2026-09-09"
      },

      "active_subscriptions": [
        {
          "period_id": "8723465",
          "subscription_id": "7612471",
          "campaign_name": "3 issues",
          "campaign_customer_facing_name": "Beautiful 3 issues",
          "campaign_id": "3i",
          "group_customer_id": "123456",     // filled in if it's a recipient subscription
          "group_subscription_id": "654321"  // points to the group subscription
        },
        {
          "period_id": "8723465",
          "subscription_id": "7612472",
          "campaign_name": "6 months",
          "campaign_customer_facing_name": "6 months of bliss",
          "campaign_id": "6m",
          "addon_base_subscription_id": "7612471"  // filled in with base subscription if this is an add-on subscription to the base
        }
      ],

      "balance": [
        {
          "amount": -99.95,
          "currency": "EUR",
          "business_entity": "DKbusiness",         // included if the business entity han an external ID
        }
      ]

    },

    // ...
  ]
}

Note that Iteras internally maintains more processing information about the customers and subscriptions - subscription management can be relatively complex. If you need more than what's currently available, please ask us.

Subscriptions

Here's an example where subscriptions are requested:

GET /api/customers/?id=12345,12346&fields=subscriptions,subscriptions.price,subscriptions.payment_agreement,subscriptions.allowed_complaints,subscriptions.invoiced_by{
  "customers": [
    {
      "id": "12345",

      "subscriptions": [
        {
          "id": "32134123",
          "state": "active",                 // or suspended/awaiting/ended/stopped
          "business_entity": "DKbusiness",   // included if the business entity has an external ID
          "data": {
            "created": "2026-08-09T01:38:53",
            ":Custom subscription field": "Eksempeltekst"
          },
          "price": 99.95,                    // included if "subscriptions.price" specified
          "currency": "EUR",                 // included if "subscriptions.price" specified
          "invoiced_by": "E-mail",           // included if "subscriptions.invoiced_by" 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",
              ":Custom product field": "Some value",
              "data": {
                ":Custom product assignemnt field": "Product value",
              }
            }
          ],
          "periods": [
            {
              "id": "835270",
              "campaign_name": "3 issues",
              "campaign_customer_facing_name": "Beautiful 3 issues",
              "campaign_id": "3i",
              "begin": "2026-08-09",
              "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": "2026-09-09",
                  "external_id": "External ID",
                }
              ]
            }
          ],
          "payment_agreement": {             // included if "subscriptions.payment_agreement" specified
            "id": "75493106",
            "text": "Mastercard: XX...XX2451 (10/2028)",
            "created": "2024-10-09T01:38:53"
          },
          "group_customer_id": "123456",     // filled in if it's a recipient subscription
          "group_subscription_id": "654321", // points to the group subscription
          "addon_base_subscription_id": "654322", // filled in with base subscription if this is an add-on subscription to the base
          "allowed_complaint_dates": [
            "2026-10-06",
            "2026-10-08"
          ],
          "allowed_complaint_reason_codes": [
            "20",
            "25"
          ]
        }
      ]
    },

    // ...
  ]
}

Products

Products assigned to the customers.

Here's an example:

GET /api/customers/?id=12346&fields=products{
  "customers": [
  {
    "id": "123456",
    // ...
    "products": [              // products assigned directly to the customer, i.e. a bought voucher
      {
        "id": "66388",         // ID of the product assignment
        "external_id": "voucher24",
        "name": "Voucher product",
        "customer_facing_name": "13 issues of interresting stuff",
        "created": "2026-09-09T01:38:53",
        ":Custom product field": "Eksempeltekst",
        "business_entity": "DKbusiness",   // included if the business entity has an external ID
        // if the product is a voucher product the fields below will be present when the voucher has been redeemed
        "redeemed": "2026-10-08T01:38:53",
        "redeemed_by": "352",               // customer number of the redeeming customer
        "redeemed_subscriptions": ["73652"],         // IDs of the subscriptions created with the voucher
      }
    ]
  ]
}

Invoices

The term invoices also covers both reminders and credit notes.

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": "2026-07-09",
          "due": "2026-07-23",
          "invoiced_by": "Payment card",
          "to_pay": 120.95,                   // amount not yet paid (0 if it has been paid)
          "business_entity": "DKbusiness",    // included if the business entity has an external ID
          "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,                    // amount with tax
              "tax_rate": 0.25,
              "tax_amount": 24.19,
              "quantity": 2,
              "category": "subscription",
              "period_campaign_id": "1y",
              "period_begin": "2026-07-09T01:38:53",
              "period_end": null,
              "period_id": "7632784",
              "subscription_id": "275498",
              "products": [     // only if the line is associated with specific products
                {
                  "id": "7365",
                  "name": "My product",
                  "customer_facing_name": "The best product",
                  "external_id": "my_prod"
                }
              ]
            },
            {
              "text": "Extra book",
              "amount": 550.00,                    // amount with tax
              "tax_rate": 0.25,
              "tax_amount": 110.00,
              "category": "product",
              "product_assignment": "73529" // ID of the product assignment (if any)
            }
          ]
        },
        {
          "invoice_number": "1005",
          "invoice_type": "reminder",
          "invoice_date": "2026-07-30",
          "reminder": 1,
          "due": "2026-08-13",
          "invoiced_by": "Payment card",
          "to_pay": 170.95,
          "to_be_paid": true,                 // whether to show this as an invoice to pay, see below
          "business_entity": "DKbusiness",    // included if the business entity has an external ID
          "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,
              "tax_amount": 0,
              "category": "reminderfee"
            }
          ]
        },
        {
          "invoice_number": "4",
          "invoice_type": "creditnote",
          "invoice_date": "2026-08-06",
          "to_pay": -20.75,               // as this is a credit note the amount is negative
          "business_entity": "DKbusiness",    // included if the business entity has an external ID
          "download_url": "https://app.iteras.dk/example/invoice/4/pdf/?...",
          "lines": [
            {
              "text": "Credited due to circumstances",
              "amount": -20.75,
              "tax_rate": 0.25,
              "tax_amount": -4.15,
              "quantity": 0.5,
              "category": "subscription",
              "period_campaign_id": "1y",
              "period_begin": "2026-07-09T01:38:53",
              "period_end": null
            }
          ]
        }
      ]
    },

    // ...
  ]
}

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=2027-01-09{
  "customers": [
    {
      "id": "12345",
      "estimated_invoicings": [
        {
          "at": "2026-12-03T01:38:53",
          "lines": [
            {
              "text": "Subscription 1 year",
              "amount": 120.95,                    // amount with tax
              "tax_rate": 0.25,
              "tax_amount": 24.19,
              "category": "subscription",
              "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.

Payments

You can fetch the payments for customers using the payments field. The result consists of the payments from the customer (not refunds).

GET /api/customers/?id=12345,12346&fields=payments{
  "customers": [
    {
      "id": "12345",
      "payments": [
        {
          "amount": 175.95,
          "currency": "DDK",
          "registered_date": "2026-10-06T01:38:53",
          "account_date": "2026-10-06",
          "method": "manual",
          "business_entity": "DKbusiness",   // included if the business entity has an external ID
          "allocated_to": [
            {
              "amount": 100.00,
              "invoice_number": "73527"
            },
          ]
        }
      ]
    },

    // ...
  ]
}

Overrides

You can fetch the overrides for customers using the overrides field.

You should use the filter filter_from to only fetch overrides beginning after that date, e.g. ?filter_from=2026-04-09 - you can also specify a relative date with -6m for "6 months ago"

GET /api/customers/?id=12345,12346&fields=overrides&filter_from=2025-10-09  {
  "customers": [
    {
      "id": "12345",
      "overrides": [
        {
          "override_id": "77642",
          "type": "alternative-delivery",
          "begin": "2026-09-25T01:38:53",
          "end": "2026-10-02T01:38:53",
          "subscription_id": "1",
          "data": {
            "address": {
              "name": "Some Test",
              "address": "Somewhere Else\n2412 Northpole",
              "country": "DK"
            }
          }
        },
        {
          "override_id": "77643",
          "type": "pause-delivery-donate",
          "begin": "2026-09-11T01:38:53",
          "end": "2026-09-18T01:38:53",
          "subscription_id": "1",
          "data": {
             "donate_amount": 8.28,
             "credit_percentage": 50,
             "donation_recipient_name": "Private Fund"
          }
        }
      ]
    },
    // ...
  ]
}

Complaints

You can fetch distribution complaints by customers using the complaints field.

You should use the filter filter_from to only fetch complaints made on or after that date, e.g. ?filter_from=2026-04-09 - you can also specify a relative date with -6m for "6 months ago"

GET /api/customers/?id=12345,12346&fields=complaints&filter_from=2025-10-09{
"customers": [
  {
    "id": "12345",
      "complaints": [
        {
          "status": "awaiting",
          "complaint_date": "2026-10-08",
          "reason_code": "20",
          "reason_text": "Wet newspaper",
          "compensation": "credit",       // empty if no compensation
          "compensation_amount": 10.25,   // if compensation is 'credit' and complaint is not cancelled
          "extend_subscription_by": 1,    // if compensation is 'extend'
          "subscription_id": "1",
        },
      ]
    },
  ]
}

History

Here's an example where formatted history is requested. Note that this should only be used in case a human-readable version is needed, it should not be used for analytics. Use raw event data for that, currently available through the webhooks.

GET /api/customers/?id=12345,12346&fields=history&filter_from=2026-04-09{
  "customers": [
    {
      "id": "12345",

      // ...

      "history": [
        {
          "text": "Something else happened",
          "timestamp": "2026-06-09T01:38:53",
          "by": "System"
        },
        {
          "text": "Something happened",
          "timestamp": "2026-07-09T01:38:53",
          "by": "somebody@example.com"
        }
      ]

    },

    // ...
  ]
}

Segments

You can fetch a list of the segments that each customer if fullfilling using the segments field. Segments must be setup in the system first.

GET /api/customers/?id=12345&fields=segments{
  "customers": [
    {
      "id": "12345",
        "segments": [
          {
            "name": "Blue segment",
            "external_id": "blue",
          },
        ]
      },
    ]
  }

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": [ /* customer 1 to customer 100 */ ],
  "next_url": "https://app.iteras.dk/api/customers/?max_results=100&from=101"
}

Then when you query next_url, you get the next page of customers - in this example this is the last page of results, so there is no next_url:

GET /api/customers/?max_results=100&from=101{
  "customers": [ /* customer 101 to customer 103 */ ]
}

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.

The from parameter is an internal parameter used for the pagination. Currently it's just the customer number to start at.

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, and operator 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 works as in the same manner as "customer:field". An example filtering on the business entity external ID of the customer subscriptions: ?filter=[{ "condition_type": "subscription:field", "field": "business_entity", "operator": "equal", "value": "DKbranch" }].

  • "subscription:exists": Customer must have a subscription. You can aditionally filter on specific states of the subscription by giving a list of required states, e.g. ?filter=[{ "condition_type": "subscription:exists", "states": ["active","suspended"] }]. States can be one or more of awaiting, active, suspended and ended.

  • "customer:segment": Customer must fullfill the conditions of the given segment, e.g. ?filter=[{ "condition_type": "customer:segment", "external_id": "my_segment" }].

    Note that the segment is identified by its external_id.

Note that a subscription filter besides filtering which customers are returned also filters the subscriptions returned on those customers.