BECKN ACTION · UPDATED 11 AUG 2026

search: discovery on the open network

One request, an unknown number of answers, arriving over several seconds from companies you have no relationship with. Search is where Beckn's architecture is most visible — and where a BAP's user experience is won or lost.

PART OF THE BECKN FOR EV CHARGING GUIDE · 10 ACTION & CONCEPT GUIDES

IN ONE PARAGRAPH

The BAP sends one search, usually through the gateway, which fans it out to every matching provider. Each BPP acknowledges immediately and POSTs its catalogue back later as on_search. There is no response count and no completion signal, so the BAP renders results as they stream in and closes the window on a timer.

The async pair

The BAP sends search — usually to the gateway, which fans it out to registered BPPs. Each BPP responds 200 ACK immediately and later POSTs its catalogue to the BAP's bap_uri as on_search.

// BAP -> gateway / BPPs
POST /search
{
  "context": {
    "domain": "ev-charging:uei",
    "action": "search",
    "version": "1.1.0",
    "location": { "country": { "code": "IND" }, "city": { "code": "std:0120" } },
    "bap_id": "emsp.example.com",
    "bap_uri": "https://emsp.example.com/beckn",
    "transaction_id": "txn-4471",
    "message_id": "msg-9021",
    "timestamp": "2026-08-11T09:00:00Z",
    "ttl": "PT10S"
  },
  "message": {
    "intent": {
      "fulfillment": {
        "stops": [{
          "location": {
            "circle": {
              "gps": "28.6270,77.3721",
              "radius": { "value": "5", "unit": "km" }
            }
          }
        }]
      },
      "item": { "descriptor": { "code": "energy" } }
    }
  }
}

And later, independently, from each provider:

// BPP -> BAP callback
POST https://emsp.example.com/beckn/on_search
{
  "context": { "...": "same transaction_id and message_id",
               "action": "on_search", "bpp_id": "cpo.electreefi.in",
               "bpp_uri": "https://cpo.electreefi.in/beckn" },
  "message": {
    "catalog": {
      "providers": [{
        "id": "EFI",
        "descriptor": { "name": "ElectreeFi Charging" },
        "locations": [{ "id": "LOC-ND-014", "gps": "28.6270,77.3721" }],
        "items": [{
          "id": "EVSE-014-02",
          "descriptor": { "name": "Sector 62 Hub - 60kW CCS2" },
          "location_ids": ["LOC-ND-014"],
          "price": { "value": "18.50", "currency": "INR/kWh" },
          "tags": [{
            "descriptor": { "code": "connector" },
            "list": [
              { "descriptor": { "code": "type" },   "value": "CCS2"      },
              { "descriptor": { "code": "power" },  "value": "60kW"      },
              { "descriptor": { "code": "status" }, "value": "AVAILABLE" }
            ]
          }]
        }]
      }]
    }
  }
}

The intent object

intent is a description of what the buyer wants, deliberately loose. A BPP matches against whatever it understands and ignores the rest, which is what allows providers with different capabilities to answer the same search.

Intent elementExpressesTypical EV use
fulfillment.stops[].location.circleGeographic areaGPS point plus radius — the most common filter
item.descriptor.codeWhat is being boughtenergy
fulfillment.stops[].timeWhenPlanned arrival, for future booking
item.tagsItem characteristicsConnector type, minimum power
provider.descriptorA specific providerSearching one known operator
Over-constraining an intent shrinks your results silently. A BPP that cannot interpret a filter may return nothing rather than returning everything. Filter broadly at the protocol level and narrow client-side — you will show the driver more chargers, and you keep control of the ranking.

Implementing it without pain

  • Correlate on transaction_id + message_id + bpp_id. Multiple BPPs answer one search over seconds, all sharing the first two fields. Keying on message_id alone means each catalogue overwrites the last — see the context object.
  • Never block. The BAP aggregates as callbacks arrive. There is no completion signal and no expected count.
  • Set a UX budget: render as results stream in, close at roughly 3–5 seconds. A driver will not wait for the slowest participant on the network.
  • BPP side: answer from a pre-built catalogue cache, not a live database fan-out. Search volume on an open network is not under your control.
  • Validate signatures on every callback. The registry says who may speak; the signature proves who did. See signing and the registry.

What to do with the results

Raw catalogues are not a driver-facing list. Four things happen between callback and screen:

  1. Deduplicate. The same physical site can arrive from more than one BPP where a CPO is reachable through multiple aggregators. Match on location and connector rather than on ID, since IDs differ per provider.
  2. Normalise price. Providers quote differently — per kWh, per minute, with or without tax. Comparing them requires converting to a common basis, and showing an inconsistent basis to a driver is worse than showing none.
  3. Rank deliberately. Distance, price, power and availability all matter, and the weighting is a product decision. Arrival order is not a ranking.
  4. Age the availability. Catalogue status is a snapshot from when the BPP answered. By the time the driver taps, it may be stale — which is why select re-checks.

After search

Discovery flows into the transaction chain: select confirms the item and returns a quote, init and confirm create the booking, then update and status track the session — each with its on_* callback twin, each correlated by the same transaction_id.

The search pattern you build first becomes the template for everything after it: send, acknowledge, wait for a callback, correlate, expire on TTL. Get the plumbing right here and the remaining six actions are variations on it.

Frequently asked questions

How does Beckn search work?

The BAP sends one search request, usually to the gateway, which forwards it to every BPP subscribed to that domain and location. Each BPP acknowledges immediately and later POSTs its catalogue back to the BAP's callback address as on_search.

How does a BAP know when all Beckn search results have arrived?

It does not. There is no response count and no completion signal, and some providers never answer. A BAP renders results progressively as callbacks arrive and closes the window on a timer, typically three to five seconds.

How do you correlate multiple on_search callbacks?

On transaction_id, message_id and bpp_id together. All responses to one search share the same transaction_id and message_id, so bpp_id is what distinguishes them. Keying on message_id alone causes each provider's catalogue to overwrite the previous one.

Should a BPP answer Beckn search from a live database?

No. Broadcast search volume on an open network is not under the provider's control, so catalogues should be served from a pre-built cache. A live database fan-out per search will not survive network growth.

Why should a Beckn search intent be loosely constrained?

Because a BPP that cannot interpret a filter may return nothing rather than everything. Filtering broadly at the protocol level and narrowing client-side surfaces more chargers to the driver and keeps ranking under the buyer app's control.