Ana içeriğe geç
Yılmaz Soft

API Entegrasyonu Rehberi: Ödeme, Kargo ve CRM Sistemleri

Web ve mobil uygulamalarda API entegrasyonu nasıl yapılır? İyzico, Aras Kargo, CRM sistemleri ve RESTful API best practices.

Yılmaz Soft
12 dk okuma
API entegrasyonu ve web servisleri

API Entegrasyonu Rehberi: Ödeme, Kargo ve CRM Sistemleri

Modern web ve mobil uygulamalarda API entegrasyonları vazgeçilmez. Ödeme almak, kargo göndermek veya CRM sistemi kullanmak için API entegrasyonları şart.

Bu kapsamlı rehberde, en çok kullanılan API’lerin nasıl entegre edileceğini, best practice’leri ve güvenlik önlemlerini öğreneceksiniz.

API Nedir?

API (Application Programming Interface), iki yazılımın birbirleriyle iletişim kurmasını sağlayan arayüzdür.

API Tipleri

  1. RESTful API (En yaygın)
  2. GraphQL (Modern)
  3. SOAP (Eski, bankacılık)
  4. WebSocket (Real-time)

REST API Temelleri

// GET - Veri çekme
fetch('https://api.example.com/users')
  .then((res) => res.json())
  .then((data) => console.log(data));

// POST - Veri gönderme
fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer YOUR_TOKEN',
  },
  body: JSON.stringify({
    name: 'Ahmet Yılmaz',
    email: '[email protected]',
  }),
})
  .then((res) => res.json())
  .then((data) => console.log(data));

HTTP Metodları:

MetodKullanımÖrnek
GETVeri okumaGET /api/users
POSTYeni veri oluşturmaPOST /api/users
PUTVeri güncelleme (tam)PUT /api/users/123
PATCHVeri güncelleme (kısmi)PATCH /api/users/123
DELETEVeri silmeDELETE /api/users/123

Ödeme API’leri

İyzico Entegrasyonu

İyzico, Türkiye’nin en popüler ödeme gateway’i.

1. Kurulum

npm install iyzipay

2. Konfigürasyon

// config/iyzico.js
const Iyzipay = require('iyzipay');

const iyzipay = new Iyzipay({
  apiKey: process.env.IYZICO_API_KEY,
  secretKey: process.env.IYZICO_SECRET_KEY,
  uri: process.env.NODE_ENV === 'production' ? 'https://api.iyzipay.com' : 'https://sandbox-api.iyzipay.com',
});

module.exports = iyzipay;

3. Ödeme Başlatma

// controllers/paymentController.js
const iyzipay = require('../config/iyzico');

exports.createPayment = async (req, res) => {
  const { price, paidPrice, basketId, buyer, shippingAddress, billingAddress, basketItems } = req.body;

  const request = {
    locale: Iyzipay.LOCALE.TR,
    conversationId: basketId,
    price: price.toString(),
    paidPrice: paidPrice.toString(),
    currency: Iyzipay.CURRENCY.TRY,
    installment: '1',
    basketId: basketId,
    paymentChannel: Iyzipay.PAYMENT_CHANNEL.WEB,
    paymentGroup: Iyzipay.PAYMENT_GROUP.PRODUCT,

    // Callback URLs
    callbackUrl: `${process.env.APP_URL}/payment/callback`,

    // Alıcı bilgileri
    buyer: {
      id: buyer.id,
      name: buyer.name,
      surname: buyer.surname,
      gsmNumber: buyer.phone,
      email: buyer.email,
      identityNumber: buyer.tcNo,
      registrationAddress: buyer.address,
      ip: req.ip,
      city: buyer.city,
      country: 'Turkey',
    },

    // Teslimat adresi
    shippingAddress: {
      contactName: shippingAddress.name,
      city: shippingAddress.city,
      country: 'Turkey',
      address: shippingAddress.fullAddress,
    },

    // Fatura adresi
    billingAddress: {
      contactName: billingAddress.name,
      city: billingAddress.city,
      country: 'Turkey',
      address: billingAddress.fullAddress,
    },

    // Sepet ürünleri
    basketItems: basketItems.map((item) => ({
      id: item.id,
      name: item.name,
      category1: item.category,
      itemType: Iyzipay.BASKET_ITEM_TYPE.PHYSICAL,
      price: item.price.toString(),
    })),
  };

  try {
    iyzipay.checkoutFormInitialize.create(request, (err, result) => {
      if (err) {
        console.error('İyzico Error:', err);
        return res.status(500).json({
          success: false,
          message: 'Ödeme başlatılamadı',
        });
      }

      // 3D Secure sayfasına yönlendir
      res.json({
        success: true,
        checkoutFormContent: result.checkoutFormContent,
        token: result.token,
      });
    });
  } catch (error) {
    console.error(error);
    res.status(500).json({ success: false });
  }
};

