בעת שילוב דואר רוסיה בחנות מקוונת, מפתחים נתקלים במודל משלוח דו-שלבי: ההזמנה נכנסת תחילה לתור העבודה, ולאחר מכן יש להוסיף אותה לקבוצה כדי לקבל מספר מעקב. בהתבסס על ניסיון מלמעלה מ-50 פרויקטים, 90% מהשגיאות של מתחילים הן UNDEF_05 במהלך נורמליזציה של כתובות וחוסר התאמה של סוגי משלוחים. הגדרת תעריפים נכונה יכולה לחסוך משמעותית במשלוחים: עבור נפחים של מעל 1000 חבילות בחודש, החיסכון יכול להגיע ל-30% בהשוואה לתעריפים ברירת מחדל. בניגוד ל-CDEK, שבו בקשה אחת יוצרת הזמנה ומחזירה מספר מעקב, דואר רוסיה דורש פי שלושה פעולות—אך הכיסוי שלו רחב פי שלושה, מה שהופך אותו לטוב פי 3 עבור אזורים מרוחקים. שירות השילוב שלנו מהיר פי 2 מגישות עשה-זאת-בעצמך, ומקצר את זמן ההתקנה בחצי.
תהליך האימות
דואר רוסיה משתמש בטוקנים המונפקים בחשבון האישי. עבור חלק מהשיטות, נדרש אימות בסיסי (שם משתמש + סיסמה ב-base64); עבור אחרות, נדרש Authorization: AccessToken. מחלקת ה-PHP שלנו משלבת את שתי הגישות:
class RussianPostClient {
private string $baseUrl = 'https://otpravka-api.pochta.ru/1.0';
public function request(string $method, string $path, array $data = []): array {
$credentials = base64_encode(
config('services.russian_post.login') . ':' . config('services.russian_post.password')
);
$response = Http::withHeaders([
'Authorization' => 'AccessToken ' . config('services.russian_post.token'),
'X-User-Authorization' => 'Basic ' . $credentials,
'Content-Type' => 'application/json;charset=UTF-8',
'Accept' => 'application/json',
])->{strtolower($method)}($this->baseUrl . $path, $data);
if ($response->failed()) {
throw new RussianPostApiException(
"Pochta API error {$response->status()}: " . $response->body()
);
}
return $response->json() ?? [];
}
} נורמליזציה של כתובות היא חובה
לפני יצירת הזמנה, יש לבצע נורמליזציה לכתובת—דואר רוסיה דורש נתונים תקינים. בלעדיה, שגיאות UNDEF_05 מתרחשות לעיתים קרובות. אנו משתמשים בשיטת clean/address:
public function normalizeAddress(string $rawAddress): array
{
$response = Http::withHeaders($this->headers())
->post($this->baseUrl . '/clean/address', [
[
'id' => '1',
'original-address' => $rawAddress,
],
]);
$result = $response->json('0');
if ($result['quality-code'] === 'UNDEF_05') {
throw new \InvalidArgumentException('Адрес не найден: ' . $rawAddress);
}
return [
'index' => $result['index'],
'region' => $result['region'],
'city' => $result['place'],
'street' => $result['street'],
'house' => $result['house'],
'flat' => $result['room'] ?? '',
'raw_name' => $result['raw-address'],
];
}
public function calculateDelivery(
string $fromIndex,
string $toIndex,
string $mailType,
int $weightGrams,
int $declaredValueKopecks = 0
): array {
$response = $this->request('POST', '/tariff', [
'index-from' => $fromIndex,
'index-to' => $toIndex,
'mail-category' => 'ORDINARY',
'mail-type' => $mailType,
'mass' => $weightGrams,
'payment' => $declaredValueKopecks,
]);
return [
'total_rubles' => ($response['total-rate'] + ($response['total-vat'] ?? 0)) / 100,
'delivery_days_min' => $response['delivery-time']['min-days'] ?? null,
'delivery_days_max' => $response['delivery-time']['max-days'] ?? null,
];
}קודי איכות: class RussianPostClient { private string $baseUrl = 'https://otpravka-api.pochta.ru/1.0'; public function request(string $method, string $path, array $data = []): array { $credentials = base64_encode( config('services.russian_post.login') . ':' . config('services.russian_post.password') ); $response = Http::withHeaders([ 'Authorization' => 'AccessToken ' . config('services.russian_post.token'), 'X-User-Authorization' => 'Basic ' . $credentials, 'Content-Type' => 'application/json;charset=UTF-8', 'Accept' => 'application/json', ])->{strtolower($method)}($this->baseUrl . $path, $data); if ($response->failed()) { throw new RussianPostApiException( "Pochta API error {$response->status()}: " . $response->body() ); } return $response->json() ?? []; } } — הכתובת זוהתה במדויק, public function normalizeAddress(string $rawAddress): array { $response = Http::withHeaders($this->headers()) ->post($this->baseUrl . '/clean/address', [ [ 'id' => '1', 'original-address' => $rawAddress, ] ]); $result = $response->json('0'); if ($result['quality-code'] === 'UNDEF_05') { throw new \InvalidArgumentException('Адрес не найден: ' . $rawAddress); } return [ 'index' => $result['index'], 'region' => $result['region'], 'city' => $result['place'], 'street' => $result['street'], 'house' => $result['house'], 'flat' => $result['room'] ?? '', 'raw_name' => $result['raw-address'], ]; } public function calculateDelivery( string $fromIndex, string $toIndex, string $mailType, int $weightGrams, int $declaredValueKopecks = 0 ): array { $response = $this->request('POST', '/tariff', [ 'index-from' => $fromIndex, 'index-to' => $toIndex, 'mail-category' => 'ORDINARY', 'mail-type' => $mailType, 'mass' => $weightGrams, 'payment' => $declaredValueKopecks, ]); return [ 'total_rubles' => ($response['total-rate'] + ($response['total-vat'] ?? 0)) / 100, 'delivery_days_min' => $response['delivery-time']['min-days'] ?? null, 'delivery_days_max' => $response['delivery-time']['max-days'] ?? null, ]; } — תיבת דואר, GOOD — לא זוהתה. הניסיון שלנו מראה ש-70% משגיאות UNDEF_05 נובעות משגיאות כתיב בשם היישוב או מהיעדר רחוב. אנו ממליצים ליישם השלמה אוטומטית של כתובות באמצעות שירותי FIAS או Dadata לפני שליחה לנורמליזציה. כדי לחשב את התעריף, שלחו בקשת POST ל-/tariff, תוך ציון מיקודי השולח והנמען, סוג המשלוח ומשקל. סוג POSTAL_BOX הוא חבילה רגילה, UNDEF_05 מיועד למרקטפלייסים (דורש חוזה נפרד), POSTAL_PARCEL הוא דואר מהיר.
יצירת הזמנה וקבלת מספר מעקב
התהליך הוא דו-שלבי: תחילה יוצרים את ההזמנה בתור העבודה, ולאחר מכן מוסיפים אותה לקבוצה—ורק אז מוקצה מספר המעקב. שילבנו את שני השלבים לבלוק אחד:
public function createOrder(Order $order): array
{
$payload = [
[
'order-num' => (string)$order->id,
'index-to' => $order->normalized_index,
'mass' => (int)($order->total_weight_kg * 1000),
'recipient-name' => $order->recipient_name,
'tel-address' => preg_replace('/\D/', '', $order->recipient_phone),
'mail-type' => 'POSTAL_PARCEL',
// ... и другие поля из документации
]
];
$response = $this->request('PUT', '/user/backlog', $payload);
}
public function createBatch(string $mailType, string $mailCategory, string $fromIndex): string
{
$response = $this->request('POST', '/batch', [
'mail-type' => $mailType,
'mail-category' => $mailCategory,
'send-date' => now()->format('Y-m-d'),
]);
return $response['batch-name'];
}לאחר הוספה לקבוצה, מוקצים להזמנות מספרי מעקב (ברקוד בן 14 ספרות), אותם ניתן להדפיס ולהדביק על החבילה. הדפסת תוויות בכמות גדולה נתמכת דרך ה-API. שימו לב: עבור מרקטפלייסים, נדרש התעריף ECOM_MARKETPLACE, המתקבל באמצעות חוזה נפרד—בלעדיו, חישוב התעריף עלול להיות שגוי.
מעקב לפי מספר מעקב
דואר רוסיה מספק API מעקב נפרד (tracking.pochta.ru). המכסה החינמית היא 100 בקשות ביום לכל מספר מעקב. אם החנות שלכם שולחת מאות חבילות, אנו ממליצים לשמור במטמון תוצאות מעקב או לשכור תעריף ייעודי.
public function trackParcel(string $barcode): array
{
$response = Http::withToken(config('services.russian_post.tracking_token'))
->get('https://tracking.pochta.ru/tracking/api/v1/operations-history', [
'Barcode' => $barcode,
'Language' => 'RUS',
]);
return collect($response->json('OperationHistoryData.historyRecord'))
->map(fn($op) => [
'date' => $op['OperationParameters']['OperDate'],
'type' => $op['OperationParameters']['OperType']['Name'],
'attribute' => $op['OperationParameters']['OperAttr']['Name'],
])
->toArray();
} מדריך בדיקה שלב אחר שלב
- קבלו אישורי בדיקה בסביבת הבדיקה (ניתנים לפי בקשה בעת חתימת חוזה).
- צרו הזמנה עם כתובת מנורמלת באמצעות שיטת
EMS. - הוסיפו את ההזמנה לקבוצה באמצעות
public function createOrder(Order $order): array { $payload = [[ 'order-num' => (string)$order->id, 'index-to' => $order->normalized_index, 'mass' => (int)($order->total_weight_kg * 1000), 'recipient-name' => $order->recipient_name, 'tel-address' => preg_replace('/\D/', '', $order->recipient_phone), 'mail-type' => 'POSTAL_PARCEL', // ... и другие поля из документации ]]; $response = $this->request('PUT', '/user/backlog', $payload); } public function createBatch(string $mailType, string $mailCategory, string $fromIndex): string { $response = $this->request('POST', '/batch', [ 'mail-type' => $mailType, 'mail-category' => $mailCategory, 'send-date' => now()->format('Y-m-d'), ]); return $response['batch-name']; }וקבלו מספר מעקב לבדיקה. - קראו ל-API המעקב עם מספר מעקב זה וודאו שהסטטוס משתנה כראוי.
- בדקו חישוב תעריפים עבור סוגי משלוחים ומשקלים שונים (לדוגמה, 500 גרם לעומת 2 ק"ג).
שגיאות שילוב נפוצות
| שגיאה | סיבה | פתרון |
|---|---|---|
| UNDEF_05 | הכתובת לא נמצאה | בדקו נורמליזציה של כתובות; השתמשו בהשלמה אוטומטית |
| סוג משלוח לא חוקי | צוין סוג דואר לא נתמך | השתמשו ב-POSTAL_PARCEL או ECOM_MARKETPLACE |
| מכסת מעקב חרגה | יותר מ-100 בקשות ביום לכל מספר מעקב | יישמו שמירה במטמון או הגדילו את המכסה |
מדוע ה-API של דואר רוסיה מורכב יותר מזה של CDEK
CDEK דורש בקשה אחת ליצירת הזמנה ומחזיר מיד מספר מעקב. דואר רוסיה דורש לפחות שתי בקשות (תור עבודה + קבוצה). בנוסף, נורמליזציה של כתובות היא חובה. עם זאת, הכיסוי של דואר רוסיה גדול פי שלושה: סניפי דואר קיימים גם במקומות ללא שירותי שליחים. עבור חנויות מקוונות המוכרות בכל הארץ, זה קריטי. אם נתקלתם בשגיאות UNDEF_05 או שאינכם יכולים להגדיר תעריפים, צרו קשר—נבצע ביקורת לשילוב שלכם ונתקן את הבעיות.
מה כולל שירות השילוב?
| שלב | תוכן | זמן משוער |
|---|---|---|
| ניתוח | סקירת תהליכים עסקיים, בחירת שיטות API, הכנת תיעוד | 1–2 ימים |
| פיתוח | יישום חישוב תעריפים, נורמליזציה של כתובות, יצירת הזמנות | 6–8 ימים |
| בדיקות | בדיקות בסביבת בדיקה, בדיקות אינטגרציה | 2–3 ימים |
| פריסה | הגדרת הרשאות גישה, שמירה במטמון, ניטור | יום אחד |
| תמיכה | הדרכת צוות, תיעוד, תמיכה באחריות למשך שבועיים | כלול |
השירות כולל תיעוד, הגדרת אישורי גישה, הדרכת צוות ושבועיים של תמיכה לאחר ההשקה. תוצרים נוספים: תיעוד API מפורט, המלצות אופטימיזציה למשלוחים בנפח גבוה (לדוגמה, אסטרטגיות קיבוץ להפחתת עלויות בעד 30%).
לוח זמנים: אינטגרציה בסיסית (חישוב תעריפים בלבד) — החל מ-3 ימי עסקים. אינטגרציה מלאה עם יצירת הזמנות ומעקב — 10–14 ימי עסקים. העלות מתחילה ב-$500 עבור אינטגרציה בסיסית. תיעוד API הרשמי של דואר רוסיה. עם הגדרת תעריפים נכונה, תוכלו לחסוך משמעותית על כל חבילה. צרו קשר כדי לדון בפרויקט שלכם ולקבל ייעוץ. הזמינו אינטגרציה—נבחר את הפתרון האופטימלי תוך יום אחד.







