Get country change events

Country change events are events triggered whenever a subscriber changes their current country location. It will be triggered once per SIM card that changes its currently registered network's country.

The event contains both the new (current) country, and the old (previous) country, with both the ISO country code, and a readable country name.

Prerequisites

  1. An OAuth 2.0 client
  2. A client access token

Required scope

subscription.country_change:read

Code

TIP

You can test our APIs without authorization by targetting sandbox.api.wgtwo.com instead of api.wgtwo.com and removing any authorization from the request/code sample.

Download proto definitions
curl -sL 'https://github.com/working-group-two/wgtwoapis/blob/master/image.bin?raw=true' -o wgtwo.bin
1
export ACCESS_TOKEN="my_client_access_token"
grpcurl -protoset wgtwo.bin \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '
  {
    "stream_configuration": {
      "regular": {},
      "disable_explicit_ack": {}
    }
  }
  ' \
  api.wgtwo.com:443 \
  wgtwo.subscription.v1.SubscriptionEventService/StreamCountryChangeEvents
1
2
3
4
5
6
7
8
9
10
11
12
13
About stream_configuration

For testing purposes, we include the config:

"stream_configuration": {
  "regular": {},              Reading position will not be stored in the server and load is not spread between your clients 
  "disable_explicit_ack": {}  Let events be automatically acked
}
1
2
3
4

By default, load will automatically be spread between all connections using the same OAuth 2.0 client and you will need to reply with a ack once your service has handled the message. This is also what we would recommend for real production usage.

See configuring event streaming for details.

Example result

{
  "countryChangeEvent": {
    "previous": {
      "code": "SE",
      "name": "Sweden"
    },
    "current": {
      "code": "NO",
      "name": "Norway"
    }
  }
}
{
  "countryChangeEvent": {
    "previous": {
      "code": "NO",
      "name": "Norway"
    },
    "current": {
      "code": "SE",
      "name": "Sweden"
    }
  }
}
{
  "countryChangeEvent": {
    "previous": {
      "code": "SE",
      "name": "Sweden"
    },
    "current": {
      "code": "US",
      "name": "US"
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Install dependencies

Maven

<dependency>
  <groupId>com.wgtwo.api.v1.grpc</groupId>
  <artifactId>subscription</artifactId>
  <version>1.10.1</version>
</dependency>
package com.example.countrychange

import com.wgtwo.api.v1.subscription.SubscriptionEventServiceGrpc
import com.wgtwo.api.v1.subscription.SubscriptionEventsProto.AckCountryChangeEventRequest
import com.wgtwo.api.v1.subscription.SubscriptionEventsProto.StreamCountryChangeEventsRequest
import com.wgtwo.api.v1.subscription.SubscriptionEventsProto.StreamCountryChangeEventsResponse
import com.wgtwo.auth.BearerTokenCallCredentials
import io.grpc.ManagedChannelBuilder
import io.grpc.StatusRuntimeException
import java.util.concurrent.Executors

private const val MAX_IN_FLIGHT = 10
private val environment = Environment.SANDBOX

private val endpoint = when (environment) {
    Environment.SANDBOX -> "sandbox.api.wgtwo.com"
    Environment.PRODUCTION -> "api.wgtwo.com"
}
private val channel = ManagedChannelBuilder.forAddress(endpoint, 443).build()
private val stub = SubscriptionEventServiceGrpc.newBlockingStub(channel).apply {
    /**
     * If you are not using the sandbox, you need to add credentials.
     * The BearerTokenCallCredentials class can be found in our auth library.
     */
    if (environment == Environment.PRODUCTION) {
        this.withCallCredentials(BearerTokenCallCredentials { "MY_CLIENT_ACCESS_TOKEN" })
    }
}
private val executor = Executors.newFixedThreadPool(MAX_IN_FLIGHT)

fun main() {
    while (!channel.isShutdown) {
        try {
            subscribe()
        } catch (e: StatusRuntimeException) {
            println("Got exception: ${e.status} - Reconnecting in 1 second")
            Thread.sleep(1000)
        }
    }
}

private fun subscribe() {
    println("Starting subscription")
    val request = StreamCountryChangeEventsRequest.newBuilder().apply {
        streamConfigurationBuilder.maxInFlight = MAX_IN_FLIGHT
    }.build()

    stub.streamCountryChangeEvents(request).forEach { response ->
        // Using an executor to handle up to MAX_IN_FLIGHT messages in parallel
        executor.submit {
            handleResponse(response)
            ack(response)
        }
    }
}

private fun handleResponse(response: StreamCountryChangeEventsResponse) {
    println("Got response:\n$response")
}

private fun ack(response: StreamCountryChangeEventsResponse) {
    val ackInfo = response.metadata.ackInfo
    val request = AckCountryChangeEventRequest.newBuilder().setAckInfo(ackInfo).build()
    stub.ackCountryChangeEvent(request)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

Example result

country_change_event {
  previous {
    code: "US"
    name: "United States"
  }
  current {
    code: "SE"
    name: "Sweden"
  }
}

# Ack success

country_change_event {
  previous {
    code: "SE"
    name: "Sweden"
  }
  current {
    code: "NO"
    name: "Norway"
  }
}

# Ack success

country_change_event {
  previous {
    code: "NO"
    name: "Norway"
  }
  current {
    code: "SE"
    name: "Sweden"
  }
}

# Ack success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

Read more