Skip to content
NFH Fabric Support home
NFH Fabric Support home

Quickstart

This guide takes you from zero to a successfully published catalog in a few minutes.

This guide takes you from zero to a successfully published catalog in a few minutes. By the end, you will have submitted a real catalog to CATALG, received an ACK, and received the per-catalog processing result on your callback endpoint.

If you have not yet read what CATALG does, start with the Overview.


Before you start

Two prerequisites must be in place. Both are one-time setup steps for your organisation.

1. A target network must exist in the DeDi registry

Any network you list in publishDirectives[].visibleTo must be registered. If you omit visibleTo, your catalog is distributed via the default global network nfh.global/beckn-nodes — no other network setup is needed. Networks are created and managed by a Network Facilitator. See Build Trusted Networks using REGISTR.

2. Your organisation must be onboarded as a network participant

Your participant identity, Ed25519 signing key, and callback base URL must be registered in the DeDi registry for your target network. Two things depend on this registration:

  • the Beckn HTTP Signature on your publish request cannot be verified without your registered public key

  • CATALG resolves your /catalog/on_publish callback URL by looking up the registered callback base URL — not by trusting the bppUri in the request body

The registered callback base URL must be a publicly reachable HTTPS endpoint. See Onboarding Network Participants.


Step 1 — Prepare a minimal catalog

A catalog is the JSON payload you submit. Below is a small valid catalog — one provider, one resource, and one offer that references the resource.

{ "context": { "version": "2.0.0", "action": "catalog/publish", "messageId": "f01e0a8a-1111-4111-8111-111111111111", "transactionId": "f01e0a8a-2222-4222-8222-222222222222", "timestamp": "2026-06-02T10:00:00.000Z", "bppId": "bpp.freshmart.local-retail.net", "bppUri": "https://bpp.freshmart.local-retail.net/beckn/" }, "message": { "publishDirectives": [ { "catalogId": "CAT-FRESHMART-HELLO", "catalogType": "REGULAR" } ], "catalogs": [ { "id": "CAT-FRESHMART-HELLO", "descriptor": { "name": "FreshMart Hello Catalog", "shortDesc": "First catalog from FreshMart" }, "provider": { "id": "freshmart-blr-001", "descriptor": { "name": "FreshMart Koramangala" } }, "resources": [ { "id": "ITEM-BASMATI-1KG", "descriptor": { "name": "India Gate Basmati Rice 1KG" }, "resourceAttributes": { "@context": "https://schema.beckn.io/RetailResource/2.1/context.jsonld", "@type": "RetailResource", "brand": "India Gate" } } ], "offers": [ { "id": "OFFER-BASMATI-HELLO", "descriptor": { "name": "Basmati 1KG — Launch Offer" }, "resourceIds": ["ITEM-BASMATI-1KG"], "offerAttributes": { "@context": "https://schema.beckn.io/RetailOffer/2.1/context.jsonld", "@type": "RetailOffer", "isActive": true } } ] } ] } }

A few things to note:

  • context.bppId and context.bppUri identify you — bppUri is informational; CATALG resolves the actual callback URL from your DeDi registry entry (see Step 5)

  • publishDirectives is an array at the message level (not inside the catalog) and is keyed to each catalog by catalogId. Use publishDirectives[].visibleTo to scope distribution to specific networks; when omitted, the catalog is distributed via the default global network nfh.global/beckn-nodes

  • resources[].resourceAttributes uses a JSON-LD @context to declare which domain schema the resource follows

  • offers[].resourceIds links the offer to one or more resources by their id; offers[].offerAttributes declares the offer schema (RetailOffer here) the same way resources do


Step 2 — Sign the request

Every publish request must carry a Beckn HTTP Signature in the Authorization header. The signature proves you hold the Ed25519 private key whose corresponding public key is registered against your participant record in the DeDi registry.

You sign and publish the request yourself — the signing flow uses your Ed25519 private key and produces a single-line header value of the form:

