Atlas API API Reference

Complete API documentation for geographic data in English and Arabic.

About SolvyAtlas API

SolvyAtlas API provides comprehensive geographic data for countries, governorates, and cities in both English and Arabic. Access structured location data with bilingual support, perfect for building address forms, location pickers, shipping calculators, and regional analytics applications.

📍 Currently Available

🇪🇬 Egypt

🚀 More countries coming soon! Stay tuned for updates.

🎉 Free Access

The SolvyAtlas API is currently completely free to use during our launch period. Get your API credentials and start building today!

ℹ️ Please note: Subscription fees may be introduced in the future. Early adopters will receive special benefits and advance notice of any pricing changes.

API Overview

SolvyAtlas API uses secure HMAC-SHA256 authentication for all client endpoints. After requesting access, you will receive your API credentials for free.

Base URL

https://atlasapi.solvytix.com

API Keys Format

You will receive two types of keys:

Public Key
pk_aB3xYz9mN7qWe8rT5yU2iO4pL6kJ1hG0
• Sent in request headers to identify your application
• Can be logged and exposed (not sensitive)
Secret Key
sk_dE6fG8hJ2kL4mN9oP1qR3sT5uV7wX0yZ
• ⚠️ MUST BE KEPT SECRET - Used locally to sign requests
• ⚠️ NEVER sent to server or exposed in client-side code

Language Selection

Specify your preferred language by including the Accept-Language header:

Accept-Language: en    // For English
Accept-Language: ar    // For Arabic

Endpoints without /with-translations return data in the language specified in the header. Endpoints with /with-translations return data in both English and Arabic simultaneously.

All endpoints return application/json.

🔐 HMAC Authentication

SolvyAtlas API uses HMAC-SHA256 for secure request authentication. Each request must include three authentication headers.

Required Headers

Every authenticated request MUST include these headers:

Header Description Example
X-Api-PublicKey Your public key pk_aB3xYz...
X-Api-Timestamp Unix timestamp (seconds) 1704451800
X-Api-Signature HMAC-SHA256 signature (Base64) 8mF3nQ5pR7t...

How HMAC Authentication Works

  1. Client receives Public Key and Secret Key
  2. For each request, Client creates a signature using:
    • Current Unix timestamp (seconds)
    • Secret Key
  3. Client sends request with Public Key, Timestamp, and Signature
  4. Server validates:
    • Public Key exists and is active
    • Timestamp is within 5-minute window
    • Signature matches expected value

Signature Calculation

Generate the signature using this algorithm:

Step 1: Get Current Timestamp
    timestamp = current Unix time in seconds

Step 2: Create Payload
    payload = timestamp (as string)

Step 3: Compute HMAC-SHA256
    signature_bytes = HMAC-SHA256(secret_key, payload)

Step 4: Encode to Base64
    signature = Base64Encode(signature_bytes)

Step 5: Send Request with Headers
    X-Api-PublicKey: your_public_key
    X-Api-Timestamp: timestamp
    X-Api-Signature: signature
    Accept-Language: en or ar

⚠️ Important Rules

  • Timestamp Format: Unix timestamp in seconds (not milliseconds)
  • Time Window: Must be within 5 minutes of server time
  • All Client Requests: Payload = timestamp only (all endpoints are GET)

Error Responses

Status Code Error Cause
401 Unauthorized Missing/invalid headers, inactive key, wrong signature
401 Timestamp too old Request timestamp >5 minutes old
429 Rate limit exceeded Too many requests per minute

Country Endpoints

GET /api/client/countries
Returns list of countries in the language specified in request headers (English or Arabic).

Response Example:

[
  {
    "id": 1,
    "code": "EG",
    "name": "Egypt"
  }
]
GET /api/client/countries/with-translations
Returns countries with English and Arabic names including translation metadata.

Response Example:

[
  {
    "id": 1,
    "code": "EG",
    "translations": [
      {
        "language": "en",
        "name": "Egypt"
      },
      {
        "language": "ar",
        "name": "مصر"
      }
    ]
  }
]
GET /api/client/countries/{id}
Returns country details by ID in the language specified in request headers.

Parameters:

id (path) - Country ID (integer)

Response Example:

