# antistress-store/cdek-sdk-v2 ## Introduction `antistress-store/cdek-sdk-v2` is a full-featured PHP SDK for integrating with the CDEK (СДЭК) delivery service API v2.0, developed by Antistress.Store®. It provides a clean, object-oriented interface for all major CDEK operations: order creation and management, tariff calculation, delivery point lookup, courier intake scheduling, print form generation (invoices and barcodes), webhook subscriptions, and financial reporting. The SDK supports both the test environment (`api.edu.cdek.ru/v2/`) and the production environment (`api.cdek.ru/v2/`), with automatic OAuth2 token management handled transparently by the client. The SDK requires PHP >= 7.2.5 with the `ext-json` extension and `guzzlehttp/guzzle >= 7.3`. All request entities follow a fluent builder pattern via chainable setter methods, and every setter returns `$this` to allow method chaining. Responses are typed value-objects with dedicated getter methods matching the CDEK API field names in camelCase. Error handling surfaces as typed exceptions (`CdekV2AuthException`, `CdekV2RequestException`) so application code can catch specific failure categories. --- ## Installation Install via Composer: ```bash composer require antistress-store/cdek-sdk-v2 ``` --- ## `CdekClientV2::__construct()` — Client Initialization Creates the HTTP client for CDEK API v2.0. Pass `'TEST'` as the first argument to use the sandbox environment with pre-configured credentials. Pass your production `$account` and `$secure` credentials for the live environment. An optional `$timeout` (float, seconds) controls the Guzzle connection timeout. ```php getRegions(); } catch (CdekV2AuthException $e) { echo 'Auth failed: ' . $e->getMessage(); } catch (CdekV2RequestException $e) { echo 'API error: ' . $e->getMessage(); } ``` --- ## `CdekClientV2::setMemory()` — Token Caching Provides a token persistence mechanism to avoid re-authorizing on every request. Pass the previously saved auth array (keyed `cdekAuth`) and a callback function that receives the updated array to persist it (e.g., to a session or database). ```php ['expires_in' => ..., 'access_token' => ..., 'account_type' => ...]] $_SESSION['cdekAuth'] = $memory['cdekAuth']; // or store in DB/cache return true; }; // Load previously saved auth data (null if not yet saved) $savedAuth = $_SESSION['cdekAuth'] ?? null; $client->setMemory($savedAuth ? ['cdekAuth' => $savedAuth] : null, $saveCallback); // The SDK will now reuse the cached token if still valid, or re-authorize and // persist the new token via $saveCallback automatically. $deliveryPoints = $client->getDeliveryPoints(); ``` --- ## `CdekClientV2::calculateTariff()` — Calculate Single Tariff Cost Calculates delivery cost and time for a specific tariff code. The `Tariff` object must have `tariff_code` set; otherwise an `\InvalidArgumentException` is thrown. Returns a `TariffResponse` with price breakdown. ```php setTariffCode(136) // Required: tariff code ->setCityCodes(172, 44) // Express method: sender city code, recipient city code ->setPackageWeight(500) // Weight in grams ->addServices(['INSURANCE' => 10000]); // Insurance for 10000 RUB try { $response = $client->calculateTariff($tariff); echo $response->getDeliverySum(); // Base delivery cost (float) echo $response->getTotalSum(); // Total including services (float) echo $response->getCurrency(); // 'RUB' echo $response->getPeriodMin(); // Min delivery days (int) echo $response->getPeriodMax(); // Max delivery days (int) echo $response->getCalendarMin(); // Min calendar days (int) echo $response->getCalendarMax(); // Max calendar days (int) echo $response->getWeightCalc(); // Calculated weight in grams (int) foreach ($response->getServices() as $service) { // AntistressStore\CdekSDK2\Entity\Responses\ServicesResponse echo $service->getCode(); // 'INSURANCE' echo $service->getSum(); // Service base amount echo $service->getTotalSum(); // Service total with VAT echo $service->getDiscountPercent(); // Discount percent echo $service->getVatRate(); echo $service->getVatSum(); } } catch (\InvalidArgumentException $e) { echo 'Missing tariff_code: ' . $e->getMessage(); } ``` --- ## `CdekClientV2::calculateTariffList()` — Calculate All Available Tariffs Calculates cost and delivery time across all available tariffs for a given route and package. No `tariff_code` is required. Returns `TariffListResponse[]`. ```php setCityCodes(172, 44) ->setPackageWeight(500) ->addServices(['PART_DELIV']); // Partial delivery (no parameter value) $tariffList = $client->calculateTariffList($tariff); foreach ($tariffList as $result) { // AntistressStore\CdekSDK2\Entity\Responses\TariffListResponse echo $result->getTariffCode(); // Tariff code (int) echo $result->getTariffName(); // Tariff name string echo $result->getTariffDescription(); // Description echo $result->getDeliverySum(); // Delivery cost (float) echo $result->getDeliveryMode(); // Delivery mode code (int) echo $result->getPeriodMin(); // Min working days echo $result->getPeriodMax(); // Max working days echo $result->getCalendarMin(); echo $result->getCalendarMax(); } ``` --- ## `CdekClientV2::getAvailableTariffs()` — List All Contract Tariffs Returns the full list of tariffs available under the authenticated account's contract. No parameters required. Returns `AvailableTariffsResponse[]`. ```php getAvailableTariffs(); foreach ($tariffs as $tariff) { // AntistressStore\CdekSDK2\Entity\Responses\AvailableTariffsResponse echo $tariff->getTariffName(); echo $tariff->getWeightMin(); // Min weight in grams echo $tariff->getWeightMax(); // Max weight in grams echo $tariff->getLengthMin(); echo $tariff->getLengthMax(); echo $tariff->getWidthMin(); echo $tariff->getWidthMax(); echo $tariff->getHeightMin(); echo $tariff->getHeightMax(); foreach ($tariff->getDeliveryModes() as $mode) { echo $mode->getMode(); // Delivery mode code } foreach ($tariff->getOrderTypes() as $type) { echo $type; // Order type } } ``` --- ## `CdekClientV2::getDeliveryPoints()` — Search CDEK Pickup Points (PVZ) Returns a filtered list of CDEK offices/pickup points. Accepts an optional `DeliveryPoints` filter object. Returns `DeliveryPointsResponse[]`. ```php setType(DeliveryPoints::TYPE_PVZ) // 'PVZ', 'ALL', or 'POSTOMAT' ->setCityCode(44) // Moscow city code ->setLanguage(DeliveryPoints::LANGUAGE_RUSSIAN) ->setCashless(true) ->setCodAllowed(true); $points = $client->getDeliveryPoints($filter); foreach ($points as $point) { // AntistressStore\CdekSDK2\Entity\Responses\DeliveryPointsResponse echo $point->getCode(); // PVZ code string echo $point->getName(); // Office name echo $point->getLocation()->getAddress(); // Street address echo $point->getLocation()->getPostalCode(); // Postal code echo $point->getWorkTime(); // Work hours string echo $point->getNote(); // Notes echo $point->getWeightMax(); // Max package weight echo $point->getHaveCashless() ? 'cashless' : ''; echo $point->getHaveCash() ? 'cash' : ''; echo $point->getAllowedCod() ? 'cod' : ''; echo $point->getIsDressingRoom() ? 'fitting' : ''; echo $point->getIsHandout() ? 'handout' : ''; echo $point->getIsReception() ? 'reception' : ''; foreach ($point->getWorkTimeList() as $wt) { echo $wt->getDay() . ': ' . $wt->getTime(); } } ``` --- ## `CdekClientV2::getRegions()` — Get Regions List Returns a paginated list of regions filterable by country codes, KLADR/FIAS codes, and language. Accepts an optional `Location` filter object. Returns `RegionsResponse[]`. ```php setCountryCodes('RU') ->setLang('rus') ->setSize(50) ->setPage(0); $regions = $client->getRegions($filter); foreach ($regions as $region) { // AntistressStore\CdekSDK2\Entity\Responses\RegionsResponse echo $region->getRegion(); // Region name echo $region->getRegionCode(); // CDEK region code echo $region->getCountryCode(); // ISO country code echo $region->getKladrRegionCode(); // KLADR code echo $region->getFiasRegionGuid(); // FIAS GUID } ``` --- ## `CdekClientV2::getCities()` — Get Cities List Returns a list of cities with filtering by country, region, postal code, and text search. Accepts an optional `Location` filter. Returns `CitiesResponse[]`. ```php setCountryCodes('RU,TR') ->setCity('Москва') ->setSize(20) ->setPage(0); $cities = $client->getCities($filter); foreach ($cities as $city) { // AntistressStore\CdekSDK2\Entity\Responses\CitiesResponse echo $city->getCode(); // CDEK city code (use for orders/tariffs) echo $city->getCity(); // City name echo $city->getCountryCode(); // ISO country code echo $city->getRegion(); // Region name echo $city->getPostalCode(); // Postal code echo $city->getKladrCode(); // KLADR code echo $city->getTimeZone(); // Timezone string echo $city->getPaymentLimit(); // COD limit } ``` --- ## `CdekClientV2::createOrder()` — Create Delivery Order Creates a new order in the CDEK system. Builds a fully configured `Order` object with sender, recipient, packages, items, and services, then submits it. Returns `EntityResponse` containing the new order UUID. ```php setNumber('ORDER-001') ->setType(1) // 1 = online shop, 2 = delivery ->setComment('Payment by card') ->setTariffCode(136) ->setDeliveryRecipientCost(150.0) // Delivery fee charged to recipient ->setPrint('waybill'); // Request waybill PDF on creation // Seller details (marketplace/dropship scenario) $seller = (new Seller()) ->setName('My Store Ltd.') ->setInn('7777777777') ->setPhone('+74951234567') ->setOwnershipForm(63); $order->setSeller($seller); // Recipient $recipient = (new Contact()) ->setName('Ivan Petrov') ->setEmail('ivan@example.com') ->setPhones('+79161234567'); $order->setRecipient($recipient); // Addresses (door-to-door tariff) $order->setShipmentAddress('ul. Lenina, d. 1') ->setShipmentCityCode(1204) // Sender city CDEK code ->setRecipientAddress('ul. Mira, d. 5, kv. 10') ->setRecipientCityCode(44); // Recipient city CDEK code // Package with items $items = []; $items[] = (new Item()) ->setName('Wireless Headphones') ->setWareKey('SKU-12345') ->setPayment(1500.00) // COD amount per unit ->setCost(1500.00) // Declared value per unit ->setWeight(300) // Grams per unit ->setAmount(2); // Quantity $package = (new Package()) ->setNumber('PKG-1') ->setWeight(700) // Total grams ->setLength(20) // cm ->setWidth(15) // cm ->setHeight(10) // cm ->setItems($items); $order->setPackages($package); // Additional services if (count($items) < 1) { $order->addServices(['PART_DELIV']); // Partial delivery if needed } try { $response = $client->createOrder($order); $uuid = $response->getEntityUuid(); // Store this UUID for future operations echo 'Order created: ' . $uuid; $reqState = $response->getRequests()[0]->getState(); // 'ACCEPTED' or 'INVALID' } catch (CdekV2RequestException $e) { echo 'Error ' . $e->getCode() . ': ' . $e->getMessage(); } ``` --- ## `CdekClientV2::getOrderInfoByUuid()` / `getOrderInfoByCdekNumber()` / `getOrderInfoByImNumber()` — Get Order Info Retrieves full order details by CDEK UUID, CDEK waybill number, or the store's own order number. Returns `OrderResponse`. ```php getOrderInfoByUuid('b5c67e09-14b9-4bf4-b4ae-97c82c5b8a91'); // Retrieve by CDEK waybill number $order = $client->getOrderInfoByCdekNumber('1105661402'); // Retrieve by store order number $order = $client->getOrderInfoByImNumber('ORDER-001'); // --- Inspect the OrderResponse --- echo $order->getUuid(); echo $order->getCdekNumber(); // CDEK waybill number echo $order->getNumber(); // Store order number echo $order->getTariffCode(); echo $order->getType(); echo $order->getComment(); echo $order->getDeliveryMode(); // Recipient echo $order->getRecipient()->getName(); // Locations echo $order->getToLocation()->getCity(); echo $order->getToLocation()->getAddress(); // Status history foreach ($order->getStatuses() as $status) { echo $status->getCode() . ' at ' . $status->getDateTime(); } // Related documents (waybills, barcodes, linked orders) $relatedEntities = $order->getRelatedEntities(); // Get UUID of the latest waybill for this order $waybillUuid = $order->getLastRelated('waybill'); // Packages and items foreach ($order->getPackages() as $package) { echo $package->getNumber(); echo $package->getWeight(); foreach ($package->getItems() as $item) { echo $item->getName() . ' x' . $item->getAmount(); } } // Delivery details $dd = $order->getDeliveryDetail(); if ($dd) { echo $dd->getDeliveryDate(); echo $dd->getRecipientsSum(); // Collected COD amount } ``` --- ## `CdekClientV2::updateOrder()` — Update Order Modifies an existing order before it is handed off for delivery. Build an `Order` with the UUID of the order to update plus only the fields you want to change. Returns `EntityResponse`. ```php withOrderUuid('b5c67e09-14b9-4bf4-b4ae-97c82c5b8a91') // Target order ->setComment('Updated comment') ->setRecipientAddress('ul. Novaya, d. 7') ->setRecipientCityCode(44); $response = $client->updateOrder($order); echo $response->getEntityUuid(); // UUID of the updated order ``` --- ## `CdekClientV2::deleteOrder()` — Delete Order Permanently deletes an order by UUID. Returns `false` on success. Throws `CdekV2RequestException` on failure. ```php deleteOrder('b5c67e09-14b9-4bf4-b4ae-97c82c5b8a91'); // $result === false means deletion succeeded if ($result === false) { echo 'Order deleted successfully.'; } } catch (CdekV2RequestException $e) { echo 'Could not delete: ' . $e->getMessage(); } ``` --- ## `CdekClientV2::cancelOrder()` — Cancel Order (Register Refusal) Cancels (registers a refusal for) an order that has not yet reached the status "Delivered" or "Not Delivered". Returns `EntityResponse`. ```php cancelOrder('b5c67e09-14b9-4bf4-b4ae-97c82c5b8a91'); echo $response->getEntityUuid(); echo $response->getRequests()[0]->getState(); // Expected: 'ACCEPTED' ``` --- ## `CdekClientV2::setInvoice()` / `getInvoice()` / `getInvoicePdf()` — Order Waybill (Invoice) Generates a waybill (receipt) PDF for one or more orders. `setInvoice()` requests creation and returns `EntityResponse` with the invoice UUID. `getInvoice()` checks generation status. `getInvoicePdf()` returns the binary PDF stream. ```php setInvoice(Invoice::withOrdersUuid($orderUuid)); $invoiceUuid = $invoiceEntity->getEntityUuid(); // Method 2: Request waybill by CDEK number $invoiceEntity = $client->setInvoice(Invoice::withCdekNumbers('1105661402')); $invoiceUuid = $invoiceEntity->getEntityUuid(); // Method 3: Retrieve UUID from a related entity on the order $orderInfo = $client->getOrderInfoByUuid($orderUuid); $invoiceUuid = $orderInfo->getLastRelated('waybill'); // Check generation status (may take a few seconds) $invoiceInfo = $client->getInvoice($invoiceUuid); echo $invoiceInfo->getUrl(); // Download URL when ready echo $invoiceInfo->getCopyCount(); foreach ($invoiceInfo->getStatuses() as $status) { echo $status->getCode(); // 'ACCEPTED', 'READY', etc. } // Download the PDF (Psr\Http\Message\StreamInterface) $pdfStream = $client->getInvoicePdf($invoiceUuid); file_put_contents('/tmp/waybill.pdf', $pdfStream->getContents()); ``` --- ## `CdekClientV2::setBarcode()` / `getBarcode()` / `getBarcodePdf()` — Package Barcode Generates a barcode label PDF for a package/place. Works the same pattern as waybills but targets the `print/barcodes` endpoint. ```php setBarcode( (new Barcode())->withOrdersUuid($orderUuid) ); $barcodeUuid = $barcodeEntity->getEntityUuid(); // Check status $barcodeInfo = $client->getBarcode($barcodeUuid); echo $barcodeInfo->getUrl(); // Download PDF $pdfStream = $client->getBarcodePdf($barcodeUuid); file_put_contents('/tmp/barcode.pdf', $pdfStream->getContents()); ``` --- ## `CdekClientV2::createAgreement()` / `getAgreement()` — Delivery Agreement (Schedule Delivery) Registers a delivery agreement to schedule a specific delivery time or change the delivery address for an existing order. Returns `EntityResponse` on creation and `AgreementResponse` on retrieval. ```php setCdekNumber(1105661402) // CDEK waybill number (int) ->setDate('2024-06-15') // Agreed delivery date (YYYY-MM-DD) ->setTimeFrom('10:00') // Agreed time from (H:i) ->setTimeTo('18:00') // Agreed time to (H:i) ->setComment('Call 30 min before') ->setToLocation( // Change delivery address if needed (new Location()) ->setCode(44) ->setAddress('ul. Mira, d. 12, kv. 5') ); // Alternative: set UUID instead of CDEK number // $agreement->setUuid('b5c67e09-...'); $response = $client->createAgreement($agreement); $agreementUuid = $response->getEntityUuid(); // Retrieve agreement details $info = $client->getAgreement($agreementUuid); echo $info->getUuid(); echo $info->getOrderUuid(); echo $info->getCdekNumber(); echo $info->getNumber(); echo $info->getComment(); echo $info->getSender()->getName(); ``` --- ## `CdekClientV2::createIntakes()` / `getIntakes()` / `deleteIntakes()` — Courier Pickup Request Registers a request for a courier to pick up packages from the sender's address. Returns `EntityResponse` on creation and `IntakesResponse` on retrieval. ```php setCdekNumber(1105661402) ->setIntakeDate('2024-06-14') // Pickup date (YYYY-MM-DD) ->setIntakeTimeFrom('09:00') // Pickup window start (hh:mm) ->setIntakeTimeTo('18:00') // Pickup window end (hh:mm) ->setLunchTimeFrom('13:00') // Lunch break start ->setLunchTimeTo('14:00') // Lunch break end ->setName('Electronics - 2 boxes') // Cargo description ->setNeedCall(true) // Request a pre-call ->setSender( (new Contact()) ->setCompany('My Store Ltd.') ->setName('Ivan Petrov') ->setPhones('+79161234567') ) ->setFromLocation( (new Location()) ->setCode(1204) ->setAddress('ul. Lenina, d. 1') ); $response = $client->createIntakes($intake); $intakeUuid = $response->getEntityUuid(); // Retrieve intake info $info = $client->getIntakes($intakeUuid); echo $info->getIntakeNumber(); echo $info->getIntakeDate(); echo $info->getIntakeTimeFrom(); echo $info->getIntakeTimeTo(); echo $info->getName(); echo $info->getNeedCall() ? 'call needed' : ''; foreach ($info->getStatuses() as $status) { echo $status->getCode(); } // Delete intake $client->deleteIntakes($intakeUuid); // returns false on success ``` --- ## `CdekClientV2::setWebhooks()` / `getWebhooks()` / `getWebhook()` / `deleteWebhooks()` — Webhook Management Subscribes to CDEK event notifications via webhooks. Supported event types: `ORDER_STATUS` (order status changes) and `PRINT_FORM` (print form readiness). ```php setWebhooks( (new Webhooks()) ->setUrl('https://myshop.example.com/cdek/webhook') ->setType(Constants::HOOK_TYPE_STATUS) // 'ORDER_STATUS' ); $webhookUuid = $response->getEntityUuid(); echo 'Webhook registered: ' . $webhookUuid; // Subscribe to print form readiness $client->setWebhooks( (new Webhooks()) ->setUrl('https://myshop.example.com/cdek/printform') ->setType('PRINT_FORM') ); // List all registered webhooks $webhooks = $client->getWebhooks(); foreach ($webhooks as $wh) { // AntistressStore\CdekSDK2\Entity\Responses\WebhookListResponse echo $wh->getUuid(); echo $wh->getUrl(); echo $wh->getType(); } // Get single webhook $wh = $client->getWebhook($webhookUuid); // Delete webhook $client->deleteWebhooks($webhookUuid); ``` --- ## `CdekClientV2::getPayments()` — Cash-on-Delivery Payment Reports Returns a list of orders for which COD (cash-on-delivery) funds were transferred on the specified date. Returns `PaymentResponse`. ```php getPayments('2024-03-25'); foreach ($paymentResponse->getOrders() as $order) { echo $order['uuid']; // CDEK order UUID echo $order['numberOrder']; // CDEK waybill number echo $order['imNumber']; // Store order number } ``` --- ## `CdekClientV2::getChecks()` — Fiscal Receipt Information Retrieves fiscal receipt (check) data for an order or all orders on a given date. Returns `CheckResponse`. ```php getChecks( (new Check()) ->setCdekNumber('1105661402') ->setDate('2024-03-25') // Optional: filter by date ); foreach ($checks as $check) { // AntistressStore\CdekSDK2\Entity\Responses\CheckResponse items echo $check->getCdekNumber(); echo $check->getOrderUuid(); echo $check->getDate(); echo $check->getFiscalStorageNumber(); echo $check->getDocumentNumber(); echo $check->getFiscalSign(); echo $check->getType(); // Receipt type code echo $check->getPaymentInfo(); } ``` --- ## `CdekClientV2::getRegistries()` — COD Payment Registries Returns COD payment registries transferred on a given date. Returns `RegistryResponse`. ```php getRegistries('2024-03-25'); foreach ($registry->getOrders() as $entry) { echo $entry['uuid']; echo $entry['numberOrder']; echo $entry['imNumber']; } ``` --- ## Summary The primary use case for `antistress-store/cdek-sdk-v2` is integrating CDEK delivery into PHP e-commerce platforms and CRM systems. A typical integration flow starts by instantiating `CdekClientV2` with production credentials and enabling token caching via `setMemory()` to avoid repeated OAuth calls. During checkout, `calculateTariffList()` provides shipping cost options to the customer, and delivery point selection is powered by `getDeliveryPoints()`. On order placement, `createOrder()` submits the shipment to CDEK and returns a UUID that the application stores alongside the order record. Waybill and barcode PDFs are generated on demand with `setInvoice()` / `getInvoicePdf()` and `setBarcode()` / `getBarcodePdf()`. For couriers collecting parcels from the seller's warehouse, `createIntakes()` schedules pickups. Status tracking is handled either by polling `getOrderInfoByUuid()` or by subscribing to push events via `setWebhooks()`. For Laravel, Symfony, or vanilla PHP integration, the SDK's fluent builder pattern allows concise, readable order construction without configuration files. The `setMemory()` callback pattern slots neatly into any caching layer—Laravel sessions, Redis, or a database column. All request entities extend `Source` (which implements `JsonSerializable` and `prepareRequest()`) so they can be introspected or logged easily. Error handling relies on two specific exceptions—`CdekV2AuthException` for credential problems and `CdekV2RequestException` for API-level errors—with translated Russian error messages mapped from CDEK error codes via `Constants::ERRORS`. The test environment (`'TEST'` constructor argument) uses the official CDEK sandbox at `api.edu.cdek.ru/v2/` with built-in test credentials, allowing full end-to-end integration testing without a production contract.