Skip to content

Communications Module Getting Started Guide

This guide covers everything you need to know to work with customer communications features in the Wildberries TypeScript SDK.

Important: Several legacy methods have been removed from the Wildberries API and are now deprecated in this SDK. See the Deprecated Methods section for details.

Table of Contents

What is the Communications Module?

The Communications module provides complete control over customer communication channels, including:

  • Questions & Answers: Manage and respond to customer questions about products
  • Feedbacks & Reviews: View, respond to, and manage product reviews
  • Pinned Reviews: Pin positive reviews to product cards (NEW feature)
  • Customer Chat: Real-time messaging with buyers
  • Claims & Returns: Handle return requests and customer claims

Key Capabilities

FeatureDescriptionKey Methods
QuestionsView and answer customer questionsquestions(), question(), updateQuestion()
Question CountsTrack unanswered questionsgetQuestionsCount(), getQuestionsCountUnanswered()
ReviewsView and respond to product reviewsfeedbacks(), feedback(), createFeedbacksAnswer()
Review CountsTrack unprocessed reviewsgetFeedbacksCount(), getFeedbacksCountUnanswered()
Pinned ReviewsPin reviews to product cardspinFeedback(), unpinFeedback(), getPinnedFeedbacks()
ChatCommunicate with buyersgetSellerChats(), getSellerEvents(), createSellerMessage()
ClaimsHandle return requestsclaims(), updateClaim()
New Items CheckCheck for new Q&AnewFeedbacksQuestions()

Prerequisites

SDK Installation

bash
npm install daytona-wildberries-typescript-sdk

API Key Setup

You need a valid Wildberries API key with communications permissions. Create a .env file:

bash
WB_API_KEY=your_api_key_here

Import and Initialize

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({
  apiKey: process.env.WB_API_KEY!
});

Basic Usage

Quick Start Example

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

async function main() {
  // Check for new questions and feedbacks
  const newItems = await sdk.communications.newFeedbacksQuestions();

  if (newItems.data?.hasNewQuestions) {
    console.log('You have new questions to answer!');
  }

  if (newItems.data?.hasNewFeedbacks) {
    console.log('You have new feedbacks to process!');
  }

  // Get unanswered questions count
  const questionCount = await sdk.communications.getQuestionsCountUnanswered();
  console.log(`Unanswered questions: ${questionCount.data?.countUnanswered}`);
  console.log(`Today: ${questionCount.data?.countUnansweredToday}`);
}

main();

Questions & Answers

Listing Questions

typescript
// Get unanswered questions with pagination
const questions = await sdk.communications.questions({
  isAnswered: false,
  take: 100,
  skip: 0,
  order: 'dateDesc'
});

console.log(`Total unanswered: ${questions.data?.countUnanswered}`);

for (const q of questions.data?.questions ?? []) {
  console.log(`Question ID: ${q.id}`);
  console.log(`Text: ${q.text}`);
  console.log(`Product: ${q.productDetails?.productName}`);
  console.log(`Date: ${q.createdDate}`);
  console.log('---');
}

Get Question by ID

typescript
// Get a specific question
const question = await sdk.communications.question({ id: 'question-uuid-here' });

if (question.data) {
  console.log(`Question: ${question.data.text}`);
  console.log(`Product: ${question.data.productDetails?.productName}`);
  console.log(`State: ${question.data.state}`);

  if (question.data.answer) {
    console.log(`Answer: ${question.data.answer.text}`);
    console.log(`Editable: ${question.data.answer.editable}`);
  }
}

Answer a Question

typescript
// Answer or edit an answer to a question
await sdk.communications.updateQuestion({
  id: 'question-uuid-here',
  answer: { text: 'Thank you for your question! The product is...' },
  state: 'wbRu'  // State for answered question
});

console.log('Question answered successfully');

Mark Question as Viewed

typescript
// Mark a question as viewed without answering
await sdk.communications.updateQuestion({
  id: 'question-uuid-here',
  wasViewed: true
});

Question Count by Date Range

typescript
// Get count of questions in a date range
const count = await sdk.communications.getQuestionsCount({
  dateFrom: Date.parse('2025-01-01') / 1000, // Unix timestamp
  dateTo: Date.parse('2025-01-31') / 1000,
  isAnswered: false
});

console.log(`Unanswered questions in January: ${count.data}`);

Feedbacks & Reviews

Listing Reviews

typescript
// Get unprocessed reviews
const feedbacks = await sdk.communications.feedbacks({
  isAnswered: false,
  take: 100,
  skip: 0,
  order: 'dateDesc'
});

console.log(`Unprocessed reviews: ${feedbacks.data?.countUnanswered}`);
console.log(`Archived reviews: ${feedbacks.data?.countArchive}`);

// Process each feedback
for (const fb of feedbacks.data?.feedbacks ?? []) {
  console.log(`Review ID: ${fb.id}`);
  console.log(`Rating: ${fb.productValuation}/5`);
  console.log(`Pros: ${fb.pros}`);
  console.log(`Cons: ${fb.cons}`);
  console.log(`Text: ${fb.text}`);
  console.log('---');
}

Get Review by ID

typescript
const feedback = await sdk.communications.feedback({ id: 'feedback-uuid-here' });

if (feedback.data) {
  console.log(`User: ${feedback.data.userName}`);
  console.log(`Rating: ${feedback.data.productValuation}/5`);
  console.log(`Product: ${feedback.data.productDetails?.productName}`);

  // Check for media
  if (feedback.data.photoLinks?.length) {
    console.log('Photos:', feedback.data.photoLinks.map(p => p.fullSize));
  }

  if (feedback.data.video) {
    console.log(`Video: ${feedback.data.video.link}`);
  }

  // Check if can request return
  if (feedback.data.isAbleReturnProductOrders) {
    console.log('Product return can be requested');
  }
}

Answer a Review

typescript
// Send an answer to a review
await sdk.communications.createFeedbacksAnswer({
  id: 'feedback-uuid-here',
  text: 'Thank you for your feedback! We appreciate your kind words.'
});

console.log('Review answered successfully');

Edit Review Answer

typescript
// Edit an existing answer (can only edit once within 60 days)
await sdk.communications.updateFeedbacksAnswer({
  id: 'feedback-uuid-here',
  text: 'Updated response: Thank you for your detailed feedback!'
});

Request Product Return

typescript
// Request a return for the product mentioned in the review
// Only available when isAbleReturnProductOrders is true
const result = await sdk.communications.createOrderReturn({
  feedbackId: 'feedback-uuid-here'
});

if (!result.error) {
  console.log('Return request submitted');
}

Get Archived Reviews

typescript
// Get reviews that have been processed or auto-archived
const archived = await sdk.communications.getFeedbacksArchive({
  take: 50,
  skip: 0,
  order: 'dateDesc'
});

console.log(`Archived reviews: ${archived.data?.feedbacks?.length}`);

Pinned Reviews

The pinned reviews feature allows you to highlight positive reviews on your product cards. This requires an active Jam subscription or tariff option.

Check Pinning Limits

typescript
// Check your limits for pinning reviews
const limits = await sdk.communications.getPinnedFeedbacksLimits();

if (limits.data.subscription) {
  console.log('Subscription limits:');
  console.log(`  Total: ${limits.data.subscription.limit}`);
  console.log(`  Used: ${limits.data.subscription.used}`);
  console.log(`  Remaining: ${limits.data.subscription.remaining}`);
}

if (limits.data.tariff) {
  console.log('Tariff limits:');
  console.log(`  Total: ${limits.data.tariff.limit}`);
  console.log(`  Used: ${limits.data.tariff.used}`);
  console.log(`  Remaining: ${limits.data.tariff.remaining}`);
}

Get Pinned Reviews Count

typescript
// Count pinned reviews
const pinnedCount = await sdk.communications.getPinnedFeedbacksCount({
  state: 'pinned'
});
console.log(`Total pinned reviews: ${pinnedCount.data}`);

// Count by pin location
const cardCount = await sdk.communications.getPinnedFeedbacksCount({
  state: 'pinned',
  pinOn: 'nm'  // On product card
});
console.log(`Pinned on cards: ${cardCount.data}`);

const groupCount = await sdk.communications.getPinnedFeedbacksCount({
  state: 'pinned',
  pinOn: 'imt'  // On merged product group
});
console.log(`Pinned on groups: ${groupCount.data}`);

List Pinned Reviews

typescript
// Get list of pinned reviews
const pinned = await sdk.communications.getPinnedFeedbacks({
  state: 'pinned',
  limit: 100
});

for (const item of pinned.data ?? []) {
  console.log(`Pin ID: ${item.pinId}`);
  console.log(`Feedback ID: ${item.feedbackId}`);
  console.log(`Pinned on: ${item.pinOn}`);
  console.log(`Pin method: ${item.pinMethod}`);
  console.log(`Pinned at: ${item.pinnedAt}`);
  console.log('---');
}

// Get next page if available
if (pinned.next) {
  const nextPage = await sdk.communications.getPinnedFeedbacks({
    state: 'pinned',
    next: pinned.next
  });
}

Pin a Review

typescript
// Pin reviews to product cards
const result = await sdk.communications.pinFeedback([
  {
    pinMethod: 'subscription',  // or 'tariff'
    pinOn: 'nm',                // 'nm' for product card, 'imt' for merged group
    feedbackId: 'VlbkVVl7mtw37wyWkJZz'
  },
  {
    pinMethod: 'tariff',
    pinOn: 'imt',
    feedbackId: 'DibuRAImknLyiqgzvGcU'
  }
]);

// Check results
for (const item of result.data ?? []) {
  if (item.isErrors) {
    console.log(`Failed to pin ${item.feedbackId}:`, item.errors);
  } else {
    console.log(`Pinned ${item.feedbackId} with pinId: ${item.pinId}`);
  }
}

Unpin Reviews

typescript
// Get pinned reviews first to obtain pinIds
const pinned = await sdk.communications.getPinnedFeedbacks({ state: 'pinned' });
const pinIdsToUnpin = pinned.data?.slice(0, 3).map(item => item.pinId) ?? [];

// Unpin the reviews
const result = await sdk.communications.unpinFeedback(pinIdsToUnpin);
console.log(`Successfully unpinned: ${result.data?.join(', ')}`);

Customer Chat

List All Chats

typescript
// Get all chats with buyers
const chats = await sdk.communications.getSellerChats();

for (const chat of chats.chats ?? []) {
  console.log(`Chat ID: ${chat.chatId}`);
  console.log(`Buyer ID: ${chat.buyerId}`);
  console.log(`Order ID: ${chat.orderId}`);
  console.log(`Status: ${chat.status}`);
  console.log('---');
}

Get Chat Events

typescript
// Get chat events (messages, status changes, etc.)
let allEvents: any[] = [];
let nextToken: number | undefined;

// Paginate through all events
do {
  const events = await sdk.communications.getSellerEvents(
    nextToken ? { next: nextToken } : undefined
  );

  allEvents = allEvents.concat(events.events ?? []);
  nextToken = events.next;

  console.log(`Fetched ${events.events?.length} events, total: ${events.totalEvents}`);
} while (nextToken);

console.log(`Total events fetched: ${allEvents.length}`);

Send Message

typescript
// Send a message to a buyer
// Note: Message content is sent via form data
const result = await sdk.communications.createSellerMessage();
console.log('Message sent:', result);

Download File from Chat

