Skip to main content

Configuration Guide

This guide covers everything you need to configure TecMeli with your Mercado Libre API credentials and customize the build for your needs.

API Credentials Overview

TecMeli requires three OAuth 2.0 credentials from Mercado Libre to authenticate API requests:
CredentialPurposeWhere It’s Used
CLIENT_IDIdentifies your applicationToken refresh requests
CLIENT_SECRETAuthenticates your applicationToken refresh requests
REFRESH_TOKENLong-lived token for obtaining access tokensAutomatic token renewal
These credentials are sensitive and should never be committed to version control. The local.properties file is automatically excluded via .gitignore.

Getting Mercado Libre API Credentials

1

Create a Mercado Libre Account

If you don’t already have one, create an account at mercadolibre.com
2

Register Your Application

Go to the Mercado Libre Developer Portal
  1. Navigate to My Applications
  2. Click Create Application
  3. Fill in the application details:
    • Name: TecMeli (or your preferred name)
    • Short Name: tecmeli
    • Description: Android client for Mercado Libre
    • Redirect URI: http://localhost (for testing)
3

Obtain Client Credentials

After creating your application, you’ll receive:
  • Client ID (App ID)
  • Client Secret (Secret Key)
Save these values - you’ll need them for configuration.
4

Generate Refresh Token

The refresh token requires OAuth 2.0 authorization flow:
  1. Construct the authorization URL:
    https://auth.mercadolibre.com/authorization?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI
    
  2. Visit this URL in a browser and authorize your application
  3. You’ll be redirected to your redirect URI with an authorization code
  4. Exchange the code for tokens using a POST request:
    curl -X POST \
      https://api.mercadolibre.com/oauth/token \
      -d grant_type=authorization_code \
      -d client_id=YOUR_CLIENT_ID \
      -d client_secret=YOUR_CLIENT_SECRET \
      -d code=YOUR_AUTH_CODE \
      -d redirect_uri=YOUR_REDIRECT_URI
    
  5. Save the refresh_token from the response
For detailed instructions on OAuth 2.0 flow, see the Mercado Libre Authentication Guide.

Creating local.properties

The local.properties file stores your API credentials locally and is never committed to version control.

Location

Create the file in the project root directory:
tecmeli/
├── app/
├── gradle/
├── local.properties    ← Create this file here
└── README.md

Configuration Format

Create local.properties with the following content:
local.properties
# Mercado Libre API Credentials
MELI_CLIENT_ID=your_client_id_here
MELI_CLIENT_SECRET=your_client_secret_here
MELI_REFRESH_TOKEN=your_refresh_token_here

# Android SDK Location (usually auto-generated by Android Studio)
sdk.dir=/path/to/Android/sdk

Example with Real Values

local.properties
# Mercado Libre API Credentials
MELI_CLIENT_ID=1234567890123456
MELI_CLIENT_SECRET=AbCdEfGhIjKlMnOpQrStUvWxYz123456
MELI_REFRESH_TOKEN=TG-507f1f77e4b0f7dce-121855823

# Android SDK Location
sdk.dir=/Users/username/Library/Android/sdk
Replace the example values with your actual credentials. The example tokens above will not work.

How Credentials Are Used

TecMeli reads credentials from local.properties and injects them into BuildConfig at compile time.

Build Configuration

From app/build.gradle.kts:
app/build.gradle.kts
android {
    namespace = "com.alcalist.tecmeli"
    compileSdk = 36

    defaultConfig {
        applicationId = "com.alcalist.tecmeli"
        minSdk = 26
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

        // Credentials from local.properties
        buildConfigField("String", "CLIENT_ID", 
            "\"${project.findProperty("MELI_CLIENT_ID") ?: ""}\"")
        buildConfigField("String", "CLIENT_SECRET", 
            "\"${project.findProperty("MELI_CLIENT_SECRET") ?: ""}\"")
        buildConfigField("String", "REFRESH_TOKEN", 
            "\"${project.findProperty("MELI_REFRESH_TOKEN") ?: ""}\"")
    }
    
    buildFeatures {
        compose = true
        buildConfig = true    // Enable BuildConfig generation
    }
}

Runtime Access

The credentials are accessed via BuildConfig in the NetworkModule:
core/di/NetworkModule.kt
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    /**
     * Provee la configuración base de la API extrayendo valores de BuildConfig.
     */
    @Provides
    @Singleton
    fun provideApiConfig(): ApiConfig {
        return ApiConfig(
            clientId = BuildConfig.CLIENT_ID,
            clientSecret = BuildConfig.CLIENT_SECRET,
            refreshToken = BuildConfig.REFRESH_TOKEN
        )
    }
}

ApiConfig Data Class

The credentials are encapsulated in a data class:
core/network/ApiConfig.kt
/**
 * Encapsula los parámetros de configuración necesarios para la autenticación con la API.
 *
 * Esta clase centraliza las credenciales requeridas por el flujo OAuth 2.0 de Mercado Libre,
 * permitiendo que sean inyectadas de forma consistente en los repositorios de tokens
 * y otros componentes de red.
 */
data class ApiConfig(
    val clientId: String,
    val clientSecret: String,
    val refreshToken: String
)

Token Refresh Flow

TecMeli automatically refreshes access tokens when they expire using the refresh token you configured.

How It Works

1

Initial Request

Every API request includes the current access token via AuthInterceptor:
core/network/AuthInterceptor.kt
class AuthInterceptor @Inject constructor(
    private val tokenRepository: TokenRepository
) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        
        // Skip auth for token endpoint
        if (originalRequest.url.encodedPath.contains("oauth/token")) {
            return chain.proceed(originalRequest)
        }

        val token = tokenRepository.getAccessToken()
        val requestBuilder = originalRequest.newBuilder()
        
        token?.let {
            requestBuilder.addHeader("Authorization", "Bearer $it")
        }
        
        return chain.proceed(requestBuilder.build())
    }
}
2

