/rest/call/read minDate maxDate not filtering

I’ve tried to use minDate and maxDate on the API call /rest/call/read as stated you should be able to specify scope - https://developer.ipcortex.co.uk/ref/rest/cdr/# however, this doesn’t appear to be working for instance…

adding the unix timestamp for today min and max should probably return 0 results but doesn’t seem to effect the results? Any advice on what I may be doing wrong?

I can see a couple of things in the request that don’t look right…

  1. max/minDate are numbers not strings so I would expect e.g. “minDate”: 1504088068000
  2. definition is an epoch millisecond offset so 11:14 today would be 1504088068000 not 15040880680

Only the first of those could be getting the min/max date ignored as an off by a thousand on the epoch offset would simply cause you to reference a (much) earlier time period which would have no calls and your issue is that you are getting too many calls back. Try sending JSON numbers for the min/maxDate attributes and if that doesn’t work, let me know the PBX firmware version and I will investigate.

Hi Rob,

Thanks for your reply and suggestions. Just tried that and still no luck. The PBX firmware version is

Hi Adam,
Could you post your new code (without PBX credentials obvs). Link to a repo would be fine and I will have someone run it and take a look.

Here you go, I’ve made the demo in Laravel (PHP). Hope that’s OK?

composer install
copy .env.example to .env

update IPCortex details with your details within .env


you’ll need to run php artisan key:generate. Ipcortex service is in app\Services\Ipcortex\Ipcortex.php and the controller is within app\Http\Controller\DemoController

Thanks, that is really helpful and I can reproduce your issue. That does seem to be an API issue in that version in that it doesn’t do what the documentation says.
I will raise this and update you.
In the meantime, I can only suggest pulling all of the records filtering locally if you are only interested in a tight range.

Thanks for looking into that. Yeah I’ve currently got them pulling into a database and using minId to reduce the amount of calls returned on every re-query.

Almost getting there!

As you can probably tell, that API call was originally designed to work with minID, much as you’ve ended up doing. There was an omission in the date checking code which prevented it from working as documented - There is an alternative undocumented format for the minDate and maxDate, which I have no expectation will ever go away, so this may help.


The time must be in UTC/GMT, and the number of digits must be exactly as specified above, such as a 4-digits year and 3-digits milliseconds. The ‘T’ and the ‘Z’ are literal.

I’ll fix this in an upcoming release to work as documented.

Hope that helps.

1 Like

Hi Steve,

That’s worked! If it’s not too much trouble could you look at filtering that API by company also? Similar to how the /rest/call/incalls works. Actually the only reason I didn’t use /rest/call/incalls was because I couldn’t find the extension but looking now that appears to be the grouped key!

I’m afraid that that REST call is providing raw cdr data, and any one of those rows can relate to one or more companies, or sometimes even none. It takes significant post-processing to determine source company and destination company. You may be able to use the incalls and outcalls REST requests? These are much slower, but are natively run per-company.

Be warned that incalls and outcalls can return a ‘retry’ response as the amount of CPU it takes means it is limited to a single run at a time - Not something you can use for anything very close to realtime data.

Hope that helps,

Is there anything you would recommend for getting the call logs/data for a realtime reporting wallboard? I thought I nearly got there but seem to be having issues associating which calls are from/to what extension as this client is hot desking so no phone ownership and with hunt groups it logs the extension of the hunt group sometimes rather than the users extension that handled the call.

I’m picking up the majority of outbound calls but it appears some actually come from the src of the hunt group.

Any help would be appreciated.

Perhaps you could detail what you are doing so far?

It is entirely possible that calls would come from the ‘src’ of the hunt group. Most phones will do that by default for a forwarded call for example. In fact a handset with multiple identities can dial a call as coming from any of it’s identities.

The more specific data to use to identify an outbound call source is the ‘channel’, but that then needs to be mapped to the current user as you’ve observed - If it is a hotdesk user, you’ll find some of this info in the cdr userinfo field where you’ll have ‘hd=nnn’ nnn being the hotdesk user’s extension.

All of this is handled by the JavaScript API, but I believe you’re using PHP?


At the minute I’ve got a list of phone users so extensions and their name stored in a table. I’ve then got a table which is storing call data from the endpoint /rest/call/read. I’m using the src field for mapping to extension for outgoing calls and for incoming I’m string replacing _CompanyName from the dst for incoming.

I did take a look at the JavaScript API and got the listeners working which I could see live call data but wasn’t clear how I could get a total of inbound/outbound calls for each extension/user for that day.

I’m happy to switch over to the JavaScript API if that is what you would recommend and if you could recommend about how I would get the call data for that day?


Live and historical data is separate. Let me have a think about it and get back to you.


OK thanks! I appreciate your time.

So, if I were doing a wallboard from scratch, I would certainly use a combination of the incalls, outcalls REST requests to collect initial historical data, and the JavaScript API for live data - On the other hand, that is largely because I use JavaScript most of the time these days!

Reading the CDR data either using the REST interface, or the Asterisk AMI (collector / live-stream) interface is also quite valid and will result in a more consistent data feed, because the AMI interface just dumps the CDR records as they are created.

When Oak approached this problem, we created a lookup table for them to be able to use the ‘channel’ and ‘dstchannel’ columns to determine who was actually making/receiving a call - There is a common disconnect where there is an assumption that handset == user == extension, but handset, user and extension are very much separate entities on an IPCortex system.

You could try the following URL, which dumps that lookup


It requires an administrative login session, so to get going, probably just log in manually as admin and browse to that page. It is fairly crude, and does take the current hotdesk situation into account, though that is probably not useful in the long-run.

Hi Steve,

Thanks for your response. I’ve just taken a look at the oak.whtm and I can see the mapping. To further understand this are each map unique? For instance the below snippet for hotdesk phone 16 occurs a few times but has 1 that maps to a correct extension. If a user logs out of the phone and another logs in, will it replace hdesk16=newextension or would it be something unique like hdesk16_6=newextension.

As the links have no datetime then I’m making sure that the mapping/association of the calls to an extension won’t change over to another user if someone then logged into that phone if that makes sense?

I mainly use JS now but in this case I’ve setup a cron that runs every minute which fetches new data from the REST API then fires an event in PHP that sends the new data to PusherJS and the frontend is listening on a certain pusher channel to update the relevant objects/arrays

I replied to this yesterday, but must not have hit “post” and now have lost that response :slight_frown:

The _2, _3, _4 etc numbers represent the multiple lines (identities) on a handset. When hotdesking, only the first line is normally used, but if other lines are activated by the user, a call can be made from one of those other lines.

The oak report will update based on the results of hotdesking, but the query uses a multi-way table join, so don’t run it TOO often. Sadly in the REST environment there is currently no quick indicator of a hotdesk or other config change available.

In case it helps:

In the JS environment, I would say this is a bit “simpler”, as you’d load, login and initialise the API as per the examples, and then I would use the REST incalls/outcalls requests to gather historical data for a starting point. From here you can “simply” register an all-calls update listener:

IPCortex.Types.Call.addListener('update', (call) => { /* process 'call' here */})

using the ‘dial’, ‘ring’ or ‘up’ call state to increment call counts, and the ‘dead’ state to decrease call counts. The call object that is sent in these updates has a uniqueID and a reference to the device they are operating on, which I think gives you what you need?

Hi @steved, thanks for this reply all those months ago! I managed to get a away without having to worry about incoming call stats until the client has just asked me now… :smile:

So, I just wanted to ask how you would use the REST API for historic data. As the “https://pabx-host-or-ip/admin/oak.whtm” endpoint returns hot-desk to extension for that present moment and if you wouldn’t recommend hitting the endpoint too often then I don’t see how I can map historic data of dstchannel to extension? I’ve used the IPCortex JS library for the listeners for another project so I could see a way to POST to an endpoint on my API to store the data for historic/reporting reasons, however, I’m unsure whether this is reliable and can keep running 24/7? Do you know whether this could sit on a NodeJS app and keep running rather than having something setup client side?


I agree that the oak.whtm page is a bit horrible if you are using hotdesking - it was put together for our first ever Oak installation and has not received much attention since then.

Hopefully the following will answer your other questions/points.


  1. Live data…

If you’re using hotdesking with the live JS API, then realtime hotdesking updates can be collected through the getLInes() callback, though I imagine that using it would be non-trivial as it is designed to present data for a single-user UI experience (ie keevio)


  1. Historical data…

For historical data, probably the simplest solution would depend on you running version 6.3.1+ software - Although 6.2.16+ includes the call reports REST call:


Version 6.3.1 adds a new option scope: {extra: true}} which returns data which takes hotdesking into account, though historical data may be inaccurate as hotdesk events are only recorded in the database in detail from the newest version.

This feature is only about a week old, so the extra option has not been documented yet, but should be added to the above documentation link fairly soon now.

  1. Long running / node…

I run the API long-term in my desktop browser (weeks or months sometimes) specially to confirm that there are no memory leaks, so you should be fine to run the api 24/7 - The code includes common techniques to help the JS garbage collector clean up.

nodeJS should also be an option - It’s not been used for a little while, so let us know if it is broken, but:

This could possibly be improved to do the ‘update’ bit every time it is started, or to ‘eval’ a live-fetched copy of the api instead of caching a local copy which might go out of date if the PABX is updated.