This document describes how a BPP adapter translates each incoming Beckn v2 action API call into one or more proprietary seller API calls, and then constructs and dispatches the corresponding Beckn callback.
BAP BPP Adapter Seller API
| | |
|── POST /beckn/select ─>| |
|<── ACK ───────────────| |
| |── GET /products/{id} ──>|
| |<─ Product ──────────────|
| |── POST /cart ──────────>|
| |<─ Cart ─────────────────|
| | |
|<── POST /on_select ───| |
|── ACK ────────────────>| |
The adapter:
- Receives a Beckn action call and immediately responds with
ACK - Asynchronously calls the seller API and translates the results
- Dispatches the
on_{action}callback tocontext.bap_uri
| Beckn Concept | Seller API Equivalent | Notes |
|---|---|---|
context.transaction_id |
transactionId on Cart and Order |
Primary session key |
beckn:Item.beckn:id |
Product.id |
Direct mapping |
beckn:Order.beckn:id |
Order.id |
Assigned by seller on confirm |
beckn:Order.beckn:seller |
Static: seller's BPP identifier | Single seller |
beckn:Offer.beckn:id |
Offer.id |
Direct mapping |
beckn:OrderItem.beckn:orderedItem |
OrderItem.productId |
Direct mapping |
The adapter maintains a transaction state store keyed on context.transaction_id to track:
- Cart association (transactionId → seller cart state)
- Order ID mapping (seller
order.id↔beckn:Order.beckn:id) - Payment ID for status tracking
- Buyer identity info (used for review attribution in
rating) - Price snapshot at
selecttime (for change detection atinit) - Partial cancellation line state (seller has no partial cancel API)
| Seller Status | Beckn beckn:orderStatus |
|---|---|
pending |
PENDING |
confirmed |
CONFIRMED |
shipped |
INPROGRESS |
delivered |
COMPLETED |
cancelled |
CANCELLED |
returned |
RETURNED |
| Seller Payment Status | Beckn beckn:paymentStatus |
|---|---|
initiated |
INITIATED |
authorized |
AUTHORIZED |
captured |
CAPTURED |
completed |
COMPLETED |
failed |
FAILED |
refunded |
REFUNDED |
| Beckn Phase | BAP Action | Seller API Operations |
|---|---|---|
| Discovery | discover |
GET /search, GET /products, GET /offers |
| Ordering | select |
Cart CRUD: GET /cart, POST /cart, PUT /cart, DELETE /cart |
init |
GET /cart, GET /products, GET /inventory |
|
confirm |
POST /orders, POST /payments/process, PUT /orders/{id}/status |
|
| Fulfillment | status |
GET /orders/{id} |
update |
PUT /orders/{id}/status, PUT /orders/{id}/return (mutation-dependent) |
|
cancel |
PUT /orders/{id}/cancel |
|
track |
GET /orders/{id} |
|
| Post-Fulfillment | support |
None (static config) |
rating |
POST /products/{id}/reviews |
Purpose: Translate a Beckn search intent into seller product queries; return a formatted catalog.
Inbound fields used:
message.text_search— free-text querymessage.filters.expression— JSONPath expression (parsed forcategory,minPrice,maxPrice, brand)message.spatial— geographic constraints (passed as hints; seller/searchdoes not natively support spatial filters)
Seller API sequence:
| Step | Call | Purpose |
|---|---|---|
| 1 | GET /search?q=&category=&minPrice=&maxPrice= |
Primary text + filter search |
| 1b | GET /products?category= |
Fallback if no text query, only category |
| 2 | GET /offers?active=true |
Fetch all active offer schemes |
JSONPath filter parsing rules:
@.category == 'X'→category=X@.price <= Y→maxPrice=Y;@.price >= X→minPrice=X@.brand == 'B'→ append toq
Catalog construction (on_discover message):
- One
beckn:Catalogfor the entire BPP (single seller) - Each
Productresult → onebeckn:Item(beckn:id = product.id) - Each active
Offer→ onebeckn:Offer(beckn:id = offer.id,beckn:items = offer.applicableProductIds) beckn:itemAttributescarries: price, currency, brand, stock, andproduct.attributeskey-value pairs- Offer
beckn:priceuses aDISCOUNTcomponent (percentageorflatdiscount value)
Purpose: Build or update the seller cart with the buyer's selected items; return a priced quote.
Inbound fields used:
context.transaction_id— cart session keymessage.order.beckn:orderItems[]— selected items with quantitybeckn:orderedItem→productIdbeckn:quantity.unitQuantity→quantitybeckn:acceptedOffer→offerId(if offer applied)
Seller API sequence:
| Step | Call | Purpose |
|---|---|---|
| 1 | GET /cart?transactionId= |
Fetch existing cart |
| 2a | GET /products/{id} |
Validate each product; get live price |
| 2b | GET /products/{id}/offers |
Get product-specific offers |
| 2c | POST /cart |
Add new items not in current cart |
| 2d | PUT /cart |
Update quantity for existing cart items |
| 2e | DELETE /cart |
Remove cart items no longer in the selection |
| 3 | GET /cart?transactionId= |
Fetch final priced cart |
Quote construction (on_select message):
- Echo
beckn:orderItemswithbeckn:pricepopulated from live product prices beckn:orderValuederived from cart total, broken into per-item UNIT price componentsbeckn:acceptedOfferspopulated if any offer is applicable and discount appliedbeckn:orderStatus: "CREATED",beckn:payment.beckn:paymentStatus: "INITIATED"
Purpose: Accept buyer and fulfillment details; validate prices and stock; return payment terms.
Inbound fields used:
message.order.beckn:buyer— buyer contact info stored in statemessage.order.beckn:fulfillment— delivery mode and shipping addressmessage.order.beckn:payment.beckn:acceptedPaymentMethod— buyer's intended payment method
Seller API sequence:
| Step | Call | Purpose |
|---|---|---|
| 1 | GET /cart?transactionId= |
Verify cart is still active |
| 2 | GET /products/{productId} (per item) |
Verify price hasn't changed since select |
| 3 | GET /inventory/{productId} (per item) |
Verify sufficient stock (available >= quantity) |
Response construction (on_init message):
- Echo order with buyer and fulfillment details
beckn:orderStatus: "PENDING"beckn:payment.beckn:paymentStatus: "INITIATED"beckn:payment.beckn:acceptedPaymentMethod: intersection of buyer's methods and seller's accepted methods (from config)beckn:payment.beckn:paymentURL: payment gateway URL (if pre-payment required, from config)- If price changed → return error payload instead;
ack_status: "NACK"or error in message
Purpose: Finalize the order, process payment, and return a confirmed order with a seller-assigned ID.
Inbound fields used:
message.order.beckn:orderItems[]— final committed itemsmessage.order.beckn:fulfillment.beckn:deliveryAttributes→ shipping addressmessage.order.beckn:payment.beckn:acceptedPaymentMethod[0]→ payment methodmessage.order.beckn:orderValue.value→ expected total
Seller API sequence:
| Step | Call | Purpose |
|---|---|---|
| 1 | POST /orders |
Create order (status: "pending") |
| 2 | POST /payments/process |
Process payment against order |
| 3 | PUT /orders/{id}/status → "confirmed" |
Confirm order on payment success |
Address mapping (fulfillment → shippingAddress):
beckn:deliveryAttributes.address.streetAddress→streetbeckn:deliveryAttributes.address.addressLocality→citybeckn:deliveryAttributes.address.addressRegion→statebeckn:deliveryAttributes.address.postalCode→zipCodebeckn:deliveryAttributes.address.addressCountry→country
Response construction (on_confirm message):
- Full order object with
beckn:id = seller_order.id(stored in adapter state) beckn:orderStatus: "CONFIRMED"beckn:payment.beckn:paymentStatus: "COMPLETED"or"CAPTURED"beckn:payment.beckn:txnRef: payment gateway reference ID from step 2 response- On payment failure: return error payload;
beckn:payment.beckn:paymentStatus: "FAILED"
Purpose: Fetch the current order state and return it in Beckn format.
Inbound fields used:
message.order.beckn:id→ resolved toseller_order.idvia adapter state
Seller API sequence:
| Step | Call | Purpose |
|---|---|---|
| 1 | GET /orders/{seller_order_id} |
Fetch full order |
Response construction (on_status message):
- Map
order.status→beckn:orderStatususing status table - If
order.trackingIdis present → includebeckn:fulfillment.trackingAction.id = order.trackingId - Payment status derived from most recent payment record (use
GET /payments/{paymentId}if payment ID is in adapter state) - Full order items echoed back with prices
Purpose: Apply a mutation to an in-flight order.
Update type detection and seller API calls:
| Mutation | Detection Heuristic | Seller API Call |
|---|---|---|
| Shipping address change | New beckn:fulfillment address in payload |
Store in adapter state (no seller update endpoint) |
| Item quantity change | beckn:orderItems quantities differ from confirmed order |
Adapter-managed state; no seller endpoint post-confirm |
| Return initiation | beckn:orderStatus == "RETURNED" or item return flag |
PUT /orders/{id}/return |
| Status override | Explicit beckn:orderStatus field on update |
PUT /orders/{id}/status (where seller status enum allows) |
Response construction (on_update message):
- Reflect the resulting order state with applied mutations
- Use adapter state for non-seller-API mutations
Purpose: Cancel a full or partial order.
Inbound fields used:
message.order.beckn:id→ seller order IDmessage.order.beckn:orderItems[](optional) → items to partially cancel
Seller API sequence:
| Scenario | Call | Purpose |
|---|---|---|
| Full cancellation | PUT /orders/{id}/cancel |
Cancel entire order |
| Partial cancellation | Adapter state update only | Mark specific lines as cancelled in state |
| All lines cancelled | PUT /orders/{id}/cancel |
Escalate to full order cancel |
Limitation: The seller API does not support partial order cancellation natively. Partial cancellations are managed entirely in adapter state. The adapter mirrors the cancelled line state in the
on_cancelcallback while keeping the order record intact in the seller system until all lines are cancelled.
Response construction (on_cancel message):
- Full order echoed with cancelled items flagged (adapter state applied)
beckn:orderStatus: "CANCELLED"(full) or"INPROGRESS"with cancelled lines (partial)- If eligible for refund →
beckn:payment.beckn:paymentStatus: "REFUNDED"
Purpose: Return a tracking handle or URL for an active shipment.
Inbound fields used:
message.tracking.id→ seller order ID (or tracking ID if pre-mapped in state)
Seller API sequence:
| Step | Call | Purpose |
|---|---|---|
| 1 | GET /orders/{seller_order_id} |
Fetch order and extract trackingId |
Response construction (on_track message):
tracking.id = order.trackingIdtracking.url = "{config.trackingBaseUrl}?trackingId={order.trackingId}"tl_method: "http/get"(redirect to tracking UI)trackingStatus: "ACTIVE"if order status isshipped;"COMPLETED"ifdelivered;"DISABLED"otherwise
Purpose: Return seller support contact details.
Seller API calls: None — support info is sourced from static seller configuration.
Response construction (on_support message):
beckn:SupportInfo:
name: config.support.name
phone: config.support.phone
email: config.support.email
url: config.support.url
hours: config.support.hours
channels: config.support.channels
Purpose: Submit buyer ratings/reviews to the seller.
Inbound fields used:
message.ratings[]— array ofRatingInputobjectsid→ entity ID being ratedratingValue→ numeric scorecategory→ITEM | ORDER | FULFILLMENT | PROVIDER | AGENTfeedback.comments→ review textfeedback.tags[]→ review tags
Seller API sequence:
| Scenario | Call | Purpose |
|---|---|---|
category == "ITEM" |
POST /products/{ratingInput.id}/reviews |
Submit product review |
category == "ORDER", "PROVIDER", "FULFILLMENT" |
None (adapter log) | No direct seller endpoint |
Review payload mapping:
productId:ratingInput.idrating:round(ratingInput.ratingValue)(seller expects integer 1–5)title:ratingInput.feedback.tags[0]or"Review"as fallbackcomment:ratingInput.feedback.commentsreviewerName: buyer display name from adapter state (stored duringinit)
Response construction (on_rating message):
received: trueaggregate.valueandaggregate.count: fromGET /products/{id}/reviewsresponse (optional enrichment)
| Error Scenario | Adapter Response |
|---|---|
Product not found (step 2a of select) |
NACK on inbound; or error object in on_select callback |
Price changed (init step 2 vs select snapshot) |
Error message in on_init; buyer must re-select |
Insufficient stock (init step 3) |
Error message in on_init |
Payment failed (confirm step 2) |
on_confirm with beckn:payment.beckn:paymentStatus: "FAILED" and error detail |
| Order cannot be cancelled (wrong status) | on_cancel with error; beckn:orderStatus unchanged |
| Order not found in seller system | NACK on inbound request |
| Seller API timeout / 5xx | NACK immediately; retry policy per adapter config |
The following values must be provided in static seller configuration:
| Config Key | Description | Used In |
|---|---|---|
config.bppId |
BPP identifier on Beckn network | All callbacks (context) |
config.bppUri |
BPP base URI | All callbacks (context) |
config.providerId |
Seller's provider ID in catalog | discover, select, on_* |
config.sellerName |
Display name of the seller | discover catalog |
config.sellerApiBase |
Seller API base URL | All seller API calls |
config.trackingBaseUrl |
Base URL for tracking page | track |
config.support.* |
Support contact details | support |
config.acceptedPaymentMethods |
Methods accepted by seller | init |
config.paymentGatewayUrl |
Payment gateway URL template | init, confirm |