{
  "id": 1,
  "code": "EG",
  "name": "Egypt"
}

Governorate Endpoints

GET /api/client/governrate
Returns list of governorates in the language specified in request headers (English or Arabic).

Response Example:

[
  {
    "id": 1,
    "countryId": 1,
    "name": "Cairo"
  }
]
GET /api/client/governrate/with-translations
Returns governorates with English and Arabic names including translation metadata.

Response Example:

[
  {
    "id": 1,
    "countryId": 1,
    "translations": [
      {
        "language": "en",
        "name": "Cairo"
      },
      {
        "language": "ar",
        "name": "القاهرة"
      }
    ]
  }
]
GET /api/client/governrate/{id}
Returns governorate by ID in the language specified in request headers.

Parameters:

id (path) - Governorate ID (integer)

Response Example:

{
  "id": 1,
  "countryId": 1,
  "name": "Cairo"
}

City Endpoints

GET /api/client/cities
Returns list of cities in the language specified in request headers (English or Arabic).

Response Example:

[
  {
    "id": 1,
    "governorateId": 1,
    "name": "Nasr City"
  }
]
GET /api/client/cities/with-translations
Returns cities with English and Arabic names including translation metadata.

Response Example:

[
  {
    "id": 1,
    "governorateId": 1,
    "translations": [
      {
        "language": "en",
        "name": "Nasr City"
      },
      {
        "language": "ar",
        "name": "مدينة نصر"
      }
    ]
  }
]
GET /api/client/cities/with-translations/{governorateId}
Returns cities filtered by governorate with English and Arabic names.

Parameters:

governrateId (path) - Governorate ID (integer)

Response Example:

[
  {
    "id": 1,
    "governorateId": 1,
    "translations": [
      {
        "language": "en",
        "name": "Nasr City"
      },
      {
        "language": "ar",
        "name": "مدينة نصر"
      }
    ]
  }
]
GET /api/client/cities/governorate/{governorateId}
Returns cities by governorate ID in the language specified in request headers.

Parameters:

governorateId (path) - Governorate ID (integer)

Response Example:

[
  {
    "id": 1,
    "governorateId": 1,
    "name": "Nasr City"
  }
]
GET /api/client/cities/{id}
Returns city details by ID in the language specified in request headers.

Parameters:

id (path) - City ID (integer)

Response Example:

{
  "id": 1,
  "governorateId": 1,
  "name": "Nasr City"
}

Usage Examples

// Browser JavaScript - HMAC-SHA256 Authentication using Web Crypto API

class AtlasApiClient {
  constructor(publicKey, secretKey) {
    this.publicKey = publicKey;
    this.secretKey = secretKey;
    this.baseURL = 'https://atlasapi.solvytix.com/api/client';
  }

  async generateSignature(timestamp, body = '') {
    const payload = `${timestamp}${body}`;
    const encoder = new TextEncoder();
    
    // Convert secret key to crypto key
    const keyData = encoder.encode(this.secretKey);
    const key = await crypto.subtle.importKey(
      'raw',
      keyData,
      { name: 'HMAC', hash: 'SHA-256' },
      false,
      ['sign']
    );
    
    // Sign the payload
    const messageData = encoder.encode(payload);
    const signature = await crypto.subtle.sign('HMAC', key, messageData);
    
    // Convert to Base64
    return btoa(String.fromCharCode(...new Uint8Array(signature)));
  }