Authorization: Signature keyId="{subscriberId}|{recordId}|{algorithm}",algorithm="ed25519",created="{unix_timestamp}",expires="{unix_timestamp}",headers="(created) (expires) digest",signature="{base64-ed25519-signature}"

For the full structure of the header, the keyId format, and what gets signed, see API Reference → Authentication.


Step 3 — POST the catalog

Send the signed request to the CATALG endpoint of the network you are publishing to:

curl -X POST https://catalg.example.net/catalog/publish \ -H "Content-Type: application/json" \ -H "Authorization: Signature keyId=\"...\",algorithm=\"ed25519\",..." \ -d @catalog.json


Step 4 — Inspect the synchronous ACK

If the request is well-formed and your signature verifies, CATALG returns a 200 OK with an ACK:

{ "message": { "status": "ACK", "messageId": "f01e0a8a-1111-4111-8111-111111111111" } }

The messageId is echoed from your request context.messageId. The ACK means CATALG has accepted the request for processing — not that the catalog has been validated against the domain schema yet. That result arrives on the callback in the next step.

If the request is malformed, the signature fails, or you do not own the catalogId, CATALG returns a NACK with an error block in the same envelope. See API Reference → Errors for the full list.


Step 5 — Receive the on_publish callback

CATALG does not trust the bppUri carried in the request body for callback delivery. Instead, it looks up your participant record in the DeDi registry using the identity from your Authorization signature (the keyId), reads the url field from your registered entry, and appends /catalog/on_publish to it. That is the URL it POSTs to.

A registered participant entry looks like this — the url field is what CATALG uses:

{ "subscriber_id": "bpp.freshmart.local-retail.net", "type": "BPP", "url": "https://bpp.freshmart.local-retail.net/beckn/", "domain": "*", "countries": ["IND"] }

Given that entry, CATALG resolves the callback URL as:

registry.url + catalog/on_publish → https://bpp.freshmart.local-retail.net/beckn/catalog/on_publish

The /beckn/ segment is the conventional base path for Fabric-protocol endpoints on a participant's domain — catalog/on_publish is appended onto it.

The url field must therefore be a publicly reachable HTTPS endpoint and must be set correctly in DeDi during onboarding (see Onboarding Network Participants). The bppUri in your request body is informational only — the registry is the source of truth.

Once CATALG finishes processing your catalog, it POSTs the per-catalog result to that resolved URL:

{ "context": { "version": "2.0.0", "action": "catalog/on_publish", "messageId": "f01e0a8a-1111-4111-8111-111111111111", "transactionId": "f01e0a8a-2222-4222-8222-222222222222", "timestamp": "2026-06-02T10:00:02.000Z", "requestDigest": { "digest": "BLAKE-512=mB2c5x...base64..." } }, "message": { "results": [ { "catalogId": "CAT-FRESHMART-HELLO", "status": "ACCEPTED", "stats": { "itemCount": 1, "providerCount": 1, "categoryCount": 1 } } ] } }

The status field on each result is 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

When status is REJECTED or PARTIAL, each result carries an errors array describing what failed:

{ "results": [ { "catalogId": "CAT-FRESHMART-HELLO", "status": "REJECTED", "errors": [ { "code": "SCHEMA_VALIDATION_FAILED", "message": "message.catalogs[0].resources[0].resourceAttributes.@context is required" } ] } ] }


What just happened?

You sent a single POST /catalog/publish request. CATALG verified your signature, validated the structure against the Fabric v2.0 schema, verified that you own the catalogId, processed the catalog, and stored it as the source of truth for the network. It then asynchronously delivered the result to the callback URL resolved from your DeDi registry entry, and pushed the catalog out to every Discovery Service whose subscription filters matched.

A consumer application can now find your catalog by querying any Discovery Service that subscribed to your network — without that Discovery Service ever calling you directly.

Where to go next

Goal

Page

Understand the catalog model — resources, offers, master templates, update modes, ownership

Catalog Concepts

Receive catalogs as a Discovery Service

Subscription & Distribution

Look up an endpoint, field, or error code

API Reference