Dropshipping suppliers integration with online store

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1 servicesAll 2065 services
Dropshipping suppliers integration with online store
Complex
~5 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Integration of Dropshipping Suppliers with E-commerce Store

Supplier integration is a technical task whose complexity is determined not by the number of products, but by the data format and quality on the supplier's side. REST API with documentation is the best case. A price list in Excel without articles and with Cyrillic in headers is the worst. Both happen.

Types of Integrations

REST API — supplier provides endpoints to get catalog, stock, prices, and receive orders. Most convenient format. Requires API key or OAuth authorization.

SOAP/XML-RPC — outdated, but still common format among large distributors and manufacturers. Requires WSDL parsing and client code generation.

FTP/SFTP + CSV/XML — supplier uploads file to server on schedule. Store retrieves and processes it. Cannot check stock in real time.

Email with Price List — extreme case. Parser attachments + OCR for PDF.

EDI (EDIFACT/X12) — used by major FMCG and pharmaceutical distributors.

Connector Factory

class SupplierConnectorFactory
{
    public static function make(Supplier $supplier): SupplierConnectorInterface
    {
        return match($supplier->integration_type) {
            'rest_api' => new RestApiConnector($supplier, app(HttpClient::class)),
            'soap'     => new SoapConnector($supplier),
            'ftp_csv'  => new FtpCsvConnector($supplier, app(SftpFilesystem::class)),
            'ftp_xml'  => new FtpXmlConnector($supplier, app(SftpFilesystem::class)),
            default    => throw new UnsupportedIntegrationTypeException($supplier->integration_type),
        };
    }
}

FTP + CSV Connector

Some suppliers export price list to FTP once a day. Connector retrieves file, parses and normalizes data:

class FtpCsvConnector implements SupplierConnectorInterface
{
    public function getProducts(int $page = 1, int $perPage = 100): array
    {
        $localPath = $this->downloadFile();
        $products  = [];

        $handle = fopen($localPath, 'r');
        $headers = fgetcsv($handle, 0, ';');
        $headers = array_map('trim', $headers); // remove BOM and spaces

        // Map headers (suppliers call fields differently)
        $mapping = $this->resolveHeaderMapping($headers);

        while (($row = fgetcsv($handle, 0, ';')) !== false) {
            $normalized = $this->normalizeRow(
                array_combine($headers, $row),
                $mapping
            );

            if ($normalized) {
                $products[] = $normalized;
            }
        }

        fclose($handle);
        @unlink($localPath);

        return array_slice($products, ($page - 1) * $perPage, $perPage);
    }

    private function resolveHeaderMapping(array $headers): array
    {
        // Different suppliers use different names for the same fields
        $aliases = [
            'sku'   => ['артикул', 'sku', 'код', 'article', 'item_no'],
            'name'  => ['наименование', 'название', 'name', 'title', 'товар'],
            'price' => ['цена', 'price', 'стоимость', 'цена_розница'],
            'stock' => ['остаток', 'количество', 'stock', 'qty', 'available'],
        ];

        $mapping = [];
        foreach ($headers as $header) {
            $lower = mb_strtolower(trim($header));
            foreach ($aliases as $field => $list) {
                if (in_array($lower, $list)) {
                    $mapping[$field] = $header;
                    break;
                }
            }
        }

        return $mapping;
    }

    private function downloadFile(): string
    {
        $remotePath = $this->supplier->credentials['ftp_path'];
        $localPath  = sys_get_temp_dir() . '/' . uniqid('supplier_') . '.csv';

        $this->sftp->download($remotePath, $localPath);

        return $localPath;
    }
}

SOAP Connector

class SoapConnector implements SupplierConnectorInterface
{
    private \SoapClient $client;

    public function __construct(private Supplier $supplier)
    {
        $this->client = new \SoapClient(
            $supplier->credentials['wsdl_url'],
            ['login' => $supplier->credentials['login'],
             'password' => $supplier->credentials['password'],
             'cache_wsdl' => WSDL_CACHE_DISK,
             'trace' => false,
            ]
        );
    }

    public function getProducts(int $page = 1, int $perPage = 100): array
    {
        $result = $this->client->GetProductList([
            'SessionID' => $this->getSession(),
            'PageNum'   => $page,
            'PageSize'  => $perPage,
        ]);

        return collect($result->ProductList->Product ?? [])
            ->map(fn($item) => new SupplierProductDTO(
                sku:   $item->Article,
                name:  $item->Name,
                price: (float) $item->Price,
                stock: (int) $item->Qty,
            ))
            ->toArray();
    }
}

Data Normalization from Supplier

Data from different suppliers inevitably diverges in structure. Normalization is performed before saving to dropship_products:

class SupplierProductNormalizer
{
    public function normalize(array $raw, Supplier $supplier): ?SupplierProductDTO
    {
        // Clean SKU from special characters
        $sku = preg_replace('/[^\w\-]/', '', $raw['sku'] ?? '');
        if (!$sku) return null;

        // Normalize price: remove spaces, replace comma with dot
        $price = (float) str_replace([' ', ','], ['', '.'], $raw['price'] ?? '0');
        if ($price <= 0) return null;

        // Normalize stock: "in stock" → 999, "no" → 0
        $stock = $this->parseStock($raw['stock'] ?? '0');

        return new SupplierProductDTO(
            sku:   $sku,
            name:  mb_convert_encoding(trim($raw['name'] ?? ''), 'UTF-8', 'auto'),
            price: $price,
            stock: $stock,
        );
    }

    private function parseStock(mixed $value): int
    {
        if (is_numeric($value)) return (int) $value;

        $lower = mb_strtolower((string) $value);
        return match(true) {
            str_contains($lower, 'наличи') => 999,
            str_contains($lower, 'нет')    => 0,
            str_contains($lower, 'ожида')  => 0,
            default => 0,
        };
    }
}

Connection Error Handling

Suppliers are unreliable: APIs go down for maintenance, FTP changes directory structure, CSV arrives with different encoding. All connectors are wrapped in Retry policy through Laravel Queue with exponential backoff:

class SyncSupplierJob implements ShouldQueue
{
    public $tries = 3;
    public $backoff = [60, 300, 900]; // 1 min, 5 min, 15 min

    public function failed(Throwable $e): void
    {
        Notification::route('mail', config('suppliers.admin_email'))
            ->notify(new SupplierSyncFailedNotification($this->supplier, $e));
    }
}

Integration Timeline

Integration Type Timeline
REST API with documentation 2–3 days
SOAP with WSDL 3–4 days
FTP + CSV (standard format) 2–3 days
FTP + CSV (non-standard format) 3–5 days
Multiple suppliers (each next one) 1–3 days