Docs

Docs / Data Feed / Rules and restrictions

For Data Feed stores
Reference · Store API v1

Rules and restrictions

How your pricing rules choose a product's price, and how your restrictions choose what your store shows, so that what you write with the API does what you meant.

Pricing rules
The first match sets the price
Restrictions
Any one exclude hides
Permissions
Pricing rules, Restrictions, for Data Feed stores
Preview
10 a minute per store

Pricing rules: the first match wins

Your rules are checked in order, lowest sort_order first, and on a tie the older rule. For each product, the first enabled rule that matches it sets its markup, and no other rule is applied: rules never add up. A product no rule matches is priced at cost plus your default margin, if one is set, and otherwise at cost: one of your store-wide pricing settings, with the price rounding and the MAP floor.

  • A rule matches when every condition it has matches, and a condition matches when any one of its values does: categories (each takes in the ones below it), brands, product classes, distributors and UPCs, then the cost range and the MAP and MSRP gates. An empty condition matches anything.
  • The price is the base the rule names (apply_markup_price_to), plus markup_percentage of it, plus markup_value_fixed, rounded to the cent and never below zero. Each offer is priced on its own, and the cheapest one your restrictions allow is the one your store sells, after your MAP floor and price rounding.
  • Your own stock is never priced by rules. An in-house row sells at the price you set on it.
  • So a rule's place is part of what it means. Put a narrow rule above a general one, or the general one takes its products. A new rule goes directly above the first rule broader than it, and POST /pricing-rules/reorder sets the whole order.

Restrictions: any one of them hides

  • Inside one restriction, every condition must match, and inside one condition any of its values will do. Categories handguns and rifles with the brand glock match Glock handguns and Glock rifles, and nothing else.
  • Any switched-on exclude that matches hides it. One is enough, and order never matters, so restrictions have no reorder.
  • Only-shows work the other way round. Once your store has a switched-on only_show, a product must match at least one of them to be shown. An exclude wins over an only-show.
  • They judge each offer, not the product. A product hidden at one distributor can still be sold from another that no restriction matches. A restriction that names distributors or a cost range never hides your own stock.
  • min_stock turns with the kind: on an exclude it matches an offer with fewer than that many in stock, on an only-show one with at least that many, so both hide low stock.
  • A switched-off restriction (disabled) is kept, and hides nothing.

Saves you confirm

Some saves are held back with a 422 until you say you mean them. Nothing is saved: send the same body again with the field the answer names.

AnswerWhenSend again with
zero_match_confirmation_requiredA pricing rule or restriction whose conditions name no product in the catalog. Not asked of one with no condition or with a cost range, whose products cannot be counted, nor of a switched-off restriction."acknowledge_zero_match": true
catalogue_wipe_confirmation_requiredA restriction that would empty your store: an exclude with no condition (wipe_shape exclude_everything), or your first switched-on only-show (first_only_show).confirm_token, taken from the answer

The empty-store question comes first, so a first only-show that matches nothing needs both. Take the token from the answer rather than writing it into your code. An only-show with no condition is not confirmed but refused, since it would restrict nothing.

Slugs and money

  • Conditions name rows by slug. categories, manufacturers and product_classes take the slugs GET /categories, GET /manufacturers and GET /product-classes list; distributors takes distributor slugs, as a product's sourced_from names them.
  • A slug that names nothing is refused by its place (manufacturers.1) and never dropped: a dropped slug would widen the rule. Slugs are checked once every other field passes, so a body with a field error and an unknown slug is told about the field first; then every slug that names nothing is named at once.
  • A row deleted since a rule was saved reads "(deleted)". The rule still holds it and matches nothing through it. Sending "(deleted)" back is refused: leave that condition out of a PATCH to keep it, or send the slugs you mean.
  • Money is a decimal string. Send at most two decimals, best as a string such as "22.50"; a JSON number is read the same, and a third decimal is refused, never rounded. It comes back as a string with two decimals.

Preview before you save

POST /pricing-rules/preview and POST /restrictions/preview take the body you would save, or an id and the fields you would change, and say what saving it would do: how many products it names, and up to 25 real products worked out both ways. They write nothing. Your store may make 10 previews a minute, the two kinds together, whichever key asks.

What a save sets off

  • Your store is worked out again, exactly as after a change on your FFL Monkey screens. New prices, and products leaving or coming back, arrive as merchant_price.recomputed changes.
  • The save itself is announced as pricing_rule.created, .updated, .deleted or .reordered, or restriction.created, .updated or .deleted: to your webhook, and in GET /changes for a key that can read them.
  • A create is not idempotent. A create retried after a lost answer makes a copy: list them, and delete the copy.
FFL Monkey Data Feed API, version 1. Questions: Support in your FFL Monkey account, or [email protected].