Catalog concepts
This page builds your mental model of what you are publishing to CATALG.
This page builds your mental model of what you are publishing to CATALG. It walks through the catalog object, its parts, and the rules that govern how CATALG processes it.
If you have not yet published a catalog, run the Quickstart first — it will make every concept here much more concrete.
Looking for exact field shapes, endpoint paths, and error codes? See the API Reference.
A catalog at a glance
A catalog is the top-level payload you publish. It carries the identity of the publishing provider, the resources they offer, and any pricing or commercial terms attached to those resources.
Here is a complete catalog stripped to its essentials:
{ "id": "CAT-FRESHMART-2026", "descriptor": { "name": "FreshMart Daily Catalog", "shortDesc": "Fresh groceries — Bangalore South" }, "provider": { "id": "freshmart-blr-001", "descriptor": { "name": "FreshMart Koramangala" } }, "resources": [ ... ], "offers": [ ... ] }
A catalog must contain at least one of resources or offers — both is common. How the catalog is processed (its type, how updates are applied, who can see it) is declared separately in publishDirectives at the message level, not inside the catalog object itself.
The sections below cover each piece in turn.
Resources
A resource is a domain-neutral unit of value. It can be a product SKU on a grocery shelf, an EV charging slot, a clinic appointment, a carbon credit, a job role — anything a network wants to make discoverable.
The core fields (id, descriptor) are universal. Domain-specific properties live inside resourceAttributes, declared using a JSON-LD @context and @type. This pattern lets any domain extend the schema without modifying the core Beckn protocol.
{ "id": "ITEM-BASMATI-RICE-1KG", "descriptor": { "name": "India Gate Basmati Rice", "shortDesc": "Aged basmati, 1 kg pack" }, "resourceAttributes": { "@context": "https://schema.beckn.io/RetailResource/2.1/context.jsonld", "@type": "RetailResource", "brand": "India Gate", "sku": "BSMTI-1KG-IG" } }
The @context URI tells consumers which schema vocabulary applies. CATALG uses it during domain schema validation (see Validation).
Offers
An offer captures the commercial terms under which one or more resources can be obtained — price, discount, eligibility, validity. Offers are separate from resources and are linked by resourceIds, which means the same resource can carry multiple competing offers from different providers.
{ "id": "OFFER-BASMATI-MAY26", "descriptor": { "name": "May Staples Deal" }, "resourceIds": ["ITEM-BASMATI-RICE-1KG"], "validity": { "startDate": "2026-05-01T00:00:00Z", "endDate": "2026-05-31T23:59:59Z" }, "offerAttributes": { "@context": "https://schema.beckn.io/RetailOffer/2.1/context.jsonld", "@type": "RetailOffer", "isActive": true }, "considerations": [ { "id": "PRICE-BASMATI", "considerationAttributes": { "@context": "https://schema.beckn.io/PriceSpecification/2.0/context.jsonld", "@type": "PriceSpecification", "value": 95, "currency": "INR" } } ] }
Provider-level offers
An offer with no resourceIds applies to all resources published by that provider. Use this for blanket promotions, free-delivery thresholds, loyalty programmes, or any commercial term not tied to a specific resource.
{ "id": "OFFER-FREE-DELIVERY", "descriptor": { "name": "Free delivery on orders above ₹500" }, "offerAttributes": { "@context": "https://schema.beckn.io/RetailOffer/2.1/context.jsonld", "@type": "RetailOffer", "isActive": true }, "considerations": [ { "id": "DELIVERY-WAIVER", "considerationAttributes": { "@context": "https://schema.beckn.io/PriceSpecification/2.0/context.jsonld", "@type": "PriceSpecification", "value": 0, "currency": "INR", "components": [ { "type": "DELIVERY", "value": 0, "currency": "INR" } ] } } ] }
Offer-only catalogs
A catalog can contain offers without any resources of its own. This is how a provider publishes pricing overlays or promotions that reference resources published by another provider. The catalog must still carry id, descriptor, and provider — only resources is omitted.
Discoverability: Offer-only catalogs and provider-level offers are not independently discoverable via resource search. A Discovery Service resolves and attaches these offers to matching real resources at query time. If no matching real resources exist in the Discovery Service, the offers will not appear in search results.
Provider
The provider block identifies who is publishing the catalog and where they operate. The availableAt array carries geo-coordinates and address, enabling spatial search on Discovery Services.
Field | Required | Description |
|---|---|---|
id | yes | Stable provider identifier within the publisher's namespace |
descriptor | yes | name, optional shortDesc, longDesc, thumbnailImage |
availableAt | no | Array of Location objects — geo (GeoJSON Point) + address (structured postal address). Resources inherit provider locations; there is no per-resource location field |
rating | no | Aggregate rating across the provider's resources |
{ "id": "freshmart-blr-001", "descriptor": { "name": "FreshMart Koramangala", "shortDesc": "Neighbourhood grocery, open 7am–10pm" }, "availableAt": [ { "geo": { "type": "Point", "coordinates": [77.6278, 12.9352] }, "address": { "streetAddress": "42 80-Feet Road, Koramangala 4th Block", "addressLocality": "Bengaluru", "addressRegion": "Karnataka", "postalCode": "560034", "addressCountry": "IN" } } ] }
Catalog types
Every catalog is one of two types, declared via catalogType in publishDirectives.
REGULAR
A commercial catalog published by a Provider Node. Resources represent what the provider is currently offering. REGULAR catalogs can contain resources, offers, or both. Most catalogs on a network are REGULAR.
MASTER (template)
A master catalog is a network-wide template published by a network facilitator or domain authority. It defines the canonical specification for a class of product or service — authoritative name, brand identity, schema type, unit of measure, and any other attributes the network wants to standardise across all providers.
Why templates exist. Without templates, every provider on a network independently defines the same product — different naming conventions, inconsistent schema types, missing attributes, conflicting brand spellings. A master resource establishes one authoritative definition that all providers on the network build from. When a consumer searches for "India Gate Basmati Rice 1KG", every store's listing refers back to the same canonical resource — ensuring consistent data across the entire network.
Master catalogs do not contain offers. They are pure resource definitions. Pricing, promotions, and commercial terms belong in REGULAR catalogs.
Extending a master in a REGULAR catalog
A Provider Node extends a master resource using resourceDirectives inside publishDirectives. The provider supplies only the fields unique to their offering — local pricing, stock status, location — and inherits everything else from the template.
"resourceDirectives": [ { "resourceId": "MY-LOCAL-BASMATI", "extends": { "masterResourceId": "MASTER-INDIA-GATE-BASMATI-1KG" } } ]
Template attributes are immutable. The provider can add new fields but cannot change values defined by the template. This is what guarantees consumers see consistent, authoritative data — canonical brand name, schema type, fixed specifications — regardless of which provider's catalog they are looking at.
For the full schema of publishDirectives and resourceDirectives, see API Reference → catalog/publish.
Publish directives
publishDirectives is an array carried at the message level (not inside the catalog) that controls how CATALG processes each catalog. Every entry is matched to a catalog by catalogId.
"message": { "publishDirectives": [ { "catalogId": "CAT-FRESHMART-2026", "catalogType": "REGULAR", "updateMode": "MERGE", "visibleTo": ["local-retail.net/grocery-net"] } ], "catalogs": [ { "id": "CAT-FRESHMART-2026", "...": "..." } ] }
publishDirectives itself is optional. When it is omitted entirely, CATALG processes every catalog in the request with its own defaults. The moment you include a publishDirectives entry, catalogType becomes mandatory within that entry; updateMode falls back to its default of MERGE if not specified.
Update modes
updateMode controls how CATALG processes incoming resources for a given catalogId:
MERGE (default) — Adds or updates incoming resources. Resources already published for this catalog but not in the incoming set are preserved. Use this for incremental updates: publish only what has changed.
FULL — Replaces the entire resource set for this catalogId. All previously published resources are removed first, then the incoming set is inserted. Use this for complete replacements: retiring old SKUs, major restructure.
Visibility — visibleTo
visibleTo restricts distribution of a catalog to a specific list of registry-registered network IDs. The catalog is delivered only to Discovery Services that subscribe to one of those networks.
When omitted — or when publishDirectives itself is not provided — the catalog is distributed via the default global network nfh.global/beckn-nodes. Every Discovery Service subscribed to that network receives the catalog. This is the catch-all path: it lets a Provider Node publish without explicit visibility configuration and have the catalog broadly discoverable across the Fabric.
"publishDirectives": [ { "catalogId": "CAT-WHOLESALE-2026", "catalogType": "REGULAR", "visibleTo": ["acme.net/distributor-net", "acme.net/wholesale-net"] } ]
When visibleTo is set, CATALG enforces it at delivery time — a Discovery Service whose subscription does not cover any of the listed networks will not receive this catalog via catalog/push, even if it is subscribed to the default global network.
Ownership
CATALG identifies the caller from the Beckn HTTP Signature in the Authorization header on every request. Ownership rules are uniform across endpoints: the identity that originally created a resource is the only identity that can later modify it.
Catalog ownership. A catalog belongs to the identity that originally published it. Only that same identity can submit updates or replacements to an existing catalogId. A request from any other identity is rejected. This applies at the resource level too — every resource in a catalog is owned by the publisher of that catalog.
Subscription ownership. A subscription belongs to the identity that created it. Only that same identity may list, view, update, or deactivate the subscription. Calls from any other identity return 403 NackForbidden.
Template resource integrity. Master resources are published and maintained by the network facilitator. Any Provider Node can extend a template and add new fields, but the template's defined values are inherited as-is and cannot be changed by a provider.
Validation
Every catalog passes through a layered set of checks before it is accepted.
Authorization
The request must carry a valid Beckn HTTP Signature in the Authorization header. CATALG resolves the public key from the DeDi registry using the subscriberId and recordId from the keyId, and verifies the signature. Missing, expired, or unrecognised signatures are rejected immediately.
Core protocol schema
CATALG validates that the request structure conforms to the Fabric v2.0 protocol schema — required context fields, correct action value, correct field names (resources, not items; resourceAttributes, not itemAttributes), and the structure of publishDirectives.
Domain schema
CATALG validates that each resource's resourceAttributes, each offer's offerAttributes, and each consideration's considerationAttributes conform to the domain schema declared in their @context URI — for example, that resources claiming @type: RetailResource actually carry the attributes the retail schema requires.
Ownership check
For updates to an existing catalogId, the caller's identity — derived from the Beckn HTTP Signature in the Authorization header — must match the identity that originally published the catalog.
What fails when
Failure | When you find out |
|---|---|
Authorization, core schema, or ownership | Synchronous rejection — HTTP 400 / 401 / 403 before the catalog is accepted |
Domain schema | Asynchronous — per-catalog REJECTED or PARTIAL result delivered via POST /catalog/on_publish |
Processing results
After processing, CATALG sends a POST /catalog/on_publish callback to the publisher's bppUri with one result per submitted catalog. Each result carries one of:
Status | Meaning |
|---|---|
ACCEPTED | Catalog processed and distributed to all matching subscribers |
REJECTED | Catalog rejected entirely — errors array explains what failed |
PARTIAL | Some resources accepted, some rejected — see errors array |
For the exact callback payload shape, see API Reference → catalog/on_publish.