Skip to main content

Overview

The remote API layer defines Retrofit interfaces that communicate with Mercado Libre’s REST API. These interfaces handle product search, product details, and OAuth authentication.

MeliApi

Retrofit interface for interacting with the Mercado Libre product catalog.

Interface Definition

interface MeliApi
Location: data/remote/api/MeliApi.kt:11 Base URL: Configured via ApiConfig (typically https://api.mercadolibre.com/)

Endpoints

searchProducts

Searches for products based on query criteria.
@GET("products/search")
suspend fun searchProducts(
    @Query("status") status: String = "active",
    @Query("site_id") siteId: String = "MCO",
    @Query("q") query: String
): Response<SearchResponseDto>
HTTP Method: GET Path: /products/search Implementation: MeliApi.kt:20
string
default:"active"
Product status filter (e.g., “active”, “inactive”)
string
default:"MCO"
Geographic site identifier (MCO = Colombia)
string
required
Search query term provided by the user
val meliApi: MeliApi = retrofit.create(MeliApi::class.java)
val response = meliApi.searchProducts(
    query = "laptop",
    siteId = "MCO",
    status = "active"
)

getProductById

Retrieves detailed information for a specific product using its unique identifier.
@GET("products/search")
suspend fun getProductById(
    @Query("site_id") siteId: String = "MCO",
    @Query("product_identifier") productId: String
): Response<SearchResponseDto>
HTTP Method: GET Path: /products/search Implementation: MeliApi.kt:34
string
default:"MCO"
Geographic site identifier (MCO = Colombia)
string
required
Unique product identifier (e.g., “MCO12345”)
val response = meliApi.getProductById(
    productId = "MCO123456",
    siteId = "MCO"
)
Despite requesting a single product, the API returns a SearchResponseDto with the product in the results array. The repository layer extracts the first result.

AuthApi

Retrofit interface for OAuth 2.0 authentication flow with Mercado Libre.

Interface Definition

interface AuthApi
Location: data/remote/api/AuthApi.kt:14 Base URL: Configured via ApiConfig (typically https://api.mercadolibre.com/)

Endpoints

refreshToken

Requests a new access token using a refresh token (OAuth 2.0 refresh token grant).
@POST("oauth/token")
@FormUrlEncoded
suspend fun refreshToken(
    @Field("grant_type") grantType: String = "refresh_token",
    @Field("client_id") clientId: String,
    @Field("client_secret") clientSecret: String,
    @Field("refresh_token") refreshToken: String
): Response<AuthResponseDto>
HTTP Method: POST Path: /oauth/token Content-Type: application/x-www-form-urlencoded Implementation: AuthApi.kt:24
grant_type
string
default:"refresh_token"
OAuth grant type (always “refresh_token” for token refresh)
client_id
string
required
Application client identifier from Mercado Libre developer portal
client_secret
string
required
Application client secret from Mercado Libre developer portal
refresh_token
string
required
Long-lived refresh token obtained during initial authentication
val authApi: AuthApi = retrofit.create(AuthApi::class.java)
val response = authApi.refreshToken(
    grantType = "refresh_token",
    clientId = "1234567890",
    clientSecret = "abcdefghijklmnopqrstuvwxyz",
    refreshToken = "TG-abc123..."
)
The client_secret is sensitive and should never be committed to version control. Use secure configuration management (e.g., BuildConfig, environment variables).

Response DTOs

SearchResponseDto

Root response object for product search and detail endpoints.
data class SearchResponseDto(
    @SerializedName("paging") var paging: PagingDto? = PagingDto(),
    @SerializedName("results") var results: ArrayList<ResultsDto> = arrayListOf()
)
Location: data/remote/dto/SearchResponseDto.kt:14
paging
PagingDto
Pagination metadata (total results, offset, limit)
results
ArrayList<ResultsDto>
Array of product objects matching the search criteria

ResultsDto

Individual product object in the search response.
data class ResultsDto(
    @SerializedName("id") var id: String,
    @SerializedName("catalog_product_id") var catalogProductId: String,
    @SerializedName("domain_id") var domainId: String,
    @SerializedName("name") var name: String,
    @SerializedName("attributes") var attributes: ArrayList<AttributesDto> = arrayListOf(),
    @SerializedName("short_description") var shortDescription: ShortDescriptionDto? = ShortDescriptionDto(),
    @SerializedName("pictures") var pictures: ArrayList<PicturesDto> = arrayListOf(),
    @SerializedName("last_updated") var lastUpdated: String? = null
)
Location: data/remote/dto/ResultsDto.kt:20
id
String
required
Unique product identifier (e.g., “MCO123456”)
catalog_product_id
String
required
Global catalog identifier
domain_id
String
required
Product category/domain identifier (e.g., “LAPTOPS”)
name
String
required
Product title or name
attributes
ArrayList<AttributesDto>
Technical specifications (brand, model, color, etc.)
short_description
ShortDescriptionDto
Brief product description
pictures
ArrayList<PicturesDto>
Product image gallery
last_updated
String
ISO 8601 timestamp of last product update

AttributesDto

Technical attribute or specification of a product.
data class AttributesDto(
    @SerializedName("id") var id: String,
    @SerializedName("name") var name: String,
    @SerializedName("value_name") var valueName: String? = null
)
Location: data/remote/dto/AttributesDto.kt:15
id
String
required
Attribute identifier (e.g., “BRAND”, “COLOR”)
name
String
required
Human-readable attribute name (e.g., “Marca”, “Color”)
value_name
String
Human-readable attribute value (e.g., “Dell”, “Negro”)

AuthResponseDto

OAuth token response from the authentication server.
data class AuthResponseDto(
    @SerializedName("access_token") val accessToken: String,
    @SerializedName("token_type") val tokenType: String,
    @SerializedName("expires_in") val expiresIn: Long,
    @SerializedName("scope") val scope: String,
    @SerializedName("user_id") val userId: Long,
    @SerializedName("refresh_token") val refreshToken: String
)
Location: data/remote/dto/AuthResponseDto.kt:15
access_token
String
required
Short-lived access token for API authorization
token_type
String
required
Token type (typically “Bearer”)
expires_in
Long
required
Token lifetime in seconds (typically 21600 = 6 hours)
scope
String
required
Granted permissions (e.g., “offline_access read”)
user_id
Long
required
Authenticated user’s Mercado Libre ID
refresh_token
String
required
Long-lived token for obtaining new access tokens

Authentication Flow

The APIs use OAuth 2.0 Bearer token authentication:
1

Initial Token Acquisition

Obtain initial access and refresh tokens through Mercado Libre’s OAuth web flow (not implemented in app).
2

Token Storage

Store refresh token securely (currently in ApiConfig, should use encrypted storage).
3

Token Refresh

Use AuthApi.refreshToken() to obtain new access tokens when needed.
4

Token Injection

Inject access token into API requests via OkHttp interceptor.
// Simplified interceptor pattern
class AuthInterceptor @Inject constructor(
    private val tokenRepository: TokenRepository
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val token = tokenRepository.getAccessToken()
        val request = chain.request().newBuilder()
            .addHeader("Authorization", "Bearer $token")
            .build()
        return chain.proceed(request)
    }
}

Error Handling

All API methods return Response<T> which is wrapped by the repository layer using safeApiCall. Common errors include:
{
  "message": "invalid_token",
  "error": "invalid_grant",
  "status": 401
}

Retrofit Configuration

APIs are provided through Hilt dependency injection:
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    @Singleton
    fun provideMeliApi(retrofit: Retrofit): MeliApi {
        return retrofit.create(MeliApi::class.java)
    }
    
    @Provides
    @Singleton
    fun provideAuthApi(retrofit: Retrofit): AuthApi {
        return retrofit.create(AuthApi::class.java)
    }
}

Repositories

Repository implementations using these APIs

Mappers

DTO to domain model transformations

Build docs developers (and LLMs) love