Documentation

Everything you need to query and publish Business Context Manifests.

Quick Start

Query any company's BCM with a single GET request. No API key required.

# Fetch a company's full BCM from the well-known path
curl https://acme.com/.well-known/bcm.json
# Or query a specific transaction type via the registry
curl https://bcmspec.org/api/bcm/acme.com/invoice_submission

Discovery Protocol

AI agents discover BCMs using a two-step lookup, similar to how crawlers check robots.txt:

1
Check the domain directlyPrimary
GET https://<domain>/.well-known/bcm.json
2
Fall back to the registryFallback
GET https://bcmspec.org/.well-known/bcm/<domain>.json

Self-hosting your BCM at the well-known path is the canonical method. The registry serves as a fallback for companies that haven't self-hosted yet.

Well-Known Endpoint

GET /.well-known/bcm/{domain}.json

Returns all published BCMs for a domain as a single merged JSON file. Hosted by the registry at bcmspec.org.

curl https://bcmspec.org/.well-known/bcm/acme.com.json

API Reference

GET /api/bcm/{domain}/{transaction_type}
Path Parameters
domainstringCompany domain (e.g. acme.com)
transaction_typestringOne of the supported transaction types
Response Headers
X-CacheHIT or MISS
X-BCM-VersionBCM spec version

Transaction Types

invoice_submission
How to submit invoices
purchase_order
How to send POs
rfq_response
How to respond to quotes
vendor_qualification
Onboarding requirements
compliance_attestation
Compliance submissions
contract_amendment
How to request changes
delivery_confirmation
Confirming deliveries
payment_terms
Payment preferences

Discovery Lookup Order

SDKs and agents resolve BCMs using a two-step discovery protocol:

1
Self-hosted well-known

Check the company's own domain first

https://{domain}/.well-known/bcm.json
2
BCM Registry fallback

Fall back to the central registry

https://bcmspec.org/.well-known/bcm/{domain}.json

Companies can self-host by placing a bcm.json file at their /.well-known/ path. If not found, SDKs automatically query the BCM Registry.

# Query the registry's well-known endpoint directly
curl https://bcmspec.org/.well-known/bcm/acme.com.json

Well-Known Endpoint

GET /.well-known/bcm/{domain}.json
Returns a consolidated JSON object containing all published BCMs for a domain, including every transaction type in a single response.

This is the same format a company would self-host at https://{domain}/.well-known/bcm.json

SDKs & MCP Server

MCP Server
GitHub

Let Claude and AI agents query BCMs natively

claude mcp add bcm-registry -- npx -y bcm-mcp-server
Node.js SDK
GitHub

One-line BCM queries from any Node.js app

npm install bcm-spec
Python SDK
GitHub

Zero-dependency BCM queries from Python

pip install bcm-spec

Example Response

{
  "domain": "acme.com",
  "transaction_type": "invoice_submission",
  "bcm": {
    "transaction_type": "invoice_submission",
    "version": "1.0",
    "domain": "acme.com",
    "last_updated": "2025-01-15",
    "accepted_formats": ["PDF", "UBL 2.1"],
    "required_fields": [
      "po_number",
      "invoice_date",
      "line_items",
      "amount",
      "currency"
    ],
    "authority_limits": {
      "auto_approve_usd": 5000,
      "requires_manager_approval_usd": 25000
    },
    "compliance_requirements": [
      "W9_on_file",
      "MSA_signed"
    ],
    "submission_endpoint": {
      "email": "ap@acme.com",
      "preferred_channel": "email"
    },
    "response_sla": {
      "acknowledgment_hours": 4,
      "processing_hours": 48
    },
    "escalation_path": {
      "contact_email": "procurement@acme.com",
      "contact_role": "AP Manager"
    },
    "data_residency": "US"
  },
  "meta": {
    "verified": true,
    "last_updated": "2025-01-15T00:00:00.000Z",
    "version": 3
  }
}

JSON Schema

The full BCM JSON Schema is available at:

Source: BusinessContextManifest/bcm-spec

Security

Agent API Keys (Optional)

BCM queries are free and open — no API key required. Agents can optionally register to get higher rate limits and query analytics.

Agent keys use the format bcm_live_ followed by 32 hex characters (128 bits of entropy). Keys are SHA-256 hashed before storage.

Rate Limiting

The BCM query endpoint enforces 60 requests per minute per IP. Exceeding this returns 429 Too Many Requests with a Retry-After header indicating seconds until the window resets.

Audit Logging

Every sensitive operation is recorded in an append-only audit log. Logged events include: BCM publish/edit, API key creation/deletion, agent blocking, domain verification, and authentication attempts.

Each entry captures: event type, actor, target, IP address, user agent, and timestamp. Audit logs are visible in the company dashboard and cannot be deleted.

Webhook Signatures

Webhook payloads are signed with HMAC-SHA256 using your webhook secret. The signature is sent in the X-BCM-Signature header as sha256=<hex>.

Every payload includes a timestamp field. Reject events older than 5 minutes to prevent replay attacks.

Verify in Node.js
const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  const sig = signature.replace('sha256=', '');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(sig)
  );
}

// Express example
app.post('/webhooks/bcm', (req, res) => {
  const raw = JSON.stringify(req.body);
  const sig = req.headers['x-bcm-signature'];
  if (!verifyWebhook(raw, sig, process.env.BCM_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  // Check timestamp to prevent replay
  const age = Date.now() - new Date(req.body.timestamp).getTime();
  if (age > 5 * 60 * 1000) {
    return res.status(400).send('Event too old');
  }
  console.log('Event:', req.body.event, req.body.data);
  res.status(200).send('OK');
});
Verify in Python
import hmac, hashlib, json, time
from datetime import datetime

def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    sig = signature.replace('sha256=', '')
    return hmac.compare_digest(expected, sig)

# Flask example
@app.route('/webhooks/bcm', methods=['POST'])
def handle_webhook():
    raw = request.get_data()
    sig = request.headers.get('X-BCM-Signature', '')
    if not verify_webhook(raw, sig, os.environ['BCM_WEBHOOK_SECRET']):
        return 'Invalid signature', 401
    # Check timestamp to prevent replay
    payload = json.loads(raw)
    event_time = datetime.fromisoformat(payload['timestamp'].replace('Z', '+00:00'))
    age = (datetime.now(event_time.tzinfo) - event_time).total_seconds()
    if age > 300:
        return 'Event too old', 400
    print(f"Event: {payload['event']}", payload['data'])
    return 'OK', 200

CORS & Caching

All API responses include Access-Control-Allow-Origin: *

Responses are cached for 5 minutes at the edge. The X-Cache header indicates cache status.

Ready to list your company?

Free forever. Takes 2 minutes.

List your company free