4. Ödeme Doğrulama (Callback)

// routes/payment.js
exports.paymentCallback = async (req, res) => {
  const { token } = req.body;

  const request = {
    locale: Iyzipay.LOCALE.TR,
    conversationId: Date.now().toString(),
    token: token,
  };

  iyzipay.checkoutForm.retrieve(request, async (err, result) => {
    if (err) {
      return res.redirect('/payment/failed');
    }

    if (result.status === 'success') {
      // Ödeme başarılı
      const paymentId = result.paymentId;
      const paidPrice = result.paidPrice;

      // Veritabanına kaydet
      await Order.updateOne(
        { basketId: result.basketId },
        {
          status: 'paid',
          paymentId: paymentId,
          paidAt: new Date(),
        }
      );

      // Email gönder
      await sendOrderConfirmationEmail(result.basketId);

      res.redirect('/payment/success');
    } else {
      res.redirect('/payment/failed');
    }
  });
};

PayTR Entegrasyonu

PayTR, düşük komisyon oranları ile popüler.

const crypto = require('crypto');
const axios = require('axios');

exports.createPayTRPayment = async (req, res) => {
  const { merchantId, merchantKey, merchantSalt, emailAddress, amount, orderId, basket } = req.body;

  // Hash oluştur
  const hashSTR = `${merchantId}${req.ip}${orderId}${emailAddress}${amount}${basket}1${merchantSalt}`;
  const paytrToken = crypto.createHmac('sha256', merchantKey).update(hashSTR).digest('base64');

  const params = {
    merchant_id: merchantId,
    user_ip: req.ip,
    merchant_oid: orderId,
    email: emailAddress,
    payment_amount: amount,
    paytr_token: paytrToken,
    user_basket: basket,
    debug_on: 0,
    no_installment: 0,
    max_installment: 12,
    user_name: 'Ahmet Yılmaz',
    user_address: 'İstanbul',
    user_phone: '05514917388',
    merchant_ok_url: `${process.env.APP_URL}/payment/success`,
    merchant_fail_url: `${process.env.APP_URL}/payment/failed`,
    timeout_limit: 30,
    currency: 'TL',
  };

  try {
    const response = await axios.post('https://www.paytr.com/odeme/api/get-token', new URLSearchParams(params));

    if (response.data.status === 'success') {
      res.json({
        success: true,
        token: response.data.token,
      });
    } else {
      res.status(400).json({
        success: false,
        message: response.data.reason,
      });
    }
  } catch (error) {
    console.error(error);
    res.status(500).json({ success: false });
  }
};

Kargo API’leri

Aras Kargo Entegrasyonu

// services/arasKargo.js
const axios = require('axios');
const xml2js = require('xml2js');

class ArasKargoService {
  constructor() {
    this.baseURL = 'https://customerservicestest.araskargo.com.tr/ArasCargoCustomerIntegrationService.asmx';
    this.username = process.env.ARAS_USERNAME;
    this.password = process.env.ARAS_PASSWORD;
    this.customerId = process.env.ARAS_CUSTOMER_ID;
  }

  async createShipment(shipmentData) {
    const {
      receiverName,
      receiverPhone,
      receiverAddress,
      receiverCity,
      receiverDistrict,
      weight, // KG
      paymentType, // 1: Alıcı Ödemeli, 2: Gönderici Ödemeli
    } = shipmentData;

    const xmlRequest = `<?xml version="1.0" encoding="utf-8"?>
      <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                     xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                     xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
          <ShippingOrderSave xmlns="http://tempuri.org/">
            <username>${this.username}</username>
            <password>${this.password}</password>
            <customerId>${this.customerId}</customerId>
            <order>
              <ReceiverName>${receiverName}</ReceiverName>
              <ReceiverPhone>${receiverPhone}</ReceiverPhone>
              <ReceiverAddress>${receiverAddress}</ReceiverAddress>
              <ReceiverCityName>${receiverCity}</ReceiverCityName>
              <ReceiverTownName>${receiverDistrict}</ReceiverTownName>
              <Weight>${weight}</Weight>
              <PaymentType>${paymentType}</PaymentType>
              <Description>E-Ticaret Siparişi</Description>
            </order>
          </ShippingOrderSave>
        </soap:Body>
      </soap:Envelope>`;

    try {
      const response = await axios.post(this.baseURL, xmlRequest, {
        headers: {
          'Content-Type': 'text/xml; charset=utf-8',
          SOAPAction: 'http://tempuri.org/ShippingOrderSave',
        },
      });

      const parser = new xml2js.Parser();
      const result = await parser.parseStringPromise(response.data);

      return {
        success: true,
        trackingNumber:
          result['soap:Envelope']['soap:Body'][0]['ShippingOrderSaveResponse'][0]['ShippingOrderSaveResult'][0][
            'TrackingNumber'
          ][0],
      };
    } catch (error) {
      console.error('Aras Kargo Error:', error);
      return { success: false, error: error.message };
    }
  }

