Currency

Feeds

The feeds namespace controls Ripllo's product-feed surface — today, the Google Merchant Center XML feed that Google Shopping and Performance Max ingest, with hooks for Meta Catalog and TikTok Shop in the same shape. Two endpoints: a merchant-scoped config CRUD, and a helper that builds the public XML feed URL Google polls. This page covers ripllo.feeds on the Node SDK. For the HTTP surface and the full XML shape, see API → Feeds.

Namespace

ripllo.feeds.getConfig()
ripllo.feeds.updateConfig(input)
ripllo.feeds.googleFeedUrl(accountId)   // local helper, no network call

The config is deliberately small: a master toggle, a default Google product category, and whether to include unpublished products. That's the whole surface — there is no currency, brand-fallback, condition or product-exclusion setting. The XML is built on demand, per request, from the mirrored product table; nothing is cached or pre-generated. googleFeedUrl is purely a local string builder, not a method that touches the network.

Methods

feeds.getConfig

Signature. ripllo.feeds.getConfig(): Promise<MerchantFeedConfig>

Returns the calling workspace's feed config. Always returns a record: if the merchant has never saved one, you get the defaults (enabled: true, defaultGoogleProductCategory: null, includeUnpublished: false) rather than null.

const cfg = await ripllo.feeds.getConfig();
console.log(cfg.enabled, cfg.defaultGoogleProductCategory, cfg.includeUnpublished);

feeds.updateConfig

Signature. ripllo.feeds.updateConfig(input): Promise<MerchantFeedConfig>

PATCH semantics — pass only the fields you want to change. Upserts, so the first call creates the row.

await ripllo.feeds.updateConfig({
  enabled: true,
  defaultGoogleProductCategory: 'Apparel & Accessories > Clothing',
  includeUnpublished: false,
});

The complete field list:

  • enabled — the master switch. Defaults to true; the feed URL being unpublished is the real opt-in, since nothing polls it until you submit it to Merchant Center.
  • defaultGoogleProductCategory — fallback taxonomy string used for any product without its own googleProductCategory. Nullable, max 200 chars.
  • includeUnpublished — when false (the default), only products marked available are emitted.
  • marketingCampaignId — optional link to a marketing campaign. Must be a campaign in your own workspace or the PATCH is 400 VALIDATION.

Unknown keys are dropped silently. The PATCH body is validated with a strict-ish schema and only recognised keys are copied into the update, so updateConfig({ googleEnabled: true, currency: 'IDR' }) returns 200 OK having changed nothing — no error tells you the feed was never enabled. Use enabled, not googleEnabled.

feeds.googleFeedUrl

Signature. ripllo.feeds.googleFeedUrl(accountId: string): string

Returns the URL you give Google. Not an async call — it's a deterministic concat of the SDK's baseUrl plus the public feed path:

const url = ripllo.feeds.googleFeedUrl('acc_<merchant>');
// → 'https://ripllo.com/api/v1/feeds/google/acc_<merchant>.xml'

Drop this string into Google Merchant Center's "Add product feed → fetch URL" flow. The endpoint is public (no signing). An accountId with no mirrored products returns a well-formed but item-less <rss> document — but see the disabled-feed case under Errors, which is a 404 rather than empty XML.

Types

interface MerchantFeedConfig {
  enabled: boolean;
  defaultGoogleProductCategory: string | null;
  includeUnpublished: boolean;
}

That is the SDK's declared shape. The row the API returns also carries id, accountId, marketingCampaignId, createdAt and updatedAt; the defaults stub returned for a merchant who has never saved a config carries only the three fields above.

Common patterns

Hand the URL off to Google Merchant Center

const cfg = await ripllo.feeds.getConfig();
if (!cfg.enabled) {
  await ripllo.feeds.updateConfig({ enabled: true });
}
const feedUrl = ripllo.feeds.googleFeedUrl(merchantAccountId);

console.log(`Add this URL to Merchant Center:\n  ${feedUrl}`);

Hide a product from Shopping

There is no exclusion list on the feed config. The feed emits every non-archived mirrored product, filtered only by availability: with includeUnpublished: false (the default) an unavailable product drops out of the feed. To hide something from Shopping, mark it unavailable on the storefront side — Ripllo has no per-product feed override.

Sniff the feed locally

const url = ripllo.feeds.googleFeedUrl(accountId);
const res = await fetch(url);
const xml = await res.text();
console.log(`${xml.match(/<item>/g)?.length ?? 0} items in feed`);

The feed surface is public, so this works without any signing.

Errors

Code Status Cause
VALIDATION 400 defaultGoogleProductCategory over 200 chars, wrong types, or a marketingCampaignId that isn't in your workspace.
NO_ACCOUNT 403 The principal carries no accountId.
INSUFFICIENT_SCOPE 403 API key lacks read (for GET /feeds/config) or write (for the PATCH). Scopes are enforced; ripllo:platform:admin is a superset of both.

The public XML endpoint never returns the API error envelope, but it is not always XML either:

  • Feed disabled (enabled: false on a saved config) → 404 with text/plain body feed disabled. This is what Merchant Center sees when a merchant switches the feed off — a fetch failure, not an empty catalogue. Check here first when Google reports it can't retrieve the feed.
  • Any other case200 with an application/xml <rss> document, which may legitimately contain zero <item> elements (unknown account, no mirrored products, or everything filtered out by includeUnpublished). The feed is capped at 5000 products, newest-updated first.

Next

  • Pixels — companion analytics-tracking surface.
  • API → Feeds — the full XML shape and crawl behaviour.
CurrencyRupiah is paid by transfer or QRIS; US dollars settle through PayPal.