Handle 401 Unauthorized

When the token expires, the API returns 401. TokenAuthenticator intercepts this:
core/network/TokenAuthenticator.kt
class TokenAuthenticator @Inject constructor(
    private val tokenRepository: TokenRepository
) : Authenticator {

    override fun authenticate(route: Route?, response: Response): Request? {
        if (response.code != 401) return null

        val result = runBlocking {
            tokenRepository.refreshToken()
        }

        return if (result.isSuccess) {
            val newToken = result.getOrNull()
            response.request.newBuilder()
                .header("Authorization", "Bearer $newToken")
                .build()
        } else {
            null
        }
    }
}
3

Refresh Token Request

The TokenRepository uses your configured credentials to request a new access token:
POST https://api.mercadolibre.com/oauth/token
{
  "grant_type": "refresh_token",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "refresh_token": "YOUR_REFRESH_TOKEN"
}
4

Retry Original Request

The original request is automatically retried with the new access token - completely transparent to the user!
This automatic token refresh ensures users never experience authentication interruptions during normal app usage.

Build Variants

TecMeli uses standard Android build variants:
app/build.gradle.kts
buildTypes {
    release {
        isMinifyEnabled = false
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
    }
}

Debug Build (Default)

Terminal
./gradlew assembleDebug
  • Debuggable: Yes
  • Minification: Disabled
  • Logging: Full HTTP logging enabled
  • Use case: Development and testing

Release Build

Terminal
./gradlew assembleRelease
  • Debuggable: No
  • Minification: Disabled (can be enabled)
  • Logging: Should be reduced in production
  • Use case: Production deployment
Before creating a release build for production, enable code minification and configure ProGuard rules to protect your API credentials.

Verification

After configuring your credentials, verify the setup:

1. Clean and Rebuild

Terminal
./gradlew clean build
This ensures BuildConfig is regenerated with your credentials.

2. Check BuildConfig

After building, verify the generated BuildConfig.java:
app/build/generated/source/buildConfig/debug/com/alcalist/tecmeli/BuildConfig.java
You should see:
BuildConfig.java
public final class BuildConfig {
  public static final String CLIENT_ID = "your_client_id";
  public static final String CLIENT_SECRET = "your_client_secret";
  public static final String REFRESH_TOKEN = "your_refresh_token";
  // ... other fields
}

3. Run the Application

Launch the app on an emulator or device:
Terminal
./gradlew installDebug
Or use Android Studio’s Run button (⌘R / Ctrl+R).

4. Test API Connectivity

In the app:
  1. Enter a search term (e.g., “laptop”)
  2. Tap the search button
  3. Verify products are loaded successfully
If you see products, your API credentials are configured correctly!

Troubleshooting

Symptom: Build error or empty BuildConfig fieldsSolution:
  1. Verify local.properties exists in the project root
  2. Check property names match exactly: MELI_CLIENT_ID, MELI_CLIENT_SECRET, MELI_REFRESH_TOKEN
  3. Restart Android Studio and sync Gradle
  4. Run ./gradlew clean build
Symptom: API requests fail with 401 errorPossible causes:
  1. Invalid credentials: Double-check your Client ID and Secret
  2. Expired refresh token: Generate a new refresh token
  3. Application not approved: Check your app status in the Developer Portal
Debug steps:
// Check what token is being used
Log.d("Auth", "Client ID: ${BuildConfig.CLIENT_ID}")
Log.d("Auth", "Refresh Token: ${BuildConfig.REFRESH_TOKEN}")
Symptom: Network errors or timeoutsSolution:
  1. Check your internet connection
  2. Verify the base URL in NetworkModule.kt:
    private const val BASE_URL = "https://api.mercadolibre.com/"
    
  3. Check OkHttp logs in Logcat for detailed error messages
Symptom: BuildConfig fields are empty stringsSolution: The Gradle configuration uses findProperty() which returns null if not found:
buildConfigField("String", "CLIENT_ID", 
    "\"${project.findProperty("MELI_CLIENT_ID") ?: ""}\"")
If credentials are empty:
  1. Ensure local.properties is in the correct location (project root)
  2. Verify property names are correct
  3. Restart Android Studio
  4. Invalidate caches: File → Invalidate Caches / Restart

Security Best Practices

Never Commit Credentials

Always keep credentials in local.properties, never in version control

Use Environment-Specific Configs

Consider separate credentials for development, staging, and production

Rotate Tokens Regularly

Refresh tokens can be regenerated in the Developer Portal

Enable ProGuard

Obfuscate credentials in release builds using ProGuard/R8

Additional Configuration Options

Network Logging

HTTP logging is configured in NetworkModule.kt:
core/di/NetworkModule.kt
@Provides
@Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
    return HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }
}
For production, change to:
level = HttpLoggingInterceptor.Level.NONE

Custom Base URL

To use a different Mercado Libre region or test environment:
core/di/NetworkModule.kt
private const val BASE_URL = "https://api.mercadolibre.com/"  // International
// or
private const val BASE_URL = "https://api.mercadolibre.com.ar/"  // Argentina
// or
private const val BASE_URL = "https://api.mercadolibre.com.mx/"  // Mexico

Next Steps

Your TecMeli installation is now complete and configured! Here’s what you can do next:

Explore the Architecture

Deep dive into Clean Architecture implementation

Run Tests

Learn about the testing strategy and run the test suite

UI Components

Explore Jetpack Compose UI components

API Reference

Browse the codebase API documentation

Build docs developers (and LLMs) love