Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for merge customers endpoint #255

Open
voghDev opened this issue Sep 15, 2023 · 8 comments
Open

Support for merge customers endpoint #255

voghDev opened this issue Sep 15, 2023 · 8 comments
Labels
enhancement New feature or request

Comments

@voghDev
Copy link

voghDev commented Sep 15, 2023

Is your feature request related to a problem? Please describe.
Hello!

We're trying to merge duplicated users in our App.
According to the documentation you provide, this can be done via web management, or calling the /api/v1/merge_customers endpoint.
I see there is no function to merge users in customer.io sdk for Android, nor iOS.

Are you planning to include a function to merge two users in the sdk?

Thanks in advance!

Describe the solution you'd like
An idea to user as starting point could be

Android (CustomerIO.kt)

fun merge(identifier: String, newIdentifier: String) {
    ... // call to /api/v1/merge_customers
}

iOS (CustomerIO.swift)

    func merge(
        identifier: String,
        newIdentifier: String
    )

Describe alternatives you've considered

Additional context
Having it in a newer version of the library would be awesome!

@Shahroz16 Shahroz16 added the enhancement New feature or request label Sep 15, 2023
@Shahroz16
Copy link
Contributor

Hi @voghDev,

Thank you for your feature request for "merge customer's endpoints". We've added it to our backlog for consideration in future releases.

We appreciate your feedback and suggestions.

@voghDev
Copy link
Author

voghDev commented Sep 22, 2023

Hi!

we've done our first successful merge requests. I'll post the Retrofit code we're using for calling the endpoint. I think it's ok posting it as any AI can generate a similar code snippet in seconds.

interface CustomerIoService {
  @POST("/api/v1/merge_customers")
  fun mergeCustomers(@Body paramsRequest: CustomerIoParamsRequest): Single<Unit>
}

data class CustomerIoParamsRequest(
  @SerializedName("primary")
  val primary: CustomerIoUserData,
  @SerializedName("secondary")
  val secondary: CustomerIoUserData,
)

data class CustomerIoUserData(
  @SerializedName("email")
  val email: String
)

class CustomerIoAuthHeaderInterceptor : Interceptor {
  private val siteId = "this is the siteId"
  private val apiKey = "this is the apiKey"
  override fun intercept(chain: Interceptor.Chain): Response = chain.run {
    val auth = buildAuthHeader(siteId, apiKey)
    proceed(
      request()
        .newBuilder()
        .header("Authorization", "Basic $auth")
        .build()
    )
  }

  private fun buildAuthHeader(siteId: String, apiKey: String) =
    Base64.encodeToString("$siteId:$apiKey".toByteArray(charset("UTF-8")), Base64.NO_WRAP)
}

// DI Module

private fun provideCustomerIoRetrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder()
  .baseUrl("https://track.customer.io/")
  .addConverterFactory(GsonConverterFactory.create())
  .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
  .client(okHttpClient)
  .build()

private fun provideCustomerIoHttpClient(): OkHttpClient {
  val logging = HttpLoggingInterceptor()
  val authHeaderInterceptor = CustomerIoAuthHeaderInterceptor()
  return OkHttpClient.Builder()
    .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
    .readTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
    .retryOnConnectionFailure(true)
    .addInterceptor(authHeaderInterceptor)
    .addInterceptor(logging)
    .build()
}

@Shahroz16 If you find something wrong on it, please let us know 🙏 we're guessing how the api works and apparently having concurrency issues between the sdk and our http layer

@Shahroz16
Copy link
Contributor

Hey @voghDev, thank you for posting this, can you explain the concurrency issue? because that shouldn't happen as SDKs network layer is going to be different than your app network layer, and I believe you are adding this in your own apps network layer.

@voghDev
Copy link
Author

voghDev commented Sep 26, 2023

Hi!
Thanks for your response. The issue is that we are getting a correct 200 OK HTTP response from the /api/v1/merge_customers endpoint, but we don't see the users merged in customer.io web panel.
After various attempts, it seems to end up merging the users correctly, but not the first time we execute it. That's why I thought about a concurrency issue, as we call identify() in the SDK and our merge Retrofit implementation in consecutive lines of code 🤔

@Shahroz16
Copy link
Contributor

I think it is because the merge request isn't blocking, it gets queued and then it gets performed when picked on the backend side of things. So as long as you got 200, and you had the right profiles, you should be okay.

@voghDev
Copy link
Author

voghDev commented Sep 28, 2023

Thanks for your help and support 🙌 We have fresh information that is helpful. It seems that when we merge the user immediately after the identify call, the answer is 200 as the Auth headers are correct, but the user is not being merged because the account has not been created yet. This happens for users identified for the first time in customer.io.
Seems like it takes a few millis/seconds for the account creation to complete.
Is there any way to query if an account exists (has been created) or not? by email, by id, by cio_id or any field? I don't see it in the SDK nor in the public Api, but would like to ask it, in case we can implement the query and share the code here 🙂

@Shahroz16
Copy link
Contributor

Hey @voghDev, I don't think there is any endpoint for this, unfortunately, so not an elegant solution but maybe add a delay? when you call the identify method of the CIO SDK, maybe add a delay of X second and then call merge?

That X seconds doesn't have to be a random value but X could be the according to your config of background queue plus some buffer?

@voghDev
Copy link
Author

voghDev commented Sep 28, 2023

That's one of the solutions we thought about; Adding a delay. Another solution would be a retry logic that performs a maximum of N attempts. Once the maximum attempts have been reached, it won't try to merge anymore. We'll let you know what we finally do 🙂 Thank you so much for the information!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants