Skip to main content

Product Import Utility

Source: internal/api/v1/store/Controllers/import.js

Overview

The Import controller provides administrative utilities for importing Stripe products and prices from the platform to connected accounts or from Stripe to the DashClicks database. It handles product/price replication with metadata preservation and reference tracking.

Key Capabilities

  • Import platform products as DashClicks catalog (type: dashclicks)
  • Replicate platform products to connected accounts (type: default)
  • Automatic price replication with reference tracking
  • Metadata preservation and additional info mapping
  • Transaction support for atomic operations

MongoDB Collections

CollectionOperationsPurpose
_store.productsCreateProduct storage
_store.pricesCreatePrice storage with reference tracking
_accountsReadConnected account validation

Service Methods

ImportProduct

Imports a Stripe product and its prices to MongoDB or replicates to connected account.

Endpoint: GET /store/import

Query Parameters:

{
product: string, // Stripe product ID
type: 'dashclicks' | 'default',
account_id: string // Required if type = 'default'
}

Response: Created product object with price references

Import Types:

  1. DashClicks (Platform Catalog):

    • Imports Stripe product/prices directly to MongoDB
    • Sets platform_type = 'dashclicks'
    • Sets connected_account = 'platform'
    • Uses additional_info mapping from environment-specific config
  2. Default (Connected Account Replication):

    • Creates new Stripe product/prices in connected account
    • Links to original via reference_price
    • Sets platform_type = 'default'
    • Tracks both platform and connected account versions

Business Logic Flows

DashClicks Import

graph TD
A[GET /store/import?type=dashclicks] --> B[Fetch Stripe Product]
B --> C[Fetch Stripe Prices]
C --> D[Start MongoDB Transaction]
D --> E[Create Product Document]
E --> F[Loop: Create Price Documents]
F --> G[Map additional_info from Config]
G --> H[Update Product with Price IDs]
H --> I[Commit Transaction]
I --> J[Return Product]

Connected Account Import

graph TD
A[GET /store/import?type=default] --> B[Validate Account]
B --> C[Fetch Platform Product]
C --> D[Fetch Platform Prices]
D --> E[Create Stripe Product in Connected Account]
E --> F[Loop: Create Stripe Prices]
F --> G[Start MongoDB Transaction]
G --> H[Create Product Document]
H --> I[Create Price Documents with References]
I --> J[Update Product with Price IDs]
J --> K[Commit Transaction]
K --> L[Return Product]

Environment-Specific Mapping

The controller uses environment-specific mappings for additional_info:

Development:

const additional_info = {
price_1JGCipGQFGgNthKOAOHaS6vX: '61113748a634a339ea1c6b48', // Facebook Ads Pro
price_1JMYy6GQFGgNthKOKjweCNr3: '61113745a634a339ea1c6b47', // Facebook Ads Plus
// ... more mappings
};

Production: Different price IDs with same product mappings

Sub-Account Products:

const subAccountProducts = {
prod_J4BSgSW33f3p5V: {
// Software product
tier1: {
month: '611fabe847100e45ebcfc507',
year: '611fae7547100e45ebcfc50b',
},
tier2: { month, year },
tier3: { month, year },
},
};

Connected Account Replication

Stripe Product Creation

Strips non-replicable fields:

delete sProd.object;
delete sProd.created;
delete sProd.livemode;
delete sProd.updated;
delete sProd.stripe_id;
delete sProd.tax_code;
delete sProd.shippable;
delete sProd.url;
delete sProd.package_dimensions;
delete sProd.lastResponse;
delete sProd.unit_label;
delete sProd.description;
delete sProd.default_price;

const prod = await stripe.products.create(sProd, {
stripeAccount: connected_account,
});

Price Replication

Strips and transforms price fields:

delete price.unit_amount_decimal;
delete price.object;
delete price.created;
delete price.livemode;
delete price.updated;
delete price.type;
delete price.id;
delete price.tiers_mode;
delete price.lookup_key;
delete price.tax_behavior;
delete price.transform_quantity;
delete price.description;
delete price.custom_unit_amount;

price.product = new_product_id;
price.recurring = { interval: price.recurring.interval };

const p = await stripe.prices.create(price, {
stripeAccount: connected_account,
});

Reference Tracking

For connected account imports, tracks platform product relationship:

const pPayload = {
...price,
platform_type: 'default',
product: nProd._id,
connected_account: account.stripe_connected_account,
account: account._id,
};

// Link to platform price
if (subAccountProducts[platform_product_id]?.[tier]?.[interval]) {
pPayload.additional_info = platform_price_id;
pPayload.additional_info_sub = platform_price_id;
}

Fields:

  • additional_info: Platform product/service reference (MongoDB ObjectId as string)
  • additional_info_sub: Same as additional_info for sub-account products

Transaction Management

All MongoDB operations wrapped in transactions for atomicity:

const session = await mongoose.startSession();
try {
session.startTransaction();

// Create product
const prod = await new StoreProduct({...}).save({ session });

// Create prices
for (price of prices) {
await new StorePrice({...}).save({ session });
}

// Update product with price references
await StoreProduct.findByIdAndUpdate(
prod._id,
{ prices: price_ids },
{ new: true, session }
);

await session.commitTransaction();
} catch (err) {
await session.abortTransaction();
throw err;
}

Edge Cases & Business Rules

1. Connected Account Validation

Returns 204 No Content if:

  • Account not found
  • Account has no stripe_connected_account

2. Product Type Distinction

DashClicks Products:

  • platform_type = 'dashclicks'
  • connected_account = 'platform'
  • No account reference
  • Used for platform-wide services

Default Products:

  • platform_type = 'default'
  • connected_account = account.stripe_connected_account
  • account = account._id
  • Used for white-label services

3. Price Metadata Preservation

Preserves tier metadata for software products:

  • tier1 (Pro), tier2 (Plus), tier3 (Premium)
  • Used for tier-based pricing logic

4. Recurring Interval Simplification

Only preserves interval, removes count:

price.recurring = { interval: price.recurring.interval }; // 'month', 'year'

💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM