LINK Mobility DK Rest API v2
Following are some examples to get up and running, the examples use commandline CURL.
01. Webservice
The webservice is at:
- http://api.linkmobility.dk/
- https://api.linkmobility.dk/
02. Structure
All api calls has a version in the URL. We will only bump the version in the api call in any new features that would break backward compatibility are added.
We support json and xml
An url will look somthing like this
http://api.linkmobility.dk/[version]/[resource].[json|xml]?apikey=[apikey]
curl 'http://api.linkmobility.dk/v2/ping.json?apikey=e1bd9f55b7d6a45348fa92c427932c4ad3744afdebf8b99aa207de991f78f9d4' -X GET curl 'http://api.linkmobility.dk/v2/ping.xml?apikey=e1bd9f55b7d6a45348fa92c427932c4ad3744afdebf8b99aa207de991f78f9d4' -X GET
03. Authentication
Authentication is done by sending the param apikey=[apikey] and you'll get something like: This function should not be used in new implementations, and will in the future be depricated.curl 'http://api.linkmobility.dk/v2/ping.json?apikey=[apikey]' -X GET
curl 'http://api.linkmobility.dk/v2/ping.xml?apikey=[apikey]' -X GET
<?xml version="1.0"?>
<response>
<status>200</status>
<userid>7405</userid>
<username>hn</username>
<iprange>77.243.40.100</iprange>
<apikey>a1bd9f58b7d6a45b48fa92c427132c4ad3744afdebf8b99af207de991f78f9d4</apikey></response>
{
"status": 200,
"userid": "7405",
"username": "hn",
"iprange": "77.243.40.100",
"apikey": "a1bd9f58b7d6a45b48fa92c427132c4ad3744afdebf8b99af207de991f78f9d4"
}
Legacy auth
curl 'http://api.linkmobility.dk/v2/ping.json?apikey=legacy&username=[username]&password=[password]&type=[md5|plain]' -X GET
curl 'http://api.linkmobility.dk/v2/ping.xml?apikey=legacy&username=[username]&password=[password]&type=[md5|plain]' -X GET
04. Lists
Get all lists Get specific list and all the contacts in it Create new list file.json file.xml Update existing list file.json file.xml Delete a specific listGET /lists.{format}
curl 'http://api.linkmobility.dk/v2/lists.json?apikey=[apikey]' -X GET
curl 'http://api.linkmobility.dk/v2/lists.xml?apikey=[apikey]' -X GET
{
"list": [
{
"id": "1",
"parent": "0",
"name": "HMN"
},
{
"id": "9",
"parent": "0",
"name": "test42"
}
],
"status": 200
}
GET /list/{id}.{format}
curl 'http://api.linkmobility.dk/v2/list/{id}.json?apikey=[apikey]' -X GET
curl 'http://api.linkmobility.dk/v2/list/{id}.xml?apikey=[apikey]' -X GET
{
"list": {
"id": "33",
"parent": "9",
"name": "Underliste 2",
"contacts": [
{
"id": "85",
"listid": "9",
"mobile": "+4587654321",
"created": "2014-12-15 13:51:26",
"changed": "2014-12-15 13:51:26",
"fields": {
"Fornavn": "Jack",
"Efternavn": "Bauer"
}
},
{
"id": "93",
"listid": "9",
"mobile": "+4512345678",
"created": "2014-12-15 13:52:32",
"changed": "2014-12-15 13:52:32",
"fields": {
"Fornavn": "Anders",
"Efternavn": "And"
}
}
]
},
"status": 200
}
POST /list.{format}
curl 'http://api.linkmobility.dk/v2/list.json?apikey=[apikey]' -X POST -H "Content-Type: application/json" -d @file.json
curl 'http://api.linkmobility.dk/v2/list.xml?apikey=[apikey]' -X POST -H "Content-Type: text/xml" -d @file.xml
payload
{
"list":{
"parent": 0,
"name":"test123"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<list>
<parent>0</parent>
<name>test42</name>
</list>
response
{
"list": {
"id": "61",
"parent": "0",
"name": "test123",
"contacts": []
},
"status": 201
}
<?xml version="1.0"?>
<response>
<list>
<id>69</id>
<parent>0</parent>
<name>test42</name>
<contacts/>
</list>
<status>201</status>
</response>
PUT /list/{id}.{format}
curl 'http://api.linkmobility.dk/v2/list/{id}.json?apikey=[apikey]' -X PUT -H "Content-Type: application/json" -d @file.json
curl 'http://api.linkmobility.dk/v2/list/{id}.xml?apikey=[apikey]' -X PUT -H "Content-Type: text/xml" -d @file.xml
payload
{
"list":{
"parent": 0,
"name":"test123"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<list>
<parent>0</parent>
<name>test42</name>
</list>
response
{
"list": {
"id": "61",
"parent": "0",
"name": "test123",
"contacts": []
},
"status": 201
}
<?xml version="1.0"?>
<response>
<list>
<id>69</id>
<parent>0</parent>
<name>test42</name>
<contacts/>
</list>
<status>201</status>
</response>
DELETE /list/{id}.{format}
curl 'http://api.linkmobility.dk/v2/list/{id}.json?apikey=[apikey]' -X DELETE
curl 'http://api.linkmobility.dk/v2/list/{id}.xml?apikey=[apikey]' -X DELETE
{
"message": "List id [65] deleted",
"status": 200
}
05. Contacts
GET /contacts/{page}.{format}
Get all contacts based on search params
curl 'http://api.linkmobility.dk/v2/contacts/1.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/contacts/1.xml?apikey=[apikey]' -X GET
Fields
You can use the following GET parameter when searching for contacts
Name | Type | Description |
---|---|---|
listid | String | Search for contacts in a specific list |
mobile | String | Search for contacts with a specific mobile number |
deleted | Boolean | Search for contacts that are deleted or active |
field_key | String | Search merge field key |
field_value | String | Search merge field value |
response
{ "contacts": [ { "id": "631809", "listid": "373", "mobile": "+4512721272", "created": "2015-03-13 09:11:22", "changed": "2015-03-13 09:11:22", "deleted": false, "fields": { "Fornavn": "TEST", "Efternavn": "" } }, { "id": "632065", "listid": "373", "mobile": "+4512721272", "created": "2015-03-13 09:11:22", "changed": "2015-03-13 09:11:22", "deleted": false, "fields": { "Fornavn": "TEST", "Efternavn": "" } } ], "paging": { "pages": 81056, "offset": 2, "current": 1 }, "stats":{ "total":"2", }, "status": 200 }
GET /contact/{id}.{format}
Get one contact by id
curl 'http://api.linkmobility.dk/v2/contact/{id}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/contact/{id}.xml?apikey=[apikey]' -X GET
{ "contact": { "id": "85", "listid": "9", "mobile": "+4512345678", "created": "2014-12-15 13:51:26", "changed": "2014-12-15 13:51:26", "fields": { "Fornavn": "Jack", "Efternavn": "Bauer" } }, "status": 200 }
POST /contact.{format}
Create new contact
curl 'http://api.linkmobility.dk/v2/contact.json?apikey=[apikey]' -X POST -H "Content-Type: application/json" -d @file.json curl 'http://api.linkmobility.dk/v2/contact.xml?apikey=[apikey]' -X POST -H "Content-Type: text/xml" -d @file.xml
payload
file.json
{ "contact": { "listid": "33", "mobile": "+4512345678", "fields": { "Fornavn": "Jack", "Efternavn": "Bauer" } } }
file.xml
<?xml version="1.0"?> <contact> <listid>33</listid> <mobile>+4512345678</mobile> <fields> <Fornavn>Jack</Fornavn> <Efternavn>Bauer</Efternavn> </fields> </contact>
response
{ "contact": { "id": "109", "listid": "33", "mobile": "+4512345678", "created": "2014-12-17 08:32:31", "changed": "2014-12-17 08:32:31", "fields": { "Fornavn": "Jack", "Efternavn": "Bauer" } }, "status": 201 }
<?xml version="1.0"?> <response> <contact> <id>113</id> <listid>33</listid> <mobile>+4512345678</mobile> <created>2014-12-17 08:32:51</created> <changed>2014-12-17 08:32:51</changed> <fields> <Fornavn>Jack</Fornavn> <Efternavn>Bauer</Efternavn> </fields> </contact> <status>201</status> </response>
PUT /contact/{id}.{format}
Update existing contact
curl 'http://api.linkmobility.dk/v2/contact/{id}.json?apikey=[apikey]' -X PUT -H "Content-Type: application/json" -d @file.json curl 'http://api.linkmobility.dk/v2/contact/{id}.xml?apikey=[apikey]' -X PUT -H "Content-Type: text/xml" -d @file.xml
payload
file.json
{ "contact": { "listid": "33", "mobile": "+4512345678", "fields": { "Fornavn": "Anders", "Efternavn": "And" } } }
file.xml
<?xml version="1.0"?> <contact> <listid>33</listid> <mobile>+4512345678</mobile> <fields> <Fornavn>Anders</Fornavn> <Efternavn>And</Efternavn> </fields> </contact>
response
{ "contact": { "id": "109", "listid": "33", "mobile": "+4512345678", "created": "2014-12-17 08:32:31", "changed": "2014-12-17 08:32:31", "fields": { "Fornavn": "Anders", "Efternavn": "And" } }, "status": 201 }
<?xml version="1.0"?> <response> <contact> <id>113</id> <listid>33</listid> <mobile>+4512345678</mobile> <created>2014-12-17 08:32:51</created> <changed>2014-12-17 08:32:51</changed> <fields> <Fornavn>Anders</Fornavn> <Efternavn>And</Efternavn> </fields> </contact> <status>201</status> </response>
DELETE /contact/{id}.{format}
Delete a specific contact by id
curl 'http://api.linkmobility.dk/v2/contact/{id}.json?apikey=[apikey]' -X DELETE curl 'http://api.linkmobility.dk/v2/contact/{id}.xml?apikey=[apikey]' -X DELETE
{ "message": "Contact id [113] deleted", "status": 200 }
{ "status": 404, "message": "Contact id [113] not found" }
06. Contact import
NB: After 24 hours from initial creation the data will be deleted.
POST /import.{format}
Initialize import job
curl 'http://api.linkmobility.dk/v2/import.json?apikey=[apikey]' -X POST -H "Content-Type: application/json" -d @file.json curl 'http://api.linkmobility.dk/v2/import.xml?apikey=[apikey]' -X POST -H "Content-Type: text/xml" -d @file.xml
Fields
Name | Type | Description |
---|---|---|
listid | integer | If you wan't to import into an existing list, add the listid |
name | String | Name to use for new list, only used if no listid is set |
clean | Boolean (1 = delete, 0 = keep) | Should all contacts in the list be deleted before import |
duplicate | Boolean (1 = delete, 0 = keep) | Should duplicate numbers be deleted |
payload
file.json
{ "import": { "listid": 33, "name": "TEST", "clean": 0, "duplicate": 0 } }
response
{ "import": { "hash": "1fa97e90d173a9ed979bec56f3cef0f1d5c2f3fbf33e263dcbae28c9bd006abe", "created": "2014-12-17 15:24:57", "listid": 0, "name": "TEST", "clean": 0, "total": 0, "processed": 0 }, "status": 201 }
PUT /import/{hash}.{format}
List of numbers to import
Uses {hash} from POST
curl 'http://api.linkmobility.dk/v2/import/{hash}.json?apikey=[apikey]' -X PUT -H "Content-Type: application/json" -d @file.json curl 'http://api.linkmobility.dk/v2/import/{hash}.xml?apikey=[apikey]' -X PUT -H "Content-Type: text/xml" -d @file.xml
payload
file.json
{ "import": { "keys": [ "Mobile", "Fornavn", "Efternavn" ], "values": [ [ "+4512345678", "Jack", "Bauer" ], [ "+4587654321", "Chuck", "Norris" ] ] } }
response
{ "import": { "hash": "792d979f57f8f046ba3c5d73353be07d4fa06a9cfbe491f044be1d357f63756c", "created": "2014-12-17 15:54:01", "listid": 1, "name": "TEST", "clean": 0, "duplicate": 1, "total": 3, "processed": 3 }, "errors": [ { "message": "Mobile is not valid! Remember a valid number must contain a countrycode like +4512345678", "count": 1, "errors": { "1": "4587654321" } } ], "status": 200 }
GET /import/{hash}.{format}
Get status on import
curl 'http://api.linkmobility.dk/v2/import/{hash}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/import/{hash}.xml?apikey=[apikey]' -X GET
{ "import": { "hash": "1fa97e90d173a9ed979bec56f3cef0f1d5c2f3fbf33e263dcbae28c9bd006abe", "created": "2014-12-17 15:24:57", "listid": 0, "name": "TEST", "clean": 0, "total": 100, "processed": 100 }, "status": 200 }
07. Merge fields
Get all merge fields Create new merge field file.json Update existing merge field file.json Delete a specific contact by idGET /mergefields.{format}
curl 'http://api.linkmobility.dk/v2/mergefields.json?apikey=[apikey]' -X GET
curl 'http://api.linkmobility.dk/v2/mergefields.xml?apikey=[apikey]' -X GET
{
"field": [
{
"id": "1",
"name": "Fornavn",
"key": "felt1"
},
{
"id": "5",
"name": "Efternavn",
"key": "felt5"
}
],
"status": 200
}
POST /mergefield.{format}
curl 'http://api.linkmobility.dk/v2/mergefield.json?apikey=[apikey]' -X POST -H "Content-Type: application/json" -d @file.json
curl 'http://api.linkmobility.dk/v2/mergefield.xml?apikey=[apikey]' -X POST -H "Content-Type: text/xml" -d @file.xml
payload
{
"field":{
"name":"Test"
}
}
response
{
"field": {
"id": "77",
"name": "Test",
"key": "felt77"
},
"status": 201
}
PUT /mergefield/{id}.{format}
curl 'http://api.linkmobility.dk/v2/mergefield/{id}.json?apikey=[apikey]' -X PUT -H "Content-Type: application/json" -d @file.json
curl 'http://api.linkmobility.dk/v2/mergefield/{id}.xml?apikey=[apikey]' -X PUT -H "Content-Type: text/xml" -d @file.xml
payload
{
"field":{
"name":"Test changed"
}
}
response
{
"field": {
"id": "73",
"name": "Test changed",
"key": "felt73"
},
"status": 200
}
DELETE /mergefield/{id}.{format}
curl 'http://api.linkmobility.dk/v2/mergefield/{id}.json?apikey=[apikey]' -X DELETE
curl 'http://api.linkmobility.dk/v2/mergefield/{id}.xml?apikey=[apikey]' -X DELETE
{
"message": "Merge field id [113] deleted",
"status": 200
}
{
"status": 404,
"message": "Merge field id [113] not found"
}
08. Messages
POST /message.{format}
Send message. For more detailed examples go to Sending SMS
curl 'http://api.linkmobility.dk/v2/message.json?apikey=[apikey]' -X POST -H "Content-Type: application/json" -d @file.json curl 'http://api.linkmobility.dk/v2/message.xml?apikey=[apikey]' -X POST -H "Content-Type: text/xml" -d @file.xml
Fields
Name | Type | Default | Description |
---|---|---|---|
recipients | String | Comma seperated list of recipients. listid, contactid or phone number, see format below | |
sender | String(11) / Int(22) | Service SMS | Name / Number of sender. If number defined use this format: +4512345678 where +45 is countrycode |
message | String | The message to send | |
status | Boolean | false | Should a status request be made. See [api:example_dlr] |
statusurl | String | URL to request with status of each message. See [api:example_dlr] | |
returndata | String | Custom data to return in statusurl request. See [api:example_dlr] | |
class | Int | 1 | See class list below |
sendtime | Date | Send message at a later time, Format : dd-mm-YYYY HH:MM | |
price | Int | 0 | Price in local unit for the selected shortcode and minimum 100. For 1272 in DK it would be øre |
charity | Boolean | false | Set price to be for a charity or vat exemption. Only allowed for approved users. |
invoicetext | String(40) | Invoice text that should be shown on end users phone bill | |
validity | Int | 2880 | Message TTL in minutes (recommendation to telcos, but not a hard limit) |
contenttype | |||
format | Enum | GSM | See list belov |
udh | String | Set UDH, used by BINARY messages | |
pushurl | String | Used by format WAPPUSH. The url pushed to the terminal | |
pushexpire | String | Used by format WAPPUSH. Exire time in unix timestamp, default is now + 7 days | |
filter | Array | Filter who in a list to send the message to. Requires the use of lists and mergefields. | |
segmentation | Array | Segmentation options for splitting lists into smaller chunks dynamicly when sending. | |
pid | Int | 0 | GSM Protocol ID |
advanced | String | Key for using advanced fields | |
protocol | String (advanced) | The protocol name (REST, SMTP and others) | |
revenuetext | String | Used with premium messages to identify and group messages in the statistics and on the premium payout overview. |
recipients
Name | Format | Description |
---|---|---|
phone number | +[number] | Phone numbers prefix is +. For instance +4512721272 |
contact id | c[id] | Contact id prefix is c. For instance c123 |
list id | [id] | List id is default and only an integer |
recipients could look like this
1,2,c123,+452721272
format
Name | Required | Description |
---|---|---|
GSM | Send normal message (160 chars, but if more than 160 chars, 153 chars per part message) | |
UNICODE | To send speciality chars like chinese letters. | |
BINARY | udh, message | Send a binary message body in hex and define udh |
WAPPUSH | pushurl, pushexpire | Send a link that is opened on the phone |
Keyword replacement
If you are sending to lists, you can use keyword replacement, for instance for inserting a uniq name in each message.
If your list had an extra field called Name you would use it like this :
Hi [Name] This is only a test
contenttypes
- 1 = Ringetoner og billeder
- 2 = Videoklip og tv
- 3 = Voksenindhold
- 4 = Musik
- 5 = Lydbøger og podcasts
- 6 = Mobilspil
- 7 = Chat tjenester
- 8 = Konkurrence og afstemning
- 9 = Biletter og adgangsbetaling
- 10 = Nyheder og information
- 11 = Indsamlinger / donationer (Humanitære organisationer)
- 12 = Telemetri (M2M)
- 13 = Diverse
- 14 = Indsamlinger / donationer (ikke humanitære organisationer)
- 15 = Lotteri (moms fri)
Note! These contenttypes currenty only apply to danish shortcodes. See contenttypes for more info.
class
- 0 - Deprecated - Do not use !
- 1 - Save message in phone memory. Either on the phone or in SIM.
- 2 - Message contains SIM data.
- 3 - Message contains info that indicate that it should be sent to external units, normally used by terminal equipment.
By default you should not change this option
filter
Filter is a json array of rules that is matched during the send process, to limit who should get the message.
Name | Values | Description |
---|---|---|
match | any / all | The way the rules should be matched. Should all or any of the rules match to include a recipient. |
rules | field, operation, value | Array of rules to match on |
Operation | value | Descriptuon |
---|---|---|
is | is | If exact match is found include the recipient |
is not | not | If exact is not found include the recipient |
contains | contains | If mergefield contains the string include the recipient |
does not contain | notcontain | If mergefield does not contain the string then include the recipient |
starts with | start | If field stats with this string then include the recipient |
ends with | ends | If fields ends with this string then include the recipient |
is greater than | greater | If field is a number that is greater than value then include the recipient |
is less than | less | If field is a number that is less than value then include the recipient |
"filter":{ "match": "any", "rules": [ { "field": "Fornavn", "operation": "is", "value": "chuck" }, { "field": "Fornavn", "operation": "not", "value": "jack" }, { "field": "Fornavn", "operation": "contains", "value": "cool" } ] }
segmentation
Segmentation is a json array that tells the system how to split/limit who to send to.
Name | Description |
---|---|
count | If set how many recipients to send to |
percent | If set how big a percentage of the segment should be used |
exclude | List of previous batches |
Sending to 10% of a list
"segmentation":{ "percent": 10 }
Sending to the rest of the list
"segmentation":{ "percent": 100, "exclude": [ 12345 ] }
Responses
Each successful request, will create a new batch for handling the messages, hence it returns a batch status object.
A couple of examples of responses
success
{ "stat": { "sendtime": "17-12-2014 08:42:24", "buffered": 0, "received": 0, "rejected": 0 }, "details": { "sendtime": "17-12-2014 08:42:24", "batchid": "310701", "state": "QUEUED" }, "status": 201 }
wrong list id
{ "status": 400, "message":"List ID 12 not found" }
GET /messages/{page}.{format}
Get list of the newest batches including future waiting batches
curl 'http://api.linkmobility.dk/v2/messages/{page}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/messages/{page}.xml?apikey=[apikey]' -X GET
{ "messages": [ { "batchid": "2229409", "time": "23-03-2015 10:59:19", "state": "DONE", "sender": "TEST", "msg": "Hello world", "protocol": "SMTP" }, { "batchid": "2229405", "time": "23-03-2015 10:50:16", "state": "DONE", "sender": "TEST", "msg": "Hello world", "protocol": "REST" } ], "status": 200 }
GET /message/{batchid}/{page}.{format}
Get message details based on batch id from POST
If page is 0 only summary is returned (batch status object)
curl 'http://api.linkmobility.dk/v2/message/{batchid}/{page}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/message/{batchid}/{page}.xml?apikey=[apikey]' -X GET
page = 0
{ "stat": { "sendtime": "17-12-2014 08:42:24", "buffered": 0, "received": 1, "rejected": 1 }, "details": { "sendtime": "17-12-2014 08:42:24", "batchid": "310701", "state": "DONE" }, "status": 200 }
page = 1
{ "message": [ { "msgid": "d2dc8158a56d5bfb201c357e950bf9e6", "status": "rejected", "recipient": "412345678", "statusreason": "Unknown subscriber" }, { "msgid": "aeb4205213393c0da008b44f527037e7", "status": "received", "recipient": "4587654321", "statusreason": "" } ], "stat": { "sendtime": "17-12-2014 08:46:33", "buffered": 0, "received": 1, "rejected": 1 }, "details": { "sendtime": "17-12-2014 08:46:33", "batchid": "310713", "state": "DONE" }, "paging": { "current": 1, "pages": 1 }, "status": 200 }
PUT /message/refund/{lookup-id}.{format}
Refunds a message. If a message is specified in the payload, the user will be notified about the refund (The notification will be sent from the users account).
curl 'http://api.linkmobility.dk/v2/message/refund/{lookup-id}.json?apikey=[apikey]' -X PUT -H "Content-Type: application/json" -d @file.json curl 'http://api.linkmobility.dk/v2/message/refund/{lookup-id}.xml?apikey=[apikey]' -X PUT -H "Content-Type: text/xml" -d @file.xml
Payload file.json
{ "refund":{ "message":"Your message will be refunded" } }
On success, the response is
{ "status": 200, "statusreason": "Message is now in queue for refund." }
EXPAND /message/expand/{batchid}.{format}
Advanced feature only allowed internally for message recipient expansion
curl 'http://api.linkmobility.dk/v2/message/expand/{batchid}.json?apikey=[apikey]&advanced=[advancedkey]' -X GET curl 'http://api.linkmobility.dk/v2/message/expand/{batchid}.xml?apikey=[apikey]&advanced=[advancedkey]' -X GET
On success, the response is
{ "header": [ "Mobile" ], "data": [ [ "+4512721272" ] ], "status": 200 }
Batch Status Object
The "batch status object" contains basic information about the batch in its current state.
{ "stat": { "sendtime": "17-12-2014 08:42:24", "buffered": 0, "received": 1, "rejected": 1 }, "details": { "sendtime": "17-12-2014 08:42:24", "batchid": "310701", "state": "DONE" }, "status": 200 }
- stat object:
- sendtime: batch send time
- buffered: number of messages buffered
- received: number of messages recieved
- rejected: number of messages rejected
- details object:
- sendtime: batch send time
- batchid: id of current batch
- state: Possible states for batch processing [ QUEUED → RUNNING → DONE ]
- status: overall status for the request
State | Description |
---|---|
QUEUED | The batch is ready for processing. The batch will be processed shortly after sendtime has passed. |
RUNNING | The batch is currently processing. Messages are being sent, and the "buffered", "received" and "rejected" numbers will be updated as it is processed. |
DONE | The batch has finished processing. Up to 48 hours after this the messages will still be sent out for delivery. |
Please note:
- The number of messages is not known before the batch changes state to "RUNNING". It is only in the "RUNNING" state the recipient lists are expanded.
- Therefore up until this point, "buffered", "recieved" and "rejected" will be 0
- Therefore up until this point, "buffered", "recieved" and "rejected" will be 0
- After the batch has changed state to "DONE" it will at some point be impossible to fetch the batch status. After this please use the 09. Query interface
09. Query interface
GET /inbox/{page}.{format}
Query incoming messages
curl 'http://api.linkmobility.dk/v2/inbox/{page}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/inbox/{page}.xml?apikey=[apikey]' -X GET
Fields
You can use the following GET parameter when searching for messages
yName | Type | Description |
---|---|---|
recipient | string | Search for messages with specific recipient |
sender | String | Search for messages with a specific sender |
starttime | Date dd-mm-YYYY HH:MM | Search time interval start |
endtime | Date dd-mm-YYYY HH:MM | Search time interval end |
msgid | String | Search for messages with msgid |
message | String | Wildcard search in text |
keyword | String | Search for message to specific keyword. |
response
{ "query": [ { "lookupid": "1424185035-66417", "msgid": "4ab1a952e2645f4d39e06e26c9c220d6", "recipient": "+45609940305097", "sender": "4512345678", "logtime": "17-02-2015 15:57:15", "message": "Hmn" } ], "paging": { "pages": 1, "offset": 10, "current": 1 }, "stats": { "total": 1 }, "status": 200 }
GET /inbox/lookup/{lookupid}.{format}
Get details for a single incomming message
curl 'http://api.linkmobility.dk/v2/inbox/lookup/{lookupid}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/inbox/lookup/{lookupid}.xml?apikey=[apikey]' -X GET
response
{ "query": { "msgid": "4ab1a952e2645f4d39e06e26c9c220d6", "recipient": "+45609940305097", "sender": "4512345678", "logtime": "17-02-2015 15:57:15", "message": "Hmn", "keyword": "HMN", "function": "liste" }, "status": 200 }
GET /outbox/{page}.{format}
Query outgoing messages
curl 'http://api.linkmobility.dk/v2/outbox/{page}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/outbox/{page}.xml?apikey=[apikey]' -X GET
Fields
You can use the following GET parameter when searching for messages
Name | Type | Description |
---|---|---|
recipient | string | Search for messages with specific recipient |
sender | String | Search for messages with a specific sender |
starttime | Date dd-mm-YYYY HH:MM | Search time interval start |
endtime | Date dd-mm-YYYY HH:MM | Search time interval end |
price | Integer | Search for messages that has price |
price_expression | Enum (<, >, = ) | How to search for price |
batchid | Integer | Search for messages with batchid |
msgid | String | Search for messages with msgid |
message | String | Wildcard search in text |
status | String | Search for messages with specific status |
mcc | String | Either a single [http://en.wikipedia.org/wiki/Mobile_country_code] or a comma seperated list |
subusers | Integer | If set to 1, then the query will extend to also include messages sent from a subuser |
response
{ "query": [ { "lookupid": "1424185035-66418", "msgid": "852e453d32e8459af090a3019fa9f9f6", "batchid": "659177", "status": "received", "statusreason": null, "recipient": "4512345678", "sender": "TEST", "logtime": "2015-02-13 10:32:44", "protocol": "REST", "message": "Hello world!", "statuscode": "0", "mcc": "238", "mnc":"2", "userid":"1234", "splitcount": "1", "push_price":500, "contenttype": "9", "state": "transaction-refunded" }, { "lookupid": "1424185035-66419", "msgid": "cb95abc5027ff19a907662c614f4f475", "batchid": "673449", "status": "received", "statusreason": null, "recipient": "4512345678", "sender": "TEST", "logtime": "2015-02-13 14:35:29", "protocol": "REST", "message": "æøå", "statuscode": "0", "mcc": "238", "mnc":"2", "userid":"1234", "splitcount": "1", "contenttype": "15", "state": "transaction-refunded" }, { "lookupid": "1424185035-66420", "msgid": "4ca01538b55c2ee68e531eb04773966a", "batchid": "679733", "status": "received", "statusreason": null, "recipient": "4512345678", "sender": "TEST", "logtime": "2015-02-13 15:43:45", "protocol": "REST", "message": "æøå", "statuscode": "0", "mcc": "238", "mnc":"2", "userid":"1234", "splitcount": "1" } ], "paging": { "pages": 1, "offset": 10, }, "stats": { "total": 3, "splitcount":3 }, "status": 200 }
GET /outbox/lookup/{lookupid}.{format}
Get details for a single message
curl 'http://api.linkmobility.dk/v2/outbox/lookup/{lookupid}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/outbox/lookup/{lookupid}.xml?apikey=[apikey]' -X GET
response
{ "query": { "msgid": "7076fc592b59097b3c48c1f6e3321b6d", "batchid": "308605", "status": "received", "statusreason": "", "recipient": "4512345678", "sender": "Test", "logtime": "2014-12-15 09:03:47", "protocol": "REST", "message": "Hello world", "returndata": "", "statusurl": "", "statusresponse": "", "statuscode":"0", "push_price":"0", "userid":"1234", "splitcount":"1", "state":"" }, "status": 200 }
NB: If the message is a premium message, then "state" will be set to one of the following;
State |
---|
authorize-forwarded |
authorize-rejected |
capture-failed |
capture-forwarded |
capture-rejected |
refund-failed |
sms-forwarded |
sms-received |
sms-rejected |
transaction-authorized |
transaction-captured |
transaction-failed |
transaction-forwarded |
transaction-refunded |
transaction-rejected |
10. Stats
GET /stats/{type}/{aggregate}.{format}
The stats system is designed to give you fast access to aggregated data.
Stats are calculated and are they are not realtime
curl 'http://api.linkmobility.dk/v2/stats/{type}/{aggregate}.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/stats/{type}/{aggregate}.xml?apikey=[apikey]' -X GET
Type
Choose what type of messages you wan't to search in
Name | Description |
---|---|
inbox | Get stats for incomming messages |
outbox | Get stats for outgoing messages |
Aggregate
Chose what aggregation level you wan't to get stats for
Name | Description |
---|---|
hourly | Get hourly stats |
daily | Get daily stats |
weekly | Get weekly stats |
monthly | Get monthly stats |
Fields
You need to select what you wan't to search for in the stats system
Name | Type | Description |
---|---|---|
group | String | Search group id |
starttime | Date dd-mm-YYYY HH:MM | Search time interval start |
endtime | Date dd-mm-YYYY HH:MM | Search time interval end |
The search groups are pre calculated stats
Type | Group | Description |
---|---|---|
inbox | sum | Total number of messages received |
inbox | keyword:number | Number of received messages per keyword/number |
outbox | sum | Total number of messages sent |
outbox | mcc:status | Number of sent messages per country/status |
If you have admin rights you can select the base aggregation level by using the following options
Name | Type | Description |
---|---|---|
advanced | String | Advanced key that gives you extended access to the stats interface |
type_1 | enum (user, mcc) | Select base type |
value_1 | String | Value to search for |
examples
outbox/daily
curl 'http://api.linkmobility.dk/v2/stats/outbox/daily.json?apikey=[apikey]&starttime=15-02-2015 00:00:00&endtime=18-02-2015 23:59:59&group=sum' -X GET
{ "stats": [ { "year": "2015", "month": "2", "day": "23", "timestamp": "2015-02-23 00:00:00", "type_1": "user", "value_1": "7405", "type_2": "sum", "value_2": "sum", "counter": "1" }, { "year": "2015", "month": "2", "day": "25", "timestamp": "2015-02-25 00:00:00", "type_1": "user", "value_1": "7405", "type_2": "sum", "value_2": "sum", "counter": "4" } ], "status": 200 }
outbox/monthly
curl 'http://api.linkmobility.dk/v2/stats/outbox/monthly.json?apikey=[apikey]&starttime=01-01-2015 00:00:00&endtime=28-02-2015 23:59:59&group=sum' -X GET
{ "stats": [ { "year": "2015", "month": "2", "timestamp": "2015-02-01 00:00:00", "type_1": "user", "value_1": "7405", "type_2": "mcc:status", "value_2": "0:queued", "counter": "1" }, { "year": "2015", "month": "2", "timestamp": "2015-02-01 00:00:00", "type_1": "user", "value_1": "7405", "type_2": "mcc:status", "value_2": "0:rejected", "counter": "1" }, { "year": "2015", "month": "2", "timestamp": "2015-02-01 00:00:00", "type_1": "user", "value_1": "7405", "type_2": "mcc:status", "value_2": "238:received", "counter": "4" } ], "status": 200 }
inbox/monthly
curl 'http://api.linkmobility.dk/v2/stats/inbox/monthly.json?apikey=[apikey]&starttime=01-01-2015 00:00:00&endtime=28-02-2015 23:59:59&group=keyword:number' -X GET
{ "stats": [ { "year": "2015", "month": "2", "timestamp": "2015-02-01 00:00:00", "type_1": "user", "value_1": "7405", "type_2": "keyword:number", "value_2": "HENRIK:1272", "counter": "1" } ], "status": 200 }
POST /stats/inbox.{format}
Ingest data into the stats system. Requires an internal advanced key.
The max batch size to post is 10000
curl 'http://api.linkmobility.dk/v2/stats/inbox.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/stats/inbox.xml?apikey=[apikey]' -X GET
{ "stats": [ { "code": "1272", "keywordid": "108406", "logtime": "2015-07-06 15:06:23", "materialized_path": "15m/49p", "msgid": "1436187983-48305", "topbruger": "1498", "userid": "7405" }, { "code": "+4512721272", "keywordid": "1234", "logtime": "2015-07-06 15:06:31", "materialized_path": "abc", "msgid": "1436187991-48309", "topbruger": 0, "userid": "7405" }, { "code": "1272", "keywordid": "107543", "logtime": "2015-07-06 15:06:32", "materialized_path": "1xg", "msgid": "1436187992-48313", "topbruger": "0", "userid": "7405" } ] }
POST /stats/outbox.{format}
Ingest data into the stats system. Requires an internal advanced key.
The max batch size to post is 10000
curl 'http://api.linkmobility.dk/v2/stats/outbox.json?apikey=[apikey]' -X GET curl 'http://api.linkmobility.dk/v2/stats/outbox.xml?apikey=[apikey]' -X GET
{ "stats": [ { "logtime": "2015-07-06 00:00:24", "materialized_path": "1s9/4j1", "mcc": "238", "msgid": "f151c342147599d3955c485f98a10d91", "payout": null, "price": "", "splitcount": "1", "status": "received", "topbruger": "2313", "userid": "5869", "group": "external" }, { "logtime": "2015-07-06 00:00:39", "materialized_path": "6lp", "mcc": "238", "msgid": "fe8f9e28811bf0f21f95eefbc59c4142", "payout": null, "price": "", "splitcount": "1", "status": "received", "topbruger": "0", "userid": "8557", "group": "internal" } ] }
11. Users
GET /users.{format}
Get all users associated with the user making the request. The request return both active and inactive users.
curl 'http://api.linkmobility.dk/v2/users.{format}?apikey=[apikey]' -X GET
Response
On success the request returns all the users associated with the requesting user
{ "users": [ { "integration_id": null, "company": null, "integration": null, "defaultsender": null, "balance": "1.2400000", "use_currency": 0, "max_forbrug": "999999", "forbrug": "131", "deactivated": null, "created": "07-12-2015 08:23:57", "parent": 0, "id": 10281, "username": "here_be_username", "apikey": "---", "materialized_path": "7xl", "prefixes": "", "iprange": "", "aclBilling": true, "aclBillingHigh": true, "aclCharity": true, "aclIncoming": true, "aclSmsinbox": true, "aclHlr": true, "aclAdmin": true, "enabled": true, "credits": 999868 } ], "status": 200 }
On failure the request will return a status 400 or 401 (depending on the error), with a message explaining the problem:
{ "status": 401, "message": "Access denied [abcd] authentication failed" }
Fields returned by a successfull request
Name | Description |
---|---|
integration_id | Used by resellers to identify users in their own CRM systems |
company | Primarily used by resellers to identify company names |
integration | Used by resellers to identify the customers integration type |
defaultsender | Default sender value on the receiving device |
balance | ??? |
use_currency | ??? |
max_forbrug | Maximum number of messages a user can send |
forbrug | Amount of messages a user has sent |
deactivated | If the user is disabled, then this indicates when the user was closed |
created | Indicates the date the user was created |
parent | ID of the parent user |
apikey | The users apikey |
materialized_path | Used to identify where the user is in the hierarchy related to it's parents |
prefixes | A list of prefixes the user is allowed to send to |
iprange | A list of IPs the user is allowed to use the api from |
aclBilling | Allows the user to send premium messages |
aclBillingHigh | Allows the user to send premium messages at higher values than DKK 12 |
aclCharity | Allows the user to send premium messages for charity |
aclIncoming | Allows the user to receive messages |
aclSmsinbox | Allows the user to user smsinbox.dk |
aclHlr | Allows the user to make HLR lookups |
aclAdmin | Allows the user to create/edit/delete users |
enabled | Indicates wether the user is enabled or disabled |
GET /user/{id}.{format}
Get a specific user, identified by id
curl 'http://api.linkmobility.dk/v2/user/{id}.json?apikey=[apikey]' -X GET
Response
On success the request will return the requested user
{ "user": { "integration_id": null, "company": null, "integration": "EC", "defaultsender": null, "balance": "1.2400000", "use_currency": 0, "max_forbrug": "999999", "forbrug": "131", "deactivated": null, "created": "07-12-2015 08:23:57", "parent": 0, "id": 10281, "username": "here_be_username", "apikey": "---", "materialized_path": "7xl", "prefixes": "", "iprange": "", "aclBilling": true, "aclBillingHigh": true, "aclCharity": true, "aclIncoming": true, "aclSmsinbox": true, "aclHlr": true, "aclAdmin": true, "enabled": true, "credits": 999868 }, "status": 200 }
On failure the request will return an error and a message describing what went wrong:
{ "status": 404, "message": "User id [9999999] not found" }
POST /user.{format}
Creates a new user
curl 'http://api.linkmobility.dk/v2/user.json?apikey=[apikey]' -H "Content-Type: application/json" -X POST -d @file.json
Payload file.json
{ "user": { "username": "test", "password": "test", "credits":0 } }
Fields
Name | Description | Required |
---|---|---|
username | Determines which username the new user will have | yes |
password | Determines the new users password. Must be sent in plain text. | yes |
credits | Determines how many credits the will be able to send. 1 credit = 1 message. If set to 0 (zero), the user will have infinite messages. | yes |
iprange | Used if the user should only be allowed to send from certain IPs. Must be formatted as follows: Single IP: 192.168.0.1 If not specified, it will be possible to send from any IP. | no |
Response
On success, the request will return a status 201 with the new user object
{ "user": { "integration_id": null, "company": null, "integration": "", "defaultsender": null, "balance": null, "use_currency": 0, "max_forbrug": "0", "forbrug": "0", "deactivated": null, "created": "27-05-2016 10:08:06", "parent": 10281, "id": 12273, "username": "api-example-test", "apikey": "here_be_apikey", "materialized_path": "7xl/9gx", "prefixes": "", "iprange": null, "aclBilling": true, "aclBillingHigh": true, "aclCharity": true, "aclIncoming": true, "aclSmsinbox": true, "aclHlr": true, "aclAdmin": false, "enabled": true, "credits": 0 }, "status": 201 }
If the status is anything but 201, then something has failed and a message describing the problem will be present
E.g. If the username is empty:
{ "message": "User not created, [username] empty", "status": 400 }
If the user is trying to create a user, but does not have persmission to do so:
{ "message": "User not created, [acl] access is denied for user", "status": 403 }
PUT /user/{id}.{format}
Updates a given user by id. When updating a user, a field will only be updated if it is set. If you leave out e.g. "IP range", then the IP range will not be updated.
curl PUT -d "http://api.linkmobility.dk/v2/user/{id}.json?apikey=[apikey]" -H "Content-Type: application/json" -X PUT -f @file.json
Payload file.json
{ "user": { "username":"new_username", "password":"new_password", "credits":100, "iprange":"", "newapikey":true, "enabled":1 } }
Fields
No fields are required and a field will only be updated if set.
Name | Description |
---|---|
username | Updates the username |
password | Updates the password. Must be sent in clear text |
credits | Indication how many credits should be added to the users balance |
iprange | If set, then the user will only be able to use the api from a specific set of IPs. Must be formatted as follows: Single IP: 192.168.0.1 |
newapikey | If set to 1, then the user will get a new apikey. Only use this, if you are sure you know what you are doing. |
enabled | Set to 1 to enable the user and set to 0 to disable the user. |
Response
On success a status 200 and the user object will be returned.
{ "user": { "integration_id": "101", "company": null, "integration": "", "defaultsender": null, "balance": null, "use_currency": 0, "max_forbrug": 100, "forbrug": "0", "deactivated": null, "created": "27-05-2016 09:25:26", "parent": 10281, "id": 12273, "username": "new_username", "apikey": "here_be_apikey", "materialized_path": "7xl/9gx", "prefixes": "", "iprange": "", "aclBilling": true, "aclBillingHigh": true, "aclCharity": true, "aclIncoming": true, "aclSmsinbox": true, "aclHlr": true, "aclAdmin": false, "enabled": true, "credits": 100 }, "status": 200 }
DEL /user/{id}.{format}
Used to delete a user
curl 'http://api.linkmobility.dk/v2/user/{id}.json?apikey=[apikey]' -X DELETE
12. Keywords
GET /keywords.{format}
Gets all keywords for the user.
{ "keywords": [ { "id": "6515641", "keyword": “PILEFLET”, "function": "http", "number": "1272", "category": "13", "mainkeyword": "0", "serviceid": "28205", "frameworkaccept": "1", "statusurl": null, "state": "reserved" }, { "id": "10281329", "keyword": “VANDFLASKE”, "function": "smsinbox", "number": "1272", "category": "9", "mainkeyword": "0", "service": null, "serviceid": "65797", "frameworkaccept": "1", "statusurl": null, "state": "reserved" }, ], "status": 200 }
GET /keywords/{number}/{keyword}.{format}
Gets a specific keyword on a specific number .
{ "keyword": { "id": "10283609", "keyword": "KONKURRENCE", "function": "subkeyword", "number": "1272", "category": "13", "mainkeyword": "0", "service": null, "serviceid": "0", "frameworkaccept": "1", "statusurl": null, "state": "reserved" }, "status": 200 }
If accessing a keyword, that is inaccessible, then a 404 - NOT FOUND will be issued.
{ "status": 404, "message": "Keyword [HELLO] was not found on number [1272]" }
GET /keywords/{id}.{format}
Gets a specific keywords, based on id
{ "keyword": { "id": "10301793", "keyword": "KUGLEPEN", "function": "contest", "number": "1272", "category": "8", "mainkeyword": "0", "serviceid": "1045", "frameworkaccept": "1", "statusurl": null, "state": "reserved" }, "status": 200 }
If accessing a keyword, that is inaccessible, then a 404 - NOT FOUND will be issued.
{ "status": 404, "message": "Keyword [HELLO] was not found on number [1272]" }
POST /keywords.{format}
Reserves a new keyword on a given number.
Fields:
Name | Description | Required |
---|---|---|
number | Which shortcode the keyword must be created on. The user must have access to this shortcode. | Yes |
keyword | Which keyword that should be reserved | Yes |
mainkeyword | If the keyword is a subkeyword of another keyword, this should contain the id of the main keyword. | No |
{ "number":"1272", "keyword":"papirhat" }
Response - OK
{ "keyword": { "id": "10305133", "keyword": "PAPIRHAT", "function": "", "number": "1272", "category": "0", "mainkeyword": "0", "service": null, "serviceid": "0", "frameworkaccept": "0", "statusurl": null, "state": "reserved" }, "status": 201 }
Response - Error
If anything goes wrong (e.g. the user does not have access to the given shortcode or the keyword is already taken on the shortcode), then a 4XX will be issued
{ "message": "User cannot access number [1919]", "status": 401 }
{ "message": "Keyword [PAPIRHAT] is already taken on [1272]", "status": 400 }
DELETE /keywords/{id}.{format}
Deletes a keyword, by a given id. The attached service will not be deleted.
Response - OK
If the keyword is deleted successfully, then a 200 OK will be returned along with the deleted keyword. The keyword will remain assigned to the number/user for the remainder of the running month, but it will be internally flagged for deletion.
{ "keyword": { "id": "10305133", "keyword": "PAPIRHAT", "function": "", "number": "1272", "category": "0", "mainkeyword": "0", "service": null, "serviceid": "0", "frameworkaccept": "0", "statusurl": null, "state": "reserved" }, "status": 201 }
Response - Error
If an error happens, a 4XX will be returned along with a message about what went wrong
{ "message": "Keyword [1234] was not found", "status": 404 }
13. Services
Types
It is currently only possible to work with the servicetype "http".
HTTP:
A service of the type http will forward the message to a given url by POST'ing it. The message will contain 3 request headeres along with the same 3 request paramters.
Name | Content | Type |
---|---|---|
SMS | The full incoming message with the keyword | String |
FROM | The sender with prefix, but not + (e.g. 4512345678) | Number |
NUMBER | The shortcode, the message has been sent to | Number |
GET /services/{type}.{format}
Returns a list of services available to the user of the given type.
curl 'http://api.linkmobility.dk/v2/services/http.{format}?apikey=[apikey]' -X GET
Response
{ "services": [ { "id": "28205", "url": "http://www.test.com/incoming", "continuous": "0", "charset": "" }, { "id": "31557", "url": "http://domain.dk/test", "continuous": "0", "charset": "" } ], "status": 200 }
POST /services/{type}.{format}
Creates a new service, that can be attached to a given keyword.
curl 'http://api.linkmobility.dk/v2/services/http.json?apikey=[apikey]' -H "Content-Type: application/json" -X POST -d @file.json
Payload file.json
{ "url":"http://www.test.com/incoming" }
Fields:
Name | Type | Description | Required |
---|---|---|---|
url | string | A valid url the message must be forwarded to | Yes |
charset | string | If the message must be sent in a specific charset, then set it here | No |
PUT /services/{type}/{id}.{format}
Updates a service given by type and id
curl 'http://api.linkmobility.dk/v2/services/http/{id}.json?apikey=[apikey]' -H "Content-Type: application/json" -X PUT -d @file.json
Payload file.json
{ "url":"http://www.test.com/incoming" }
Response - OK
If the update is ok, then a 200 OK will be returned, along with the updated object.
{ "service": { "id": "52533", "url": "http://www.test.com/incoming", "continuous": "1", "charset": "utf-8" }, "status": 200 }
Response - Error
If the update fails, then the system will response with a 4XX and a message to explain what was wrong.
{ "status": 400, "message": "Url cannot be empty" }
14. Contenttypes
GET /premium/contenttypes.{format}
Fetch a list of supported contenttypes for premium (priced) messages.
- Contenttypes can expire.
- Contenttypes are specific for shortcodes.
- Do not use the ids from the example below in production. Ask the API for an up to date list of contenttypes.
Note! These contenttypes only apply to the listed shortcodes.
Example response:
{ "data": [ { "contenttypes": [ { "id": "1", "description": "Ringetoner og billeder", "type": "digital", "vatexempt": "off", "expires": "2017-12-12" }, { "id": "2", "description": "Ringback toner", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "3", "description": "Musik (digital)", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "4", "description": "Wallpaper og animationer", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "5", "description": "Videoer", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "6", "description": "Nyheder", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "7", "description": "Indhold for voksne", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "8", "description": "Lotteri", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "9", "description": "Applikationer", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "10", "description": "Afstemninger", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "11", "description": "Mobil markedsforing", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "12", "description": "Internetportaler", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "13", "description": "Chat", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "14", "description": "Community", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "15", "description": "Info-services", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "16", "description": "Mixed digitalt indhold", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "17", "description": "Indsamling til humanitære organisationer (kræver godkendelse af “Stiftelsen Innsamlingskontrollen I Norge”)", "type": "donation", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "18", "description": "Koncertbilletter", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "19", "description": "Kontingent (medlemskab)", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "20", "description": "Diverse fysiske varer (nonfood)", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "21", "description": "Internet TV", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "22", "description": "Internet film", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "23", "description": "E-bøger", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "24", "description": "E-magasiner", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "25", "description": "E-aviser", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "26", "description": "Internet musik\t", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "27", "description": "Diverse digitalt indhold", "type": "digital", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "28", "description": "Biografbiletter", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "29", "description": "Bøger", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "30", "description": "Musik (CDer)", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "31", "description": "Magasiner", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "32", "description": "Entrebilletter (sport)", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "34", "description": "Klassificerede annoncer", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "35", "description": "Klassificerede annoncer (pris over 200 NOK)", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "38", "description": "Mad og drikkevarer", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "39", "description": "Transport (bus)", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "40", "description": "Transport (tog)", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "41", "description": "Sundheds-services", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" }, { "id": "42", "description": "Parkering", "type": "physical", "vatexempt": "off", "expires": "0000-00-00" } ], "shortcodes": [ "+472333" ] } ], "status": 200 }
Feeling lost? Click on this link! Portal page