typescript
// Download a file or image from a chat message
// Get the downloadID from chat events
const downloadId = 'download-id-from-event';
const file = await sdk.communications.getSellerDownload(downloadId);
console.log('File downloaded');

Claims & Returns

List Return Claims

typescript
// Get active return claims (last 14 days)
const claims = await sdk.communications.claims({
  is_archive: false,
  limit: 50,
  offset: 0
});

console.log('Return claims:', claims);

// Filter by product
const productClaims = await sdk.communications.claims({
  is_archive: false,
  nm_id: 123456789
});

// Get a specific claim
const specificClaim = await sdk.communications.claims({
  is_archive: false,
  id: 'claim-id-here'
});

Respond to a Claim

typescript
// Respond to a customer return claim
const result = await sdk.communications.updateClaim();
console.log('Claim response sent:', result);

Deprecated Methods

The following methods have been removed from the Wildberries API and are deprecated in this SDK. They will log a warning when called and may return errors from the API.

Deprecated MethodDescriptionReason
supplierValuations()Get complaint reasons for reviewsRemoved from API
createFeedbacksAction()Report a review or product issueRemoved from API
templates()Get response templatesRemoved from API
createTemplate()Create a response templateRemoved from API
updateTemplate()Update a response templateRemoved from API
deleteTemplate()Delete a response templateRemoved from API

Migration Notes

Templates functionality has been removed. You will need to:

  1. Store response templates in your own application
  2. Manage templates through your own database or configuration
  3. Use the standard createFeedbacksAnswer() method to send responses

Review complaint/action functionality has been removed. Contact Wildberries support for alternative methods to report problematic reviews.

Deprecated Method Warnings

When you call a deprecated method, the SDK will log a warning:

typescript
// This will log a warning to console
const templates = await sdk.communications.templates({ templateType: 1 });
// [WB SDK] templates is deprecated and may be removed. This endpoint has been removed from the Wildberries API.

Error Handling

Comprehensive Error Handling

typescript
import {
  WildberriesSDK,
  RateLimitError,
  AuthenticationError,
  ValidationError,
  NetworkError,
  WBAPIError
} from 'daytona-wildberries-typescript-sdk';

async function processQuestions() {
  try {
    const questions = await sdk.communications.questions({
      isAnswered: false,
      take: 100,
      skip: 0
    });
    // Process questions...
  } catch (error) {
    if (error instanceof RateLimitError) {
      console.error('Rate limit exceeded');
      console.error(`Retry after: ${error.retryAfter}ms`);
      // SDK handles retry automatically
    } else if (error instanceof AuthenticationError) {
      console.error('Invalid API key - check your credentials');
    } else if (error instanceof ValidationError) {
      console.error('Invalid request:', error.message);
      // Fix request parameters
    } else if (error instanceof NetworkError) {
      console.error('Network error:', error.message);
      // Check connectivity
    } else if (error instanceof WBAPIError) {
      console.error(`API error ${error.statusCode}: ${error.message}`);
    }
  }
}

Handling API Response Errors

The Communications API returns errors in a consistent format:

typescript
const response = await sdk.communications.questions({
  isAnswered: false,
  take: 100,
  skip: 0
});

if (response.error) {
  console.error(`API Error: ${response.errorText}`);
  if (response.additionalErrors?.length) {
    console.error('Additional errors:', response.additionalErrors);
  }
} else {
  // Process response.data
}

Rate Limits

The Communications API uses different rate limits by endpoint category:

Rate Limit Tiers

CategoryRequests/SecIntervalBurstMethods
Q&A and Reviews3333ms6Most feedback/question methods
Pinned Reviews3333ms6All pinning methods
Customer Chat11s10Chat list, events, messages
Claims0.333s10claims(), updateClaim()

Rate Limit Tips

  • The SDK handles rate limiting automatically with queuing and retry
  • Claims methods are slowest - only 20 requests per minute
  • Q&A and Reviews allow 180 requests per minute with 6-request bursts
  • Use pagination to reduce the number of API calls
  • Batch operations when possible