  async getCountries(language = 'en') {
    try {
      const timestamp = Math.floor(Date.now() / 1000);
      const signature = await this.generateSignature(timestamp);

      const response = await fetch(`${this.baseURL}/countries`, {
        headers: {
          'X-Api-PublicKey': this.publicKey,
          'X-Api-Timestamp': timestamp.toString(),
          'X-Api-Signature': signature,
          'Accept-Language': language  // 'en' for English, 'ar' for Arabic
        }
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      console.error('Error fetching countries:', error);
      throw error;
    }
  }

  async getCitiesByGovernorate(governorateId, language = 'en') {
    try {
      const timestamp = Math.floor(Date.now() / 1000);
      const signature = await this.generateSignature(timestamp);

      const response = await fetch(
        `${this.baseURL}/cities/governorate/${governorateId}`,
        {
          headers: {
            'X-Api-PublicKey': this.publicKey,
            'X-Api-Timestamp': timestamp.toString(),
            'X-Api-Signature': signature,
            'Accept-Language': language
          }
        }
      );

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      console.error('Error fetching cities:', error);
      throw error;
    }
  }
}

// Example usage
const client = new AtlasApiClient(
  'pk_aB3xYz9mN7qWe8rT5yU2iO4pL6kJ1hG0',
  'sk_dE6fG8hJ2kL4mN9oP1qR3sT5uV7wX0yZ'
);

// Get countries
client.getCountries('en')
  .then(data => console.log('Countries:', data))
  .catch(err => console.error(err));
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

public class AtlasApiClient
{
    private readonly HttpClient _httpClient;
    private readonly string _publicKey;
    private readonly string _secretKey;

    public AtlasApiClient(string publicKey, string secretKey)
    {
        _publicKey = publicKey;
        _secretKey = secretKey;
        _httpClient = new HttpClient();
    }

    private string GenerateSignature(long timestamp, string body = "")
    {
        var payload = $"{timestamp}{body}";
        var keyBytes = Encoding.UTF8.GetBytes(_secretKey);
        var messageBytes = Encoding.UTF8.GetBytes(payload);

        using var hmac = new HMACSHA256(keyBytes);
        var hashBytes = hmac.ComputeHash(messageBytes);
        return Convert.ToBase64String(hashBytes);
    }

    private long GetUnixTimestamp()
    {
        return DateTimeOffset.UtcNow.ToUnixTimeSeconds();
    }

    public async Task<string> GetCountriesAsync(string language = "en")
    {
        var timestamp = GetUnixTimestamp();
        var signature = GenerateSignature(timestamp);

        var request = new HttpRequestMessage(HttpMethod.Get, 
            "https://atlasapi.solvytix.com/api/client/countries");
        
        request.Headers.Add("X-Api-PublicKey", _publicKey);
        request.Headers.Add("X-Api-Timestamp", timestamp.ToString());
        request.Headers.Add("X-Api-Signature", signature);
        request.Headers.Add("Accept-Language", language);

        var response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();
        
        return await response.Content.ReadAsStringAsync();
    }
}

// Example usage
var client = new AtlasApiClient(
    "pk_aB3xYz9mN7qWe8rT5yU2iO4pL6kJ1hG0",
    "sk_dE6fG8hJ2kL4mN9oP1qR3sT5uV7wX0yZ"
);
var countries = await client.GetCountriesAsync("en");
import hmac
import hashlib
import base64
import time
import requests

class AtlasApiClient:
    def __init__(self, public_key, secret_key):
        self.public_key = public_key
        self.secret_key = secret_key
        self.base_url = "https://atlasapi.solvytix.com/api/client"
    
    def _generate_signature(self, timestamp, body=''):
        """Generate HMAC-SHA256 signature"""
        payload = f"{timestamp}{body}"
        signature = hmac.new(
            self.secret_key.encode('utf-8'),
            payload.encode('utf-8'),
            hashlib.sha256
        ).digest()
        return base64.b64encode(signature).decode('utf-8')
    
    def _get_timestamp(self):
        """Get current Unix timestamp in seconds"""
        return int(time.time())
    
    def get_countries(self, language='en'):
        """
        Get countries list
        language: 'en' for English, 'ar' for Arabic
        """
        timestamp = self._get_timestamp()
        signature = self._generate_signature(timestamp)
        
        headers = {
            'X-Api-PublicKey': self.public_key,
            'X-Api-Timestamp': str(timestamp),
            'X-Api-Signature': signature,
            'Accept-Language': language
        }
        
        response = requests.get(
            f'{self.base_url}/countries',
            headers=headers
        )
        response.raise_for_status()
        return response.json()

# Example usage
client = AtlasApiClient(
    'pk_aB3xYz9mN7qWe8rT5yU2iO4pL6kJ1hG0',
    'sk_dE6fG8hJ2kL4mN9oP1qR3sT5uV7wX0yZ'
)

countries = client.get_countries('en')
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.time.Instant;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class AtlasApiClient {
    private final HttpClient httpClient;
    private final String publicKey;
    private final String secretKey;
    private static final String BASE_URL = 
        "https://atlasapi.solvytix.com/api/client";

    public AtlasApiClient(String publicKey, String secretKey) {
        this.publicKey = publicKey;
        this.secretKey = secretKey;
        this.httpClient = HttpClient.newHttpClient();
    }

    private String generateSignature(long timestamp, String body) 
        throws Exception {
        String payload = timestamp + body;
        Mac hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec keySpec = new SecretKeySpec(
            secretKey.getBytes("UTF-8"), "HmacSHA256"
        );
        hmac.init(keySpec);
        byte[] hash = hmac.doFinal(payload.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(hash);
    }

    public String getCountries(String language) throws Exception {
        long timestamp = Instant.now().getEpochSecond();
        String signature = generateSignature(timestamp, "");

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(BASE_URL + "/countries"))
            .header("X-Api-PublicKey", publicKey)
            .header("X-Api-Timestamp", String.valueOf(timestamp))
            .header("X-Api-Signature", signature)
            .header("Accept-Language", language)
            .GET()
            .build();

        HttpResponse<String> response = httpClient.send(
            request, HttpResponse.BodyHandlers.ofString()
        );
        return response.body();
    }

    public static void main(String[] args) throws Exception {
        AtlasApiClient client = new AtlasApiClient(
            "pk_aB3xYz9mN7qWe8rT5yU2iO4pL6kJ1hG0",
            "sk_dE6fG8hJ2kL4mN9oP1qR3sT5uV7wX0yZ"
        );
        String countries = client.getCountries("en");
        System.out.println(countries);
    }
}
const crypto = require('crypto');
const axios = require('axios');

class AtlasApiClient {
  constructor(publicKey, secretKey) {
    this.publicKey = publicKey;
    this.secretKey = secretKey;
    this.baseURL = 'https://atlasapi.solvytix.com/api/client';
  }

  generateSignature(timestamp, body = '') {
    const payload = `${timestamp}${body}`;
    const signature = crypto
      .createHmac('sha256', this.secretKey)
      .update(payload)
      .digest('base64');
    return signature;
  }

  async getCountries(language = 'en') {
    try {
      const timestamp = Math.floor(Date.now() / 1000);
      const signature = this.generateSignature(timestamp);

      const response = await axios.get(`${this.baseURL}/countries`, {
        headers: {
          'X-Api-PublicKey': this.publicKey,
          'X-Api-Timestamp': timestamp.toString(),
          'X-Api-Signature': signature,
          'Accept-Language': language
        }
      });
      return response.data;
    } catch (error) {
      console.error('Error:', error.response?.data || error.message);
      throw error;
    }
  }

  async getCitiesByGovernorate(governorateId, language = 'en') {
    try {
      const timestamp = Math.floor(Date.now() / 1000);
      const signature = this.generateSignature(timestamp);

      const response = await axios.get(
        `${this.baseURL}/cities/governorate/${governorateId}`,
        {
          headers: {
            'X-Api-PublicKey': this.publicKey,
            'X-Api-Timestamp': timestamp.toString(),
            'X-Api-Signature': signature,
            'Accept-Language': language
          }
        }
      );
      return response.data;
    } catch (error) {
      console.error('Error:', error.response?.data || error.message);
      throw error;
    }
  }
}

// Example usage
const client = new AtlasApiClient(
  'pk_aB3xYz9mN7qWe8rT5yU2iO4pL6kJ1hG0',
  'sk_dE6fG8hJ2kL4mN9oP1qR3sT5uV7wX0yZ'
);

// Get countries
client.getCountries('en')
  .then(data => console.log('Countries:', data))
  .catch(err => console.error(err));

Request Access

Get started with SolvyAtlas API for free! Submit your request below, and you'll receive your Public Key and Secret Key credentials at no cost.

📋 What you'll receive:
• Public Key - Used to identify your application
• Secret Key - Used for secure authentication (keep confidential)
Free access to all API endpoints listed above
• Early adopter benefits for future updates

💡 Pricing: Currently free. Subscription fees may apply in the future, but early users will receive advance notice and special consideration.

Your access request has been submitted successfully. We'll review it and get back to you soon.