What is the outlets.bd public API?
In summary, a REST + webhook API at https://api.outlets.bd/v1 that exposes verified retail outlet data for Bangladesh — cursor pagination, district and status filters, CORS-enabled JSON responses, per-key rate limits, and HMAC-SHA256-signed webhooks for verification events.
- Base URL: https://api.outlets.bd/v1
- Auth: Authorization: Bearer <key>; keys are owner-scoped, rotate atomically.
- Rate limits: per key, surfaced in X-RateLimit-* headers.
- Webhooks: HMAC-SHA256 signed, exponential-backoff retry, auto-disable on repeated failure.
- Errors: { error: { code, message, request_id } } envelope with standard HTTP status.
Build on Bangladesh's
verified retail network.
REST endpoints + signed webhooks for outlets, verifications, and district aggregates. v1 ships to early-access partners first.
OpenAPI 3.0 (excerpt)
openapi: 3.0.3
info:
title: outlets.bd API
version: 0.1.0-preview
servers:
- url: https://api.outlets.bd/v1
paths:
/outlets:
get:
summary: List verified outlets
parameters:
- name: district
in: query
schema: { type: string }
- name: status
in: query
schema: { type: string, enum: [pending, approved, rejected] }
responses:
'200':
description: A page of outlets
/outlets/{id}/verifications:
post:
summary: Submit a geo-stamped verification
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [lat, lng]
properties:
lat: { type: number }
lng: { type: number }
accuracy_m: { type: number }
photo_url: { type: string, format: uri }
notes: { type: string }
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWTPublic API v1 — live
curl https://outlets.bd/api/public/v1/outlets?district=Dhaka&limit=25 \
-H "Authorization: Bearer otl_live_..."
# 200
{
"data": [
{
"id": "8c1d...",
"name": "Karim General Store",
"district": "Dhaka",
"address": "…",
"lat": 23.8069,
"lng": 90.3687,
"status": "approved",
"updated_at": "2026-06-10T12:00:00Z"
}
],
"next_cursor": "MjAyNi0wNi0xMFQxMjowMDowMFp8OGMxZC4uLg",
"rate_limit": { "limit": 60, "remaining": 42, "reset_at": "…" }
}
# Errors: 400 invalid_query | 401 unauthorized | 429 rate_limited | 500 internal_error
# Response envelope: { "error": { "code": "…", "message": "…" } }Sample webhook delivery
POST https://your-app.example.com/webhooks/outlets
content-type: application/json
x-outlets-event: outlet.verified
x-outlets-delivery: 7c9f2b1e-...
x-outlets-timestamp: 1717000000
x-outlets-signature: t=1717000000,v1=<hmac_sha256_hex>
{
"id": "d5c...",
"event": "outlet.verified",
"created_at": "2026-06-10T12:00:00Z",
"data": {
"outlet": {
"id": "8c1d...",
"name": "Karim General Store",
"district": "Dhaka",
"lat": 23.8069,
"lng": 90.3687,
"status": "approved"
},
"verification_id": "…",
"decided_at": "2026-06-10T12:00:00Z"
}
}Verify a webhook signature
// Verify a webhook (Node)
import { createHmac, timingSafeEqual } from "crypto";
function verify(rawBody, header, secret) {
const [tPart, vPart] = header.split(",");
const t = tPart.split("=")[1];
const v1 = vPart.split("=")[1];
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
return timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Get an API key
Join the developer waitlist for sandbox access.