typescript
// Efficient: Get 100 items per request
const questions = await sdk.communications.questions({
  isAnswered: false,
  take: 100,  // Maximum items per request
  skip: 0
});

// Less efficient: Get fewer items, requiring more requests
const questions = await sdk.communications.questions({
  isAnswered: false,
  take: 10,
  skip: 0
});

Best Practices

1. Monitor for New Content Regularly

typescript
// Set up a polling interval to check for new questions/reviews
async function checkForNewContent() {
  const newItems = await sdk.communications.newFeedbacksQuestions();

  if (newItems.data?.hasNewQuestions || newItems.data?.hasNewFeedbacks) {
    // Trigger notification or processing
    console.log('New content available!');
  }
}

// Poll every 5 minutes
setInterval(checkForNewContent, 5 * 60 * 1000);

2. Process Reviews by Rating

typescript
// Prioritize responding to negative reviews
async function processNegativeReviews() {
  const feedbacks = await sdk.communications.feedbacks({
    isAnswered: false,
    take: 100,
    skip: 0
  });

  // Sort by rating (lowest first)
  const sortedByRating = (feedbacks.data?.feedbacks ?? [])
    .sort((a, b) => (a.productValuation ?? 5) - (b.productValuation ?? 5));

  for (const fb of sortedByRating) {
    if ((fb.productValuation ?? 5) <= 3) {
      console.log(`Priority: ${fb.productValuation} star review`);
      // Handle negative review
    }
  }
}

3. Use Pinned Reviews Strategically

typescript
async function pinTopReviews(nmId: number) {
  // Get reviews for a product
  const feedbacks = await sdk.communications.feedbacks({
    isAnswered: true,  // Only processed reviews
    nmId: nmId,
    take: 100,
    skip: 0
  });

  // Find 5-star reviews with photos
  const topReviews = (feedbacks.data?.feedbacks ?? [])
    .filter(fb => fb.productValuation === 5 && fb.photoLinks?.length);

  // Check limits before pinning
  const limits = await sdk.communications.getPinnedFeedbacksLimits();
  const remaining = limits.data.subscription?.remaining ?? 0;

  if (topReviews.length > 0 && remaining > 0) {
    const toPin = topReviews.slice(0, Math.min(remaining, 3));

    await sdk.communications.pinFeedback(
      toPin.map(fb => ({
        pinMethod: 'subscription',
        pinOn: 'nm',
        feedbackId: fb.id!
      }))
    );
  }
}

4. Track Response Times

typescript
async function getResponseMetrics() {
  const unansweredToday = await sdk.communications.getQuestionsCountUnanswered();
  const totalUnanswered = await sdk.communications.getQuestionsCount({
    isAnswered: false
  });

  console.log('Question Response Metrics:');
  console.log(`  Unanswered today: ${unansweredToday.data?.countUnansweredToday}`);
  console.log(`  Total unanswered: ${totalUnanswered.data}`);

  const feedbackMetrics = await sdk.communications.getFeedbacksCountUnanswered();
  console.log('Feedback Response Metrics:');
  console.log(`  Unprocessed today: ${feedbackMetrics.data?.countUnansweredToday}`);
  console.log(`  Total unprocessed: ${feedbackMetrics.data?.countUnanswered}`);
  console.log(`  Average rating: ${feedbackMetrics.data?.valuation}`);
}

5. Handle Claims Promptly

typescript
async function processReturnClaims() {
  // Claims expire after 14 days - process them regularly
  const claims = await sdk.communications.claims({
    is_archive: false,
    limit: 100,
    offset: 0
  });

  console.log(`Active claims: ${(claims as any[]).length}`);

  // Process each claim based on your return policy
  for (const claim of claims as any[]) {
    console.log(`Claim ${claim.id}: ${claim.status}`);
    // Respond to claim
  }
}

Made with ❤️ for the Wildberries developer community