  async trackShipment(trackingNumber) {
    const xmlRequest = `<?xml version="1.0" encoding="utf-8"?>
      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
          <QueryByReferenceNumber xmlns="http://tempuri.org/">
            <username>${this.username}</username>
            <password>${this.password}</password>
            <referenceNumber>${trackingNumber}</referenceNumber>
          </QueryByReferenceNumber>
        </soap:Body>
      </soap:Envelope>`;

    try {
      const response = await axios.post(this.baseURL, xmlRequest, {
        headers: {
          'Content-Type': 'text/xml; charset=utf-8',
        },
      });

      const parser = new xml2js.Parser();
      const result = await parser.parseStringPromise(response.data);

      return {
        success: true,
        status: result.status,
        currentLocation: result.location,
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }
}

module.exports = new ArasKargoService();

Yurtiçi Kargo API

// services/yurticiKargo.js
class YurticiKargoService {
  constructor() {
    this.apiKey = process.env.YURTICI_API_KEY;
    this.baseURL = 'https://api.yurticikargo.com/api/v1';
  }

  async createShipment(data) {
    const shipmentRequest = {
      sender: {
        name: data.senderName,
        phone: data.senderPhone,
        address: data.senderAddress,
        city: data.senderCity,
        district: data.senderDistrict,
      },
      receiver: {
        name: data.receiverName,
        phone: data.receiverPhone,
        address: data.receiverAddress,
        city: data.receiverCity,
        district: data.receiverDistrict,
      },
      package: {
        weight: data.weight,
        desi: this.calculateDesi(data.dimensions),
        value: data.packageValue,
        description: data.description,
      },
      paymentType: data.paymentType, // 'SENDER' or 'RECEIVER'
    };

    try {
      const response = await axios.post(`${this.baseURL}/shipments`, shipmentRequest, {
        headers: {
          Authorization: `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
        },
      });

      return {
        success: true,
        trackingNumber: response.data.trackingNumber,
        shipmentId: response.data.shipmentId,
      };
    } catch (error) {
      return {
        success: false,
        error: error.response?.data?.message || error.message,
      };
    }
  }

  calculateDesi(dimensions) {
    // Desi = (En x Boy x Yükseklik) / 3000
    const { width, height, length } = dimensions;
    return (width * height * length) / 3000;
  }
}

module.exports = new YurticiKargoService();

CRM Entegrasyonları

HubSpot CRM Entegrasyonu

// services/hubspot.js
const axios = require('axios');

class HubSpotService {
  constructor() {
    this.apiKey = process.env.HUBSPOT_API_KEY;
    this.baseURL = 'https://api.hubapi.com';
  }

  // İletişim (Contact) oluştur
  async createContact(contactData) {
    const { email, firstName, lastName, phone, company } = contactData;

    try {
      const response = await axios.post(
        `${this.baseURL}/crm/v3/objects/contacts`,
        {
          properties: {
            email: email,
            firstname: firstName,
            lastname: lastName,
            phone: phone,
            company: company,
          },
        },
        {
          headers: {
            Authorization: `Bearer ${this.apiKey}`,
            'Content-Type': 'application/json',
          },
        }
      );

      return {
        success: true,
        contactId: response.data.id,
      };
    } catch (error) {
      console.error('HubSpot Error:', error.response?.data);
      return { success: false, error: error.message };
    }
  }

  // Deal (Fırsat) oluştur
  async createDeal(dealData) {
    const { dealName, amount, stage, contactId } = dealData;

    try {
      const response = await axios.post(
        `${this.baseURL}/crm/v3/objects/deals`,
        {
          properties: {
            dealname: dealName,
            amount: amount,
            dealstage: stage,
            pipeline: 'default',
          },
          associations: [
            {
              to: { id: contactId },
              types: [
                {
                  associationCategory: 'HUBSPOT_DEFINED',
                  associationTypeId: 3, // Contact to Deal
                },
              ],
            },
          ],
        },
        {
          headers: {
            Authorization: `Bearer ${this.apiKey}`,
            'Content-Type': 'application/json',
          },
        }
      );

      return {
        success: true,
        dealId: response.data.id,
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }

  // Not ekle
  async addNote(contactId, noteContent) {
    try {
      await axios.post(
        `${this.baseURL}/crm/v3/objects/notes`,
        {
          properties: {
            hs_note_body: noteContent,
            hs_timestamp: Date.now(),
          },
          associations: [
            {
              to: { id: contactId },
              types: [
                {
                  associationCategory: 'HUBSPOT_DEFINED',
                  associationTypeId: 10, // Note to Contact
                },
              ],
            },
          ],
        },
        {
          headers: {
            Authorization: `Bearer ${this.apiKey}`,
            'Content-Type': 'application/json',
          },
        }
      );

      return { success: true };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }
}

module.exports = new HubSpotService();

Salesforce Entegrasyonu

// services/salesforce.js
const jsforce = require('jsforce');

class SalesforceService {
  constructor() {
    this.conn = new jsforce.Connection({
      loginUrl: process.env.SALESFORCE_LOGIN_URL,
    });
  }

  async connect() {
    try {
      await this.conn.login(
        process.env.SALESFORCE_USERNAME,
        process.env.SALESFORCE_PASSWORD + process.env.SALESFORCE_TOKEN
      );
      return { success: true };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }

  async createLead(leadData) {
    const { firstName, lastName, company, email, phone, status } = leadData;

    try {
      const result = await this.conn.sobject('Lead').create({
        FirstName: firstName,
        LastName: lastName,
        Company: company,
        Email: email,
        Phone: phone,
        Status: status || 'Open',
        LeadSource: 'Website',
      });

      return {
        success: result.success,
        leadId: result.id,
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }

  async convertLeadToOpportunity(leadId) {
    try {
      const result = await this.conn.sobject('Lead').convertLead({
        leadId: leadId,
        convertedStatus: 'Qualified',
      });

      return {
        success: true,
        accountId: result.accountId,
        contactId: result.contactId,
        opportunityId: result.opportunityId,
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }
}

module.exports = new SalesforceService();

RESTful API Best Practices

1. Versiyonlama

// ✅ URL versiyonlama
app.use('/api/v1', routesV1);
app.use('/api/v2', routesV2);

// Örnek:
// GET /api/v1/users
// GET /api/v2/users (yeni özellikler)

2. HTTP Status Kodları

// Success
200 OK              // GET, PUT, PATCH başarılı
201 Created         // POST ile yeni kayıt oluşturuldu
204 No Content      // DELETE başarılı

// Client Errors
400 Bad Request     // Geçersiz istek
401 Unauthorized    // Authentication gerekli
403 Forbidden       // Yetki yok
404 Not Found       // Kaynak bulunamadı
422 Unprocessable   // Validasyon hatası

// Server Errors
500 Internal Error  // Sunucu hatası
503 Service Unavailable // Servis down

3. Endpoint Naming Convention

// ✅ İyi Örnekler
GET    /api/v1/users              // Tüm kullanıcılar
GET    /api/v1/users/123          // Belirli kullanıcı
POST   /api/v1/users              // Yeni kullanıcı
PUT    /api/v1/users/123          // Kullanıcı güncelle (tüm alan)
PATCH  /api/v1/users/123          // Kullanıcı güncelle (kısmi)
DELETE /api/v1/users/123          // Kullanıcı sil

// İlişkili kaynaklar
GET    /api/v1/users/123/orders   // Kullanıcının siparişleri
POST   /api/v1/users/123/orders   // Yeni sipariş

// ❌ Kötü Örnekler
GET /api/getUsers
POST /api/createUser
GET /api/user-detail?id=123

4. Pagination

// controllers/userController.js
exports.getUsers = async (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 20;
  const skip = (page - 1) * limit;

  try {
    const users = await User.find().limit(limit).skip(skip).sort({ createdAt: -1 });

    const total = await User.countDocuments();

    res.json({
      success: true,
      data: users,
      pagination: {
        page: page,
        limit: limit,
        total: total,
        totalPages: Math.ceil(total / limit),
        hasNextPage: page < Math.ceil(total / limit),
        hasPrevPage: page > 1,
      },
    });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
};

// Kullanım:
// GET /api/v1/users?page=2&limit=50

5. Filtering ve Sorting

exports.getProducts = async (req, res) => {
  const { category, minPrice, maxPrice, sort } = req.query;

  // Filtreler
  let filter = {};
  if (category) filter.category = category;
  if (minPrice || maxPrice) {
    filter.price = {};
    if (minPrice) filter.price.$gte = parseFloat(minPrice);
    if (maxPrice) filter.price.$lte = parseFloat(maxPrice);
  }

  // Sıralama
  let sortOption = {};
  if (sort) {
    const sortFields = sort.split(',');
    sortFields.forEach((field) => {
      if (field.startsWith('-')) {
        sortOption[field.substring(1)] = -1; // Descending
      } else {
        sortOption[field] = 1; // Ascending
      }
    });
  }

  try {
    const products = await Product.find(filter).sort(sortOption);
    res.json({ success: true, data: products });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
};

// Kullanım:
// GET /api/v1/products?category=electronics&minPrice=100&maxPrice=1000&sort=-price,name

API Güvenliği

1. JWT Authentication

// middleware/auth.js
const jwt = require('jsonwebtoken');

exports.protect = async (req, res, next) => {
  let token;

  if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
    token = req.headers.authorization.split(' ')[1];
  }

  if (!token) {
    return res.status(401).json({
      success: false,
      message: 'Bu işlem için giriş yapmalısınız',
    });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = await User.findById(decoded.id);
    next();
  } catch (error) {
    return res.status(401).json({
      success: false,
      message: 'Geçersiz token',
    });
  }
};

// Kullanım:
// app.get('/api/v1/profile', protect, getUserProfile);

2. API Key Authentication

// middleware/apiKey.js
exports.validateApiKey = (req, res, next) => {
  const apiKey = req.headers['x-api-key'];

  if (!apiKey) {
    return res.status(401).json({
      success: false,
      message: 'API key gerekli'
    });
  }

  // Veritabanından kontrol et
  const validApiKey = await ApiKey.findOne({ key: apiKey, isActive: true });

  if (!validApiKey) {
    return res.status(403).json({
      success: false,
      message: 'Geçersiz API key'
    });
  }

  req.apiKey = validApiKey;
  next();
};

3. Rate Limiting

const rateLimit = require('express-rate-limit');

// Genel rate limiter
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 dakika
  max: 100, // Max 100 istek
  message: 'Çok fazla istek gönderdiniz, lütfen daha sonra tekrar deneyin',
});

app.use('/api/', limiter);

// Login için daha sıkı rate limit
const loginLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 saat
  max: 5, // Max 5 deneme
  message: 'Çok fazla giriş denemesi, 1 saat sonra tekrar deneyin',
});

app.post('/api/v1/auth/login', loginLimiter, login);

Webhooks

Webhook Nedir?

Webhook, bir olayı gerçek zamanlı olarak diğer sistem ve bildirir.

Webhook İmplementasyonu

// models/Webhook.js
const WebhookSchema = new mongoose.Schema({
  url: { type: String, required: true },
  events: [{ type: String }], // ['order.created', 'order.updated']
  secret: { type: String },
  isActive: { type: Boolean, default: true },
});

// services/webhook.js
const axios = require('axios');
const crypto = require('crypto');

class WebhookService {
  async trigger(event, data) {
    // Bu event'i dinleyen webhook'ları bul
    const webhooks = await Webhook.find({
      events: event,
      isActive: true,
    });

    for (const webhook of webhooks) {
      await this.sendWebhook(webhook, event, data);
    }
  }

  async sendWebhook(webhook, event, data) {
    const payload = {
      event: event,
      data: data,
      timestamp: new Date().toISOString(),
    };

    // HMAC imza oluştur
    const signature = crypto.createHmac('sha256', webhook.secret).update(JSON.stringify(payload)).digest('hex');

    try {
      await axios.post(webhook.url, payload, {
        headers: {
          'Content-Type': 'application/json',
          'X-Webhook-Signature': signature,
        },
        timeout: 5000,
      });

      console.log(`Webhook sent to ${webhook.url}`);
    } catch (error) {
      console.error(`Webhook failed: ${webhook.url}`, error.message);
      // Retry logic eklenebilir
    }
  }
}

// Kullanım:
// Sipariş oluşturulduğunda
await webhookService.trigger('order.created', {
  orderId: order.id,
  amount: order.amount,
  status: 'pending',
});

Webhook Güvenliği

// Webhook signature doğrulama
exports.validateWebhookSignature = (req, res, next) => {
  const signature = req.headers['x-webhook-signature'];
  const secret = process.env.WEBHOOK_SECRET;

  const expectedSignature = crypto.createHmac('sha256', secret).update(JSON.stringify(req.body)).digest('hex');

  if (signature !== expectedSignature) {
    return res.status(403).json({
      success: false,
      message: 'Geçersiz webhook signature',
    });
  }

  next();
};

Sonuç

API entegrasyonları modern uygulamaların olmazsa olmazıdır. Bu rehberde öğrendikleriniz:

✅ Ödeme sistemleri (İyzico, PayTR) ✅ Kargo entegrasyonları (Aras, Yurtiçi) ✅ CRM sistemleri (HubSpot, Salesforce) ✅ RESTful API best practices ✅ Güvenlik ve rate limiting ✅ Webhook implementasyonu


Yılmaz Soft API Entegrasyon Hizmetleri

Projeniz için API Entegrasyonları

✅ Ödeme gateway’leri ✅ Kargo firması entegrasyonları ✅ CRM ve ERP sistemleri ✅ Özel API geliştirme ✅ Webhook ve real-time sistemler

Ücretsiz Danışmanlık →


Son güncelleme: 22 Ocak 2025 Yazar: Yılmaz Soft Backend Ekibi

YS

Yılmaz Soft

Yılmaz Soft olarak web geliştirme, mobil uygulama ve dijital pazarlama alanlarında profesyonel çözümler sunuyoruz. Müşterilerimizin dijital dönüşüm süreçlerinde yanlarında olmaktan gurur duyuyoruz.

İletişime Geçin

İlgili Yazılar