# Get CDR Records

## Overview

Get call (and messaging) delivery records from your account.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](https://docs.tsgglobal.com/graphql-api-and-authentication).
{% endhint %}

##

## Endpoint

<mark style="color:green;">`POST`</mark> <https://api.portal.tsgglobal.world/graphql>

## Method

After sending messages or creating calls, you can check those by using the `cdrRecords` query which returns a `paginatedCdrResult` object type. This query is a bit more complex due to the usage of advanced GraphQL features like fragments and cursor based pagination.

Arguments which can be sent are listed below. The exclamation mark (`!`)means a parameter is mandatory, otherwise it's optional:

```
companyId: ID
For which company to list CDRs (only for admin users)

type: CdrType!
The type of the CDR records to list

startDatetime: DateTime!
Will return all records with datetime >= startDatetime

endDatetime: DateTime!
Will return all records with datetime < endDatetime (UTC based), max value is now

cursor: String
Used to paginate, returns results for the passed cursor (if any)

limit: Int
Limit the number of results per page, default is 100, max is 1000
```

### Sample Query

```
query cdrRecordsQuery(
      $type: CdrType!
      $startDatetime: DateTime!
      $endDatetime: DateTime!
      $limit: Int
      $cursor: String
    ) {
      cdrRecords(
        type: $type
        startDatetime: $startDatetime
        endDatetime: $endDatetime
        limit: $limit
        cursor: $cursor
      ) {
        exportLink
        paginationInfo {
          nextCursor
          limit
        }
        cdrs {
          ... on ApiCdr {
            datetime
            from
            destination
            status
            charge
            type
          }
          ... on MessageCdr {
            datetime
            fromNumber
            toNumber
            direction
            status
            charge
            type
          }
          ... on VoiceCdr {
            datetime
            callId
            sourceAni
            destinationNumber
            didUsed
            sessionTime
            status
            calledRate
            charge
            callType
            aniIi
          }
        }
      }
    }
```

In this query GraphQL fragments are used (e.g. `... on MessageCdr { ... }`, they are needed because what we return is a union of types for `cdrs`, and the fields are depending on the passed `type`. In our example below we're using `SMS`, but the fragments can be specified for each field in a general query, only change the type.

In our case the type is `SMS`, you send it as an uppercase string, example of variables sent:

### Sample Variables

```
{
  "type": "SMS",
  "startDatetime": "2022-04-26T07:00:00.000Z",
  "endDatetime": "2022-04-26T17:13:05.377Z",
  "limit": 20
}
```

### Sample Response

```
{
  "data": {
    "cdrRecords": {
      "cdrs": [
        {
          "__typename": "MessageCdr",
          "account": "ACMEANCHO",
          "charge": "0.0095000000",
          "cost": "0.0051500000",
          "datetime": "2022-01-02T00:00:00Z",
          "direction": "SMS / MO Surcharge: T-Mobile - TF",
          "fromNumber": "12247512345",
          "status": "SENT",
          "surcharge": "0.0025000000",
          "toNumber": "18447312345",
          "uniqueId": "45e868c1-96b2-474c-a60f-98b76d812343"
        },
        {
          "__typename": "MessageCdr",
          "account": "ACMEANCHO",
          "charge": "0.0010000000",
          "cost": "0.0000000000",
          "datetime": "2022-01-02T00:00:00Z",
          "direction": "SMS / MO: AT&T - LO-ZERO",
          "fromNumber": "18134512345",
          "status": "SENT",
          "surcharge": "0.0000000000",
          "toNumber": "19725212345",
          "uniqueId": "22854899-1bc9-47b2-9a90-98b76d812344"
        },
        {
          "__typename": "MessageCdr",
          "account": "ACMEANCHO",
          "charge": "0.0095000000",
          "cost": "0.0051500000",
          "datetime": "2022-01-02T00:00:01Z",
          "direction": "SMS / MT Surcharge: T-Mobile - TF",
          "fromNumber": "18777312345",
          "status": "SENT",
          "surcharge": "0.0025000000",
          "toNumber": "16502912345",
          "uniqueId": "ce8590ac-0674-4ef8-8a7f-98b76d812345"
        },
      ],
      "exportLink": "https://api.portal.tsgglobal.world/export/call_records?sig=abe5dfefb701b284db7b8d18e4673654e788ab42a1ef51bcbc4f153ga218f2fa&end_datetime=2022-01-10T23%3A59%3A59.999Z&fields=account%2Cunique_id%2Ccharge%2Cfrom_number%2Cto_number%2Cstatus%2Cdatetime%2Ccost%2Csurcharge%2Cdirection&start_datetime=2022-01-01T00%3A00%3A00.000Z&type=sms&company_internal_id=ACMEANCHO&new_export=true&user_id=e17bbdf0-e72a-4998-bcfb-8f3e92123456",
      "paginationInfo": {
        "limit": 100,
        "nextCursor": null
      }
    }
  }
}
```

### Pagination

We're using pagination for this endpoint because there can be milions of records for short time frames. To paginate through the results tweak the previous query so it looks like this (notice the new `$limit` and `$cursor` arguments):

query($type: CdrType!, $startDatetime: DateTime!, $endDatetime: DateTime!, $companyId: ID, $limit: Int, $cursor: String) { cdrRecords(type: $type, startDatetime: $startDatetime, endDatetime: $endDatetime, companyId: $companyId, limit: $limit, cursor: $cursor) {

```
query($type: CdrType!, $startDatetime: DateTime!, $endDatetime: DateTime!, $companyId: ID, $limit: Int, $cursor: String) {
  cdrRecords(type: $type, startDatetime: $startDatetime, endDatetime: $endDatetime, companyId: $companyId, limit: $limit, cursor: $cursor) {    
		
		cdrs {
			__typename
			... on MessageCdr {
				account
				uniqueId
				charge
				fromNumber
				toNumber
				status
				datetime
				cost
				surcharge
				direction
			}
			
			... on ApiCdr {
				account
				charge
				destination
				datetime
				status
				from
				uniqueId
				type
			}
			
			... on VoiceCdr {
				account
				charge
				destination
				datetime
				status				
				uniqueId
				aniIi
				callId
				callType
				destinationNumber
				sourceAni
				calledRate
				didUsed
				sessionTime
			}
		}
		
		paginationInfo {
			limit
			nextCursor
		}
    exportLink
  }
}
```

and variables (`limit=2` and `cursor=null`):

```json
{
	"type": "SMS",
	"startDatetime": "2022-01-01T00:00:00.000Z",
	"endDatetime": "2022-01-10T23:59:59.999Z",
	"companyId": "65deb62c-bb16-4a9d-927a-ec1abb37a832",
	"limit": 2,
	"cursor": null
}
```

The results we get have `paginationInfo` filled differently, notice the `limit` and `nextCursor` properties below:

```
{
  "data": {
    "cdrRecords": {
      "cdrs": ["...edited for readability..."],
      "exportLink": "...edited for readability...",
      "paginationInfo": {
        "limit": 2,
		"nextCursor": "123456"
      }
    }
  }
}
```

We need to use the `nextCursor` value to get the next page, the variables now look like the following:

```
{
	"type": "SMS",
	"startDatetime": "2022-01-01T00:00:00.000Z",
	"endDatetime": "2022-01-10T23:59:59.999Z",
	"companyId": "65deb62c-bb16-4a9d-927a-ec1abb37a832",
	"limit": 2,
	"cursor": "123456"
}
```

This will get us the next round of results with another `nextCursor` value:

```
{
  "data": {
    "cdrRecords": {
      "cdrs": ["...edited for readability..."],
      "exportLink": "...edited for readability...",
      "paginationInfo": {
        "limit": 2,
		"nextCursor": "554433"
      }
    }
  }
}
```

We can paginate until the result we get has `nextCursor: null`, when it's `null` it means we reached the end.

### Exporting CDRs

You can export CDRs by using the `exportLink` which the `cdrRecords` query provides. The easiest way is to click on the link, but you can also do a server-side or client-side download if you want to save the results.

The links in the above example won't work since they're fake but you can generate one with your queries. The export will trigger a CSV file download (via HTTP streams) and include the fields you specified in the query, but the pagination options will be ignored.

Example of an export Link:

```
https://api.portal.tsgglobal.world/export/call_records? \
sig=abe5dfefb701b284db7b8d18e4673654e788ab42a1ef51bcbc4f153ga218f2fa& \
fields=account,unique_id,charge,from_number,to_number,status,datetime,cost,surcharge,direction& \
start_datetime=2022-01-01T00:00:00.000Z& \
end_datetime=2022-01-10T23:59:59.999Z& \
type=sms& \
company_internal_id=ACMEANCHO& \
new_export=true& \
user_id=e17bbdf0-e72a-4998-bcfb-8f3e92123456
```

#### Notes

* The export link is protected by a signature and cannot be tampered with, once generated it's public.
* The export process has a timeout of 20 minutes, so if you notice the export timing out reduce the startDatetime and endDatetime period to something manageable and try again
