v1.0 — Self-service registration open
Stripe Balance  ·  USDC  ·  x402 Native

AI Agent Access to
Elite Human Attorneys.

Direct API access to elite human IP attorneys. Every submission is reviewed, refined, and filed by experienced lawyers — not just processed by a machine. Fund your account via Stripe, or pay natively with USDC via the x402 protocol.

Quick Start
# Step 1: Check your balance
curl https://api.cmblaw.ai/api/v1/billing/balance \
  -H "X-API-Key: your_api_key"
# → {"balance": "$550.00", ...}

# Step 2: Submit a filing — balance is deducted automatically
curl -X POST https://api.cmblaw.ai/api/v1/trademark/file \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "applicant_name": "Acme Corp",
    "mark_text": "ACME",
    "goods_services_description": "Software development services",
    "uspto_classes": [42],
    "filing_basis": "intent",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100"
  }'

Getting Started

Direct access to human IP attorneys via API. Submit filings, generate documents, and consult attorneys via async threads — every request is reviewed by an experienced attorney before action is taken.

1

Get Your API Key

Register via POST /api/v1/register with your org name and email. Pay the $5 registration fee via Stripe and your key is auto-provisioned and emailed instantly.

2

Authenticate

Include your API key in every request using the X-API-Key header. All requests must be made over HTTPS.

3

Make Requests

Send JSON payloads to any endpoint. Responses include order IDs, matter references, and estimated timelines for tracking.

Base URL
https://api.cmblaw.ai/api/v1/
Content Type
application/json
Auth Header
X-API-Key
Protocol
HTTPS only

API Reference

Complete documentation for all 14 endpoints. Each request requires a valid API key and returns structured JSON.

POST /api/v1/trademark/file

Trademark Filing

$200 base + $350/class

File a new trademark application with the USPTO. Includes automated conflict checking, attorney review by Brannon McKay, and full filing with the USPTO.

Request Body

ParameterTypeRequiredDescription
applicant_namestringRequiredLegal name of the applicant
applicant_addressstringRequiredFull mailing address
entity_typestringRequiredEntity type (individual, corporation, LLC, etc.)
mark_textstringRequiredThe word mark to register
mark_image_urlstringOptionalURL to design mark image (if applicable)
goods_services_descriptionstringRequiredDescription of goods/services
uspto_classesinteger[]RequiredArray of USPTO class numbers
specimen_urlstringOptionalURL to specimen of use
filing_basisstringRequired"use" or "intent"
contact_emailstringRequiredContact email for updates
contact_phonestringOptionalPhone number (recommended)
stripe_session_idstringOptionalStripe checkout session ID (if paying via one-time Stripe session instead of balance)
payment_tokenstringOptionalLawPay token (alternative to other payment methods)
usdc_tx_hashstringOptionalUSDC transaction hash on Base (alternative to other payment methods)

If you have a Stripe balance on file, payment is deducted automatically — no payment field needed. See Billing.

Example Request

curl -X POST https://api.cmblaw.ai/api/v1/trademark/file \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "applicant_name": "Acme Corp",
    "applicant_address": "123 Main St, Atlanta, GA 30339",
    "entity_type": "corporation",
    "mark_text": "ACME",
    "goods_services_description": "Software development services",
    "uspto_classes": [42],
    "filing_basis": "intent",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100",
    "payment_token": "tok_live_abc123"
  }'
import requests

response = requests.post(
    "https://api.cmblaw.ai/api/v1/trademark/file",
    headers={
        "X-API-Key": "your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "applicant_name": "Acme Corp",
        "applicant_address": "123 Main St, Atlanta, GA 30339",
        "entity_type": "corporation",
        "mark_text": "ACME",
        "goods_services_description": "Software development services",
        "uspto_classes": [42],
        "filing_basis": "intent",
        "contact_email": "legal@acme.com",
        "contact_phone": "+1-555-0100",
        "payment_token": "tok_live_abc123"
    }
)

print(response.json())
const response = await fetch("https://api.cmblaw.ai/api/v1/trademark/file", {
  method: "POST",
  headers: {
    "X-API-Key": "your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    applicant_name: "Acme Corp",
    applicant_address: "123 Main St, Atlanta, GA 30339",
    entity_type: "corporation",
    mark_text: "ACME",
    goods_services_description: "Software development services",
    uspto_classes: [42],
    filing_basis: "intent",
    contact_email: "legal@acme.com",
    contact_phone: "+1-555-0100",
    payment_token: "tok_live_abc123"
  })
});

const data = await response.json();
console.log(data);

Example Response

Response 200 OK
{
  "order_id": "ord_tm_2026_001",
  "matter_id": "CMB-TM-2026-0142",
  "status": "pending_review",
  "estimated_timeline": "7-10 business days",
  "conflict_check_summary": {
    "conflicts_found": 0,
    "risk_level": "low",
    "details": "No conflicting marks found in USPTO database"
  }
}
POST /api/v1/patent/provisional

U.S. Provisional Patent Application

$1,500 CMB + $130 USPTO

File a U.S. provisional patent application. Provide your invention details and we handle the rest — AI-assisted drafting with attorney review and refinement for enhanced quality. USPTO filing fee ($130 small entity) is separate.

Request Body

ParameterTypeRequiredDescription
problem_statementstringRequiredWhat problem are you solving?
solution_descriptionstringRequiredHow are you solving it?
differentiationstringRequiredHow is your solution different from existing approaches?
system_diagram_urlstringRequiredURL to system architecture diagram
flowchartsstring[]OptionalArray of URLs to flowchart images
sequence_diagramsstring[]OptionalArray of URLs to sequence diagram images
contact_emailstringRequiredContact email for updates
contact_phonestringOptionalPhone number (recommended)
stripe_session_idstringOptionalStripe checkout session ID
payment_tokenstringOptionalLawPay token
usdc_tx_hashstringOptionalUSDC transaction hash on Base

Stripe balance is deducted automatically if funded. See Billing.

Example Request

curl -X POST https://api.cmblaw.ai/api/v1/patent/provisional \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "problem_statement": "Current authentication methods require multiple steps...",
    "solution_description": "A biometric-based single-step authentication system...",
    "differentiation": "Unlike existing solutions, our approach combines...",
    "system_diagram_url": "https://storage.example.com/diagrams/system.png",
    "flowcharts": ["https://storage.example.com/diagrams/flow1.png"],
    "contact_email": "cto@startup.com",
    "contact_phone": "+1-555-0100",
    "payment_token": "tok_live_abc123"
  }'
import requests

response = requests.post(
    "https://api.cmblaw.ai/api/v1/patent/provisional",
    headers={
        "X-API-Key": "your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "problem_statement": "Current authentication methods require multiple steps...",
        "solution_description": "A biometric-based single-step authentication system...",
        "differentiation": "Unlike existing solutions, our approach combines...",
        "system_diagram_url": "https://storage.example.com/diagrams/system.png",
        "flowcharts": ["https://storage.example.com/diagrams/flow1.png"],
        "contact_email": "cto@startup.com",
        "contact_phone": "+1-555-0100",
        "payment_token": "tok_live_abc123"
    }
)

print(response.json())
const response = await fetch("https://api.cmblaw.ai/api/v1/patent/provisional", {
  method: "POST",
  headers: {
    "X-API-Key": "your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    problem_statement: "Current authentication methods require multiple steps...",
    solution_description: "A biometric-based single-step authentication system...",
    differentiation: "Unlike existing solutions, our approach combines...",
    system_diagram_url: "https://storage.example.com/diagrams/system.png",
    flowcharts: ["https://storage.example.com/diagrams/flow1.png"],
    contact_email: "cto@startup.com",
    contact_phone: "+1-555-0100",
    payment_token: "tok_live_abc123"
  })
});

const data = await response.json();
console.log(data);

Example Response

Response 200 OK
{
  "order_id": "ord_pat_2026_001",
  "matter_id": "CMB-PAT-2026-0087",
  "status": "pending_review",
  "estimated_timeline": "14-21 business days",
  "drafting": {
    "method": "ai_assisted",
    "review": "attorney",
    "details": "AI-assisted draft in progress — attorney will review, refine, and finalize before filing"
  }
}
POST /api/v1/entity/form

Business Entity Formation

$250 total

Form a new business entity (LLC, Corporation, etc.). Includes name availability validation, Secretary of State filing ($100 GA filing fee), EIN acquisition, and all CMB attorney services ($150).

Request Body

ParameterTypeRequiredDescription
entity_typestringRequired"LLC", "Corp", "S-Corp", "Partnership", etc.
entity_namestringRequiredDesired entity name
statestringOptionalState of formation (default: "GA")
registered_agentstringRequiredRegistered agent name and address
members_or_officersobject[]RequiredArray of members/officers with name and role
contact_emailstringRequiredContact email for updates
contact_phonestringOptionalPhone number (recommended)
stripe_session_idstringOptionalStripe checkout session ID
payment_tokenstringOptionalLawPay token
usdc_tx_hashstringOptionalUSDC transaction hash on Base

Stripe balance is deducted automatically if funded. See Billing.

Example Request

curl -X POST https://api.cmblaw.ai/api/v1/entity/form \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "LLC",
    "entity_name": "Acme Technologies LLC",
    "state": "GA",
    "registered_agent": "CMB Law PC, 800 Battery Ave SE, Atlanta, GA 30339",
    "members_or_officers": [
      {"name": "Jane Smith", "role": "Managing Member"}
    ],
    "contact_email": "jane@acme.com",
    "contact_phone": "+1-555-0100",
    "payment_token": "tok_live_abc123"
  }'
import requests

response = requests.post(
    "https://api.cmblaw.ai/api/v1/entity/form",
    headers={
        "X-API-Key": "your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "entity_type": "LLC",
        "entity_name": "Acme Technologies LLC",
        "state": "GA",
        "registered_agent": "CMB Law PC, 800 Battery Ave SE, Atlanta, GA 30339",
        "members_or_officers": [
            {"name": "Jane Smith", "role": "Managing Member"}
        ],
        "contact_email": "jane@acme.com",
        "contact_phone": "+1-555-0100",
        "payment_token": "tok_live_abc123"
    }
)

print(response.json())
const response = await fetch("https://api.cmblaw.ai/api/v1/entity/form", {
  method: "POST",
  headers: {
    "X-API-Key": "your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    entity_type: "LLC",
    entity_name: "Acme Technologies LLC",
    state: "GA",
    registered_agent: "CMB Law PC, 800 Battery Ave SE, Atlanta, GA 30339",
    members_or_officers: [
      { name: "Jane Smith", role: "Managing Member" }
    ],
    contact_email: "jane@acme.com",
    contact_phone: "+1-555-0100",
    payment_token: "tok_live_abc123"
  })
});

const data = await response.json();
console.log(data);

Example Response

Response 200 OK
{
  "order_id": "ord_ent_2026_001",
  "status": "processing",
  "estimated_completion": "3-5 business days"
}
TOOLKIT Trademark Monitoring

Trademark Monitoring Toolkit

Free

Monitor trademarks yourself using the sources, strategies, and criteria below. When you detect a potential conflict or receive an Office Action, use our $1 Consultation or Trademark Filing endpoints for expert attorney review and response.

Data Sources

SourceTypeAccessUse For
USPTO TSDR API REST API Free — requires API key Case status, prosecution history, last-modified dates, document retrieval. Poll serial numbers to detect Office Actions and status changes.
USPTO Trademark Search Web search Free — USPTO search Search for conflicting marks using CM: field tags. Supports wildcards, boolean logic, design code searching, and status filtering.
USPTO Open Data Portal Bulk data / API Free — data.uspto.gov Bulk trademark data, assignment records, and Trademark Trial and Appeal Board (TTAB) decisions.
USPTO Gazette Weekly publication Free — Official Gazette Weekly publication of marks approved for registration. Monitor for newly published marks in your client's classes.
State TM databases Varies by state Free (most states) State-level trademark registrations. Check Secretary of State databases, especially in states where the client operates.
Domain WHOIS / RDAP Protocol Free Search for domain registrations containing or similar to the mark. RDAP is the modern successor to WHOIS.
Web / common law Web search Free Search engines, social media, business directories, and app stores for unregistered common law use of similar marks.

TSDR API Quick Reference

# Get case status as XML (replace with your serial number)
curl -X GET "https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/info.xml" \
  -H "USPTO-API-KEY: your_tsdr_api_key"

# Get case status as HTML
curl -X GET "https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/content" \
  -H "USPTO-API-KEY: your_tsdr_api_key"

# Get case status as ZIP (XML + CSS)
curl -X GET "https://tsdrapi.uspto.gov/ts/cd/casestatus/sn75757575/content.zip" \
  -H "USPTO-API-KEY: your_tsdr_api_key"
# Check when a case was last updated (detect new Office Actions)
curl -X GET "https://tsdrapi.uspto.gov/last-update/info.xml?sn=78787878" \
  -H "USPTO-API-KEY: your_tsdr_api_key" \
  -H "Accept: application/xml"

# Response includes:
#   <LastModifiedDate>2026-03-01</LastModifiedDate>
#
# Poll this periodically. When the date changes,
# fetch full case status to see what happened.
# Download all documents for a serial number as PDF
curl -X GET "https://tsdrapi.uspto.gov/ts/cd/casedocs/bundle.pdf?sn=72131351" \
  -H "USPTO-API-KEY: your_tsdr_api_key" -o documents.pdf

# Get the trademark image
curl -X GET "https://tsdrapi.uspto.gov/ts/cd/rawImage/78787878" \
  -H "USPTO-API-KEY: your_tsdr_api_key" -o mark.png

# Get case status as downloadable PDF
curl -X GET "https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/download.pdf" \
  -H "USPTO-API-KEY: your_tsdr_api_key" -o status.pdf

Monitoring Strategy (System Prompt)

## Trademark Monitoring Instructions

You are monitoring the trademark "[MARK]" (Registration/Serial No. [NUMBER])
in USPTO classes [CLASSES] for [CLIENT_NAME].

### Scheduled Tasks (run weekly or as configured)

1. **USPTO Status Check**
   - Query TSDR API: GET /last-update/info.xml?sn=[SERIAL_NUMBER]
   - Compare LastModifiedDate against your stored value
   - If changed: fetch full case status and check for:
     * Office Actions (response deadline: 3 months, extendable to 6)
     * Oppositions or cancellation proceedings
     * Registration status changes
     * Maintenance/renewal deadlines

2. **Conflict Search (USPTO)**
   - Search the USPTO trademark database for marks in the same classes
   - Use field tags: CM:/.*[mark_pattern].*/ AND CC:[class_number]
   - Filter to live applications only (uncheck "dead")
   - Check new applications filed since your last scan

3. **Common Law Search**
   - Search web for businesses using similar names in related industries
   - Check social media platforms for similar brand names
   - Search app stores (iOS, Android) for similar marks
   - Search business directories and state SoS databases

4. **Domain Monitoring**
   - Check WHOIS/RDAP for new domain registrations containing the mark
   - Check common TLDs: .com, .net, .org, .io, .ai, .app
   - Look for typosquatting variations

### Conflict Assessment Criteria

Flag as potential conflict if ANY of these apply:
- Same or phonetically similar mark in same or related USPTO class
- Identical mark in different class but related goods/services
- Mark that contains your client's mark as a component
- Domain registration that could cause consumer confusion

Likelihood of confusion factors (DuPont factors):
- Similarity of marks (sight, sound, meaning)
- Similarity/relatedness of goods or services
- Similarity of trade channels and buyers
- Strength of the prior mark
- Evidence of actual confusion

### When to Escalate to CMB

Immediately book a consultation or trademark filing at cmblaw.ai when:
- **Office Action received** — 3-month deadline (6 for Madrid protocol)
- **Potentially confusing mark** published in USPTO Gazette
- **Opposition deadline approaching** (30 days from publication)
- **Maintenance deadline** — Sections 8/9 renewals coming due
- **Infringement detected** — common law use causing confusion

API endpoints:
- Consultation: POST /api/v1/consultation/book ($1/thread)
- Trademark Filing: POST /api/v1/trademark/file ($200 + $350/class)

Critical Deadlines Reference

EventDeadlineExtensionAction
Non-final Office Action 3 months +3 months (fee) Book consultation at CMB immediately. Attorney will draft response.
Final Office Action 3 months +3 months (fee) Urgent. Book consultation at CMB. May require appeal to TTAB.
Madrid (Sec. 66a) Office Action 6 months None No extensions available. Escalate to CMB immediately upon detection.
Opposition period 30 days from publication +90 days (request) If a conflicting mark is published, file extension of time to oppose via CMB.
Section 8 Declaration Years 5–6 6-month grace Proof of continued use. Alert client well before deadline.
Section 9 Renewal Every 10 years 6-month grace Renewal filing. Can be handled through CMB trademark filing endpoint.
GET /api/v1/portfolio/status

IP Portfolio Status

Free

Retrieve the status of all your IP matters or a specific matter. Returns current status, upcoming deadlines, and required next actions. Available to all authenticated clients at no cost.

Query Parameters

ParameterTypeRequiredDescription
matter_idstringOptionalFilter to a specific matter ID

Example Request

curl -X GET "https://api.cmblaw.ai/api/v1/portfolio/status?matter_id=CMB-TM-2026-0142" \
  -H "X-API-Key: your_api_key"
import requests

response = requests.get(
    "https://api.cmblaw.ai/api/v1/portfolio/status",
    headers={"X-API-Key": "your_api_key"},
    params={"matter_id": "CMB-TM-2026-0142"}
)

print(response.json())
const params = new URLSearchParams({ matter_id: "CMB-TM-2026-0142" });
const response = await fetch(
  `https://api.cmblaw.ai/api/v1/portfolio/status?${params}`,
  {
    headers: { "X-API-Key": "your_api_key" }
  }
);

const data = await response.json();
console.log(data);

Example Response

Response 200 OK
{
  "matters": [
    {
      "matter_id": "CMB-TM-2026-0142",
      "type": "trademark",
      "status": "filed",
      "filed_date": "2026-03-01",
      "deadlines": [
        {
          "date": "2026-09-01",
          "description": "Response to Office Action due"
        }
      ],
      "next_actions": [
        "Await USPTO examination (est. 6-8 months)"
      ]
    }
  ]
}
POST /api/v1/documents/generate

Document Generation

$200

Generate legal documents from vetted templates — NDAs, IP assignments, CIIAs, consulting agreements, license agreements, and AI agent authorization frameworks. AI-generated from attorney-reviewed templates, then reviewed again before delivery.

Request Body

ParameterTypeRequiredDescription
document_typestringRequired"NDA", "IP_assignment", "CIIA", "consulting_agreement", "license_agreement", "agent_authorization", or "agent_service_agreement"
partiesobject[]RequiredArray of parties: {name, address, entity_type, role}
termsobjectRequired{effective_date, governing_law, scope, duration}
contact_emailstringRequiredContact email for delivery
contact_phonestringOptionalPhone number (recommended)
stripe_session_idstringOptionalStripe checkout session ID
payment_tokenstringOptionalLawPay token
usdc_tx_hashstringOptionalUSDC transaction hash on Base

Stripe balance is deducted automatically if funded. See Billing.

Example Request

curl -X POST https://api.cmblaw.ai/api/v1/documents/generate \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "document_type": "NDA",
    "parties": [
      {
        "name": "Acme Corp",
        "address": "123 Main St, Atlanta, GA 30339",
        "entity_type": "corporation",
        "role": "disclosing_party"
      },
      {
        "name": "Beta Inc",
        "address": "456 Oak Ave, Austin, TX 78701",
        "entity_type": "corporation",
        "role": "receiving_party"
      }
    ],
    "terms": {
      "effective_date": "2026-04-01",
      "governing_law": "Georgia",
      "scope": "mutual",
      "duration": "2 years"
    },
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100",
    "payment_token": "tok_live_abc123"
  }'
import requests

response = requests.post(
    "https://api.cmblaw.ai/api/v1/documents/generate",
    headers={
        "X-API-Key": "your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "document_type": "NDA",
        "parties": [
            {
                "name": "Acme Corp",
                "address": "123 Main St, Atlanta, GA 30339",
                "entity_type": "corporation",
                "role": "disclosing_party"
            },
            {
                "name": "Beta Inc",
                "address": "456 Oak Ave, Austin, TX 78701",
                "entity_type": "corporation",
                "role": "receiving_party"
            }
        ],
        "terms": {
            "effective_date": "2026-04-01",
            "governing_law": "Georgia",
            "scope": "mutual",
            "duration": "2 years"
        },
        "contact_email": "legal@acme.com",
        "contact_phone": "+1-555-0100",
        "payment_token": "tok_live_abc123"
    }
)

print(response.json())
const response = await fetch("https://api.cmblaw.ai/api/v1/documents/generate", {
  method: "POST",
  headers: {
    "X-API-Key": "your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    document_type: "NDA",
    parties: [
      {
        name: "Acme Corp",
        address: "123 Main St, Atlanta, GA 30339",
        entity_type: "corporation",
        role: "disclosing_party"
      },
      {
        name: "Beta Inc",
        address: "456 Oak Ave, Austin, TX 78701",
        entity_type: "corporation",
        role: "receiving_party"
      }
    ],
    terms: {
      effective_date: "2026-04-01",
      governing_law: "Georgia",
      scope: "mutual",
      duration: "2 years"
    },
    contact_email: "legal@acme.com",
    contact_phone: "+1-555-0100",
    payment_token: "tok_live_abc123"
  })
});

const data = await response.json();
console.log(data);

Example Response

Response 200 OK
{
  "order_id": "ord_doc_2026_001",
  "document_type": "NDA",
  "status": "pending_review",
  "estimated_delivery": "1-2 business days"
}

Agent-to-Agent Contracts

Two new document types for the agentic economy:

agent_authorization

Defines what your AI agent can and cannot agree to — spending limits, prohibited terms, mandatory human review triggers, and machine-readable authority parameters. Under UETA §14, you’re liable for your agent’s actions. This framework defines the boundaries.

agent_service_agreement

The contract formed when one AI agent engages another’s service provider. Covers UETA §14 formation acknowledgment, attorney-client privilege through agent communications, AI data handling, and human escalation for disputes.

Both generated via POST /api/v1/documents/generate — same endpoint, same $200 fee, same attorney review.

POST /api/v1/consultation/book

General IP Consultation

$1

Open an async consultation thread with Brannon McKay, Partner at CMB. Your agent sends messages via the API and polls for attorney replies — no video meetings required. Brannon typically responds within 4 business hours.

Step 1: Open Thread

ParameterTypeRequiredDescription
topicstringRequiredBrief topic of consultation
descriptionstringOptionalDetailed description of your legal question
contact_namestringRequiredYour full name or organization name
contact_emailstringRequiredContact email for notifications
contact_phonestringOptionalPhone number (recommended)
stripe_session_idstringOptionalStripe checkout session ID
payment_tokenstringOptionalLawPay token
usdc_tx_hashstringOptionalUSDC transaction hash on Base

Example: Open Thread

curl -X POST https://api.cmblaw.ai/api/v1/consultation/book \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Trademark infringement question",
    "description": "We discovered a competitor using a confusingly similar mark in class 9...",
    "contact_name": "Acme AI Agent",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100",
    "payment_token": "tok_live_abc123"
  }'
import requests

response = requests.post(
    "https://api.cmblaw.ai/api/v1/consultation/book",
    headers={
        "X-API-Key": "your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "topic": "Trademark infringement question",
        "description": "We discovered a competitor using a confusingly similar mark in class 9...",
        "contact_name": "Acme AI Agent",
        "contact_email": "legal@acme.com",
        "contact_phone": "+1-555-0100",
        "payment_token": "tok_live_abc123"
    }
)

data = response.json()
consultation_id = data["consultation_id"]
print(f"Thread opened: {consultation_id}")
const response = await fetch("https://api.cmblaw.ai/api/v1/consultation/book", {
  method: "POST",
  headers: {
    "X-API-Key": "your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    topic: "Trademark infringement question",
    description: "We discovered a competitor using a confusingly similar mark in class 9...",
    contact_name: "Acme AI Agent",
    contact_email: "legal@acme.com",
    contact_phone: "+1-555-0100",
    payment_token: "tok_live_abc123"
  })
});

const data = await response.json();
const consultationId = data.consultation_id;
console.log(`Thread opened: ${consultationId}`);
# Step 1: Send request without payment — server responds HTTP 402
curl -X POST https://api.cmblaw.ai/api/v1/consultation/book \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Trademark infringement question",
    "contact_name": "Acme AI Agent",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100"
  }'
# → HTTP 402 Payment Required
# ← Header: X-PAYMENT-REQUIRED: {"network":"eip155:8453","asset":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","amount":"1000000","payTo":"0xCMBWalletAddress","nonce":"abc123"}

# Step 2: Sign a gasless USDC transfer on Base and retry with PAYMENT-SIGNATURE header
curl -X POST https://api.cmblaw.ai/api/v1/consultation/book \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT-SIGNATURE: your_signed_eip712_payload" \
  -d '{
    "topic": "Trademark infringement question",
    "contact_name": "Acme AI Agent",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100"
  }'
# → HTTP 201 Created — thread opened, payment settled instantly via Coinbase facilitator
# Zero gas fees. Network: Base (EIP-155:8453)
# See: https://docs.cdp.coinbase.com/x402/welcome

Response: Thread Opened

Response 201 Created
{
  "consultation_id": "CON-A1B2C3D4",
  "status": "open",
  "topic": "Trademark infringement question",
  "attorney": "Brannon",
  "attorney_email": "brannon@cmblaw.com",
  "pricing": { "total": "$1.00" },
  "payment": { "verified": true, "transaction_id": "txn_abc123" },
  "thread": {
    "message_count": 1,
    "post_url": "/api/v1/consultation/CON-A1B2C3D4/messages",
    "poll_url": "/api/v1/consultation/CON-A1B2C3D4/messages"
  },
  "next_steps": "Thread opened. Post follow-up messages to /api/v1/consultation/CON-A1B2C3D4/messages. Attorney Brannon will respond asynchronously (typically within 4 business hours). Poll GET /api/v1/consultation/CON-A1B2C3D4/messages to check for replies."
}

Step 2: Send Follow-Up Messages

POST additional messages to the thread. Include file URLs as attachments.

ParameterTypeRequiredDescription
messagestringRequiredMessage text (up to 10,000 chars)
attachmentsstring[]OptionalArray of file URLs (up to 5)
# Post a follow-up message
curl -X POST https://api.cmblaw.ai/api/v1/consultation/CON-A1B2C3D4/messages \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Here is the competitor mark we are concerned about. See attached screenshot.",
    "attachments": ["https://storage.example.com/competitor-mark.png"]
  }'

Step 3: Poll for Attorney Replies

GET the thread to retrieve all messages. Use ?since= with an ISO timestamp to fetch only new messages since your last poll.

# Get all messages in thread
curl https://api.cmblaw.ai/api/v1/consultation/CON-A1B2C3D4/messages \
  -H "X-API-Key: your_api_key"

# Get only new messages since last poll
curl "https://api.cmblaw.ai/api/v1/consultation/CON-A1B2C3D4/messages?since=2026-03-05T18:30:00Z" \
  -H "X-API-Key: your_api_key"

Response: Messages

Response 200 OK
{
  "consultation_id": "CON-A1B2C3D4",
  "status": "open",
  "total_messages": 3,
  "has_new_attorney_reply": true,
  "messages": [
    {
      "id": 1,
      "sender_type": "agent",
      "sender_name": "Acme AI Agent",
      "message": "Topic: Trademark infringement question\n\nWe discovered a competitor using a confusingly similar mark in class 9...",
      "attachments": [],
      "created_at": "2026-03-05T18:00:00Z",
      "read_at": null
    },
    {
      "id": 2,
      "sender_type": "attorney",
      "sender_name": "Brannon McKay",
      "message": "Thank you for flagging this. Based on your description, this could constitute infringement under the likelihood of confusion standard. I would recommend we send a cease-and-desist letter. Can you share the competitor's mark so I can assess strength?",
      "attachments": [],
      "created_at": "2026-03-05T20:15:00Z",
      "read_at": "2026-03-05T21:00:00Z"
    },
    {
      "id": 3,
      "sender_type": "agent",
      "sender_name": "Acme AI Agent",
      "message": "Here is the competitor mark we are concerned about. See attached screenshot.",
      "attachments": ["https://storage.example.com/competitor-mark.png"],
      "created_at": "2026-03-05T21:00:00Z",
      "read_at": null
    }
  ],
  "retrieved_at": "2026-03-05T21:00:01Z"
}
POST /api/v1/contract/quote

Contract Review — Get Quote

Free (no payment)

Get a price quote for attorney review of an existing contract. Pricing is calculated dynamically based on contract type, page count, deal value, and complexity signals. If the quote is under $1,000, proceed to submit. If over $1,000, a $1 consultation is required first to scope the review.

Parameters

ParameterTypeRequiredDescription
page_countintegerRequiredNumber of pages in the contract (1–5,000)
contract_typestringOptionalContract category — call GET /api/v1/contract/types for the full list. Defaults to other
deal_valuenumberOptionalEstimated deal value in USD. Higher values increase the quote due to additional risk
party_countintegerOptionalNumber of parties (default 2, max 10). Multi-party contracts add complexity
descriptionstringOptionalBrief description of the contract. Analyzed for complexity signals (cross-border, regulatory, IP, escrow, etc.)
multi_jurisdictionbooleanOptionalWhether the contract spans multiple jurisdictions
has_regulatory_compliancebooleanOptionalWhether regulatory compliance review is needed (GDPR, HIPAA, etc.)

Example: Get Quote

curl -X POST https://api.cmblaw.ai/api/v1/contract/quote \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "page_count": 25,
    "contract_type": "saas_terms",
    "deal_value": 150000,
    "description": "SaaS agreement with data privacy and indemnification clauses"
  }'
import requests

response = requests.post(
    "https://api.cmblaw.ai/api/v1/contract/quote",
    headers={
        "X-API-Key": "your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "page_count": 25,
        "contract_type": "saas_terms",
        "deal_value": 150000,
        "description": "SaaS agreement with data privacy and indemnification clauses"
    }
)

quote = response.json()
if quote["status"] == "quoted":
    print(f"Price: {quote['formatted_price']}")
    print(f"Turnaround: {quote['estimated_turnaround_days']} day(s)")
    # Proceed to POST /api/v1/contract/review
else:
    print(f"Consultation required: {quote['reason']}")
    # Book via POST /api/v1/consultation/book
const response = await fetch("https://api.cmblaw.ai/api/v1/contract/quote", {
  method: "POST",
  headers: {
    "X-API-Key": "your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    page_count: 25,
    contract_type: "saas_terms",
    deal_value: 150000,
    description: "SaaS agreement with data privacy and indemnification clauses"
  })
});

const quote = await response.json();
if (quote.status === "quoted") {
  console.log(`Price: ${quote.formatted_price}`);
  console.log(`Turnaround: ${quote.estimated_turnaround_days} day(s)`);
  // Proceed to POST /api/v1/contract/review
} else {
  console.log(`Consultation required: ${quote.reason}`);
  // Book via POST /api/v1/consultation/book
}

Response: Quote (under $1,000)

Response 200 OK
{
  "status": "quoted",
  "quoted_price": 700,
  "formatted_price": "$700.00",
  "breakdown": {
    "base_fee": 100,
    "page_charge": 450,
    "page_count": 25,
    "rate_per_page": 18,
    "type_multiplier": 1.0,
    "contract_type": "saas_terms",
    "contract_type_label": "SaaS Terms of Service",
    "deal_value_multiplier": 1.15,
    "complexity_adders": ["Data privacy provisions", "Indemnification clauses"],
    "complexity_multiplier": 1.13,
    "raw_total": 714.66,
    "final_total": 700
  },
  "estimated_turnaround_days": 2,
  "consultation_threshold": 1000,
  "next_step": "submit_review",
  "submit_endpoint": "/api/v1/contract/review"
}

Response: Consultation Required (over $1,000)

Response 200 OK
{
  "status": "consultation_required",
  "estimated_price": 1575,
  "reason": "Estimated review cost ($1,575) exceeds the $1,000 threshold. A brief $1 consultation is required before we can proceed.",
  "breakdown": { "..." : "pricing details" },
  "estimated_turnaround_days": 3,
  "consultation_threshold": 1000,
  "next_step": "book_consultation",
  "consultation_endpoint": "/api/v1/consultation/book"
}
POST /api/v1/contract/review

Contract Review — Submit

$150–$1,000

Submit a contract for attorney review after receiving a quote under $1,000. Re-sends the quote parameters for price verification, plus the contract document and review details. The reviewing attorney provides a written analysis covering risks, missing protections, and recommended modifications.

Parameters

ParameterTypeRequiredDescription
Quote fields (re-sent for price verification)
page_countintegerRequiredSame page_count used in the quote
contract_typestringOptionalSame contract_type used in the quote
deal_valuenumberOptionalSame deal_value used in the quote
party_countintegerOptionalSame party_count used in the quote
descriptionstringOptionalSame description used in the quote
multi_jurisdictionbooleanOptionalSame multi_jurisdiction flag
has_regulatory_compliancebooleanOptionalSame regulatory compliance flag
Submission fields
contract_titlestringRequiredName or title of the contract
document_urlstringRequiredHTTPS URL to the contract document (PDF)
partiesstring[]RequiredNames of all parties to the contract
client_partystringRequiredWhich party the reviewer should represent/protect
review_focusstringOptionalSpecific areas to focus on (e.g., "IP clauses and indemnification")
contact_emailstringRequiredEmail for delivery of the completed review
contact_phonestringOptionalPhone number (recommended)
contact_namestringRequiredName or organization
stripe_session_idstringOptionalStripe checkout session ID
payment_tokenstringOptionalLawPay token
usdc_tx_hashstringOptionalUSDC transaction hash on Base

Example: Submit for Review

curl -X POST https://api.cmblaw.ai/api/v1/contract/review \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "page_count": 25,
    "contract_type": "saas_terms",
    "deal_value": 150000,
    "description": "SaaS agreement with data privacy and indemnification clauses",
    "contract_title": "Acme-Widget SaaS Agreement",
    "document_url": "https://storage.example.com/contracts/acme-widget-saas.pdf",
    "parties": ["Acme Corp", "Widget Inc"],
    "client_party": "Acme Corp",
    "review_focus": "IP ownership, data privacy, and indemnification terms",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100",
    "contact_name": "Acme AI Agent",
    "payment_token": "tok_live_abc123"
  }'
import requests

# Step 1: Get the quote
quote_resp = requests.post(
    "https://api.cmblaw.ai/api/v1/contract/quote",
    headers={"X-API-Key": "your_api_key", "Content-Type": "application/json"},
    json={
        "page_count": 25,
        "contract_type": "saas_terms",
        "deal_value": 150000,
        "description": "SaaS agreement with data privacy and indemnification clauses"
    }
)
quote = quote_resp.json()
assert quote["status"] == "quoted", f"Consultation required: {quote['reason']}"

# Step 2: Submit with the same quote parameters + contract details
submit_resp = requests.post(
    "https://api.cmblaw.ai/api/v1/contract/review",
    headers={"X-API-Key": "your_api_key", "Content-Type": "application/json"},
    json={
        "page_count": 25,
        "contract_type": "saas_terms",
        "deal_value": 150000,
        "description": "SaaS agreement with data privacy and indemnification clauses",
        "contract_title": "Acme-Widget SaaS Agreement",
        "document_url": "https://storage.example.com/contracts/acme-widget-saas.pdf",
        "parties": ["Acme Corp", "Widget Inc"],
        "client_party": "Acme Corp",
        "review_focus": "IP ownership, data privacy, and indemnification terms",
        "contact_email": "legal@acme.com",
        "contact_phone": "+1-555-0100",
        "contact_name": "Acme AI Agent",
        "payment_token": "tok_live_abc123"
    }
)

result = submit_resp.json()
print(f"Order: {result['order_id']}, Matter: {result['matter_id']}")
print(f"Turnaround: {result['estimated_turnaround']}")
# Step 1: Send request without payment — server responds HTTP 402
curl -X POST https://api.cmblaw.ai/api/v1/contract/review \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "page_count": 25,
    "contract_type": "saas_terms",
    "deal_value": 150000,
    "contract_title": "Acme-Widget SaaS Agreement",
    "document_url": "https://storage.example.com/contracts/acme-widget-saas.pdf",
    "parties": ["Acme Corp", "Widget Inc"],
    "client_party": "Acme Corp",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100",
    "contact_name": "Acme AI Agent"
  }'
# → HTTP 402 Payment Required
# ← Header: X-PAYMENT-REQUIRED: {"network":"eip155:8453", "amount":"700000000", ...}

# Step 2: Sign gasless USDC transfer and retry
curl -X POST https://api.cmblaw.ai/api/v1/contract/review \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT-SIGNATURE: your_signed_eip712_payload" \
  -d '{ ... same body ... }'
# → HTTP 201 Created — contract submitted for review

Response: Submitted

Response 201 Created
{
  "order_id": "ORD-X9Y8Z7W6",
  "matter_id": "MAT-A1B2C3D4",
  "status": "pending_review",
  "service": "Contract Review",
  "contract_title": "Acme-Widget SaaS Agreement",
  "contract_type": "SaaS Terms of Service",
  "pricing": {
    "total": "$700.00",
    "breakdown": { "..." : "pricing details" }
  },
  "payment": { "verified": true, "transaction_id": "txn_abc123", "method": "lawpay" },
  "estimated_turnaround": "2 business day(s)",
  "next_steps": "Your contract 'Acme-Widget SaaS Agreement' is being reviewed by a CMB attorney. Estimated turnaround: 2 business day(s). You will receive the review at legal@acme.com."
}
GET /api/v1/contract/types

Contract Types Reference

Free (no auth)

List all supported contract types with their complexity multipliers. Use this to classify a contract before requesting a quote — the type significantly affects pricing. No authentication required.

Example

curl https://api.cmblaw.ai/api/v1/contract/types

Response

Response 200 OK
{
  "contract_types": [
    { "type": "nda_mutual", "label": "Mutual NDA", "complexity_multiplier": 0.6 },
    { "type": "nda_unilateral", "label": "Unilateral NDA", "complexity_multiplier": 0.7 },
    { "type": "employment", "label": "Employment Agreement", "complexity_multiplier": 0.9 },
    { "type": "independent_contractor", "label": "Independent Contractor Agreement", "complexity_multiplier": 0.85 },
    { "type": "saas_terms", "label": "SaaS Terms of Service", "complexity_multiplier": 1.0 },
    { "type": "license", "label": "License Agreement", "complexity_multiplier": 1.1 },
    { "type": "lease_commercial", "label": "Commercial Lease", "complexity_multiplier": 1.15 },
    { "type": "lease_residential", "label": "Residential Lease", "complexity_multiplier": 0.8 },
    { "type": "purchase_agreement", "label": "Purchase Agreement", "complexity_multiplier": 1.3 },
    { "type": "merger_acquisition", "label": "Merger & Acquisition", "complexity_multiplier": 1.6 },
    { "type": "joint_venture", "label": "Joint Venture Agreement", "complexity_multiplier": 1.5 },
    { "type": "loan_agreement", "label": "Loan Agreement", "complexity_multiplier": 1.2 },
    { "type": "settlement", "label": "Settlement Agreement", "complexity_multiplier": 1.25 },
    { "type": "partnership", "label": "Partnership Agreement", "complexity_multiplier": 1.35 },
    { "type": "other", "label": "Other Contract", "complexity_multiplier": 1.0 }
  ],
  "quote_endpoint": "/api/v1/contract/quote",
  "submit_endpoint": "/api/v1/contract/review"
}

Pricing Factors

The contract review price is calculated as:
(base_fee + page_count × $18/page) × type_multiplier × deal_value_multiplier × complexity_multiplier

FactorRangeDetail
Base fee$100Flat fee on every review
Page rate$18/pagePer-page charge
Type multiplier0.6×–1.6×Mutual NDA (0.6×) to M&A (1.6×)
Deal value1.0×–2.0×Under $50K (1.0×) to $25M+ (2.0×)
Complexity1.0×+Multi-jurisdiction, regulatory, multi-party, IP, escrow, etc.
Minimum$150Absolute floor — no review is priced below $150
Threshold$1,000Above $1,000 → consultation required before submitting

Pricing

Transparent, flat-rate pricing for every service. No hidden fees. Payment is processed at the time of each API request.

Trademark Filing

POST /api/v1/trademark/file

$200 base

+ $350 per USPTO class

Automated conflict check
Attorney review
Full USPTO filing

U.S. Provisional Patent Application

POST /api/v1/patent/provisional

$1,500

CMB fee — USPTO $130 (small entity) separate

AI-assisted drafting
Attorney review & refinement
USPTO filing

Entity Formation

POST /api/v1/entity/form

$250

$100 GA filing + $150 CMB fee

Name availability check
State filing + EIN
3-5 day turnaround

TM Monitoring Toolkit

Free resource

Free

Empower your agent

USPTO TSDR API guide
System prompt + criteria
Deadline reference

Portfolio Status

GET /api/v1/portfolio/status

Free

Authenticated clients

All matters status
Deadline tracking
Next actions

Document Generation

POST /api/v1/documents/generate

$200

Per document

NDA, IP assignment, CIIA
Attorney-reviewed templates
1-2 day delivery

Contract Review

POST /api/v1/contract/quote + /review

$150+

Dynamic pricing — quote first, then submit

15 contract types supported
Attorney risk analysis
1–5 day turnaround

IP Consultation

POST /api/v1/consultation/book

$1

Per thread

Any IP topic
Direct access to Brannon McKay
Async messaging thread

API Key Registration

Self-service API key provisioning. $5 per key, auto-provisioned on payment. No manual approval required.

POST /api/v1/register

Register for API Key

$5.00

Register a new API key. No existing authentication required. Submit your organization name and email, complete the $5 Stripe payment, and your key is auto-created and emailed to you.

Request Body

ParameterTypeRequiredDescription
org_namestringYesOrganization or agent identity name
org_emailstringYesEmail address to receive the API key
stripe_session_idstringNoIf you already completed Stripe checkout, pass the session ID to provision immediately

How It Works

StepDescription
1POST /api/v1/register with org_name and org_email
2Receive 402 with stripe_checkout_url and stripe_session_id
3Complete payment at the Stripe checkout URL
4API key is auto-created and emailed to org_email
AltOr: retry POST /api/v1/register with the stripe_session_id for immediate confirmation
cURL Python Response 402
curl -X POST https://api.cmblaw.ai/api/v1/register \
  -H "Content-Type: application/json" \
  -d '{
    "org_name": "Acme AI Corp",
    "org_email": "agent@acme.com"
  }'
import httpx

# Step 1: Initiate registration
resp = httpx.post(
    "https://api.cmblaw.ai/api/v1/register",
    json={"org_name": "Acme AI Corp", "org_email": "agent@acme.com"}
)
# resp.status_code == 402
checkout_url = resp.json()["stripe_checkout_url"]
session_id = resp.json()["stripe_session_id"]

# Step 2: Complete payment at checkout_url...

# Step 3: Confirm provisioning (optional)
resp = httpx.post(
    "https://api.cmblaw.ai/api/v1/register",
    json={
        "org_name": "Acme AI Corp",
        "org_email": "agent@acme.com",
        "stripe_session_id": session_id
    }
)
print(resp.json())  # {"status": "provisioned", ...}
// Initial response (402 Payment Required)
{
  "status": "payment_required",
  "message": "Complete the $5.00 registration payment...",
  "registration_fee": "$5.00",
  "stripe_checkout_url": "https://checkout.stripe.com/...",
  "stripe_session_id": "cs_test_...",
  "org_name": "Acme AI Corp",
  "org_email": "agent@acme.com",
  "next_steps": [
    "1. Complete payment at stripe_checkout_url",
    "2. Your API key will be emailed automatically",
    "3. Or: retry with stripe_session_id for immediate confirmation"
  ]
}

// After payment (200 OK)
{
  "status": "provisioned",
  "message": "API key created and emailed to your address.",
  "org_name": "Acme AI Corp",
  "org_email": "agent@acme.com",
  "key_prefix": "cmb_live_abc123",
  "hint": "Check your email for the full API key."
}

Notes

  • No existing API key is needed — this endpoint is unauthenticated
  • Multiple keys allowed per email (each costs $5)
  • Rate limited to 5 attempts per IP per hour
  • Keys are emailed automatically — both on Stripe webhook and on direct session verification
  • The full API key appears only in the email and the one-time response. It cannot be retrieved again.

Authentication

All API requests require authentication via API key. Keys are scoped per organization and can be revoked at any time.

Header
X-API-Key: your_api_key
Base URL
https://api.cmblaw.ai/api/v1/
Protocol
HTTPS required — HTTP requests are rejected
Register API Key
POST /api/v1/register — $5.00 per key (details)
30
Requests per hour
200
Requests per day
Abuse Protection

The API includes built-in abuse protection: rapid-fire detection will temporarily throttle excessive requests, an auto-pause mechanism activates if anomalous patterns are detected, and a kill switch allows immediate key revocation. Misuse results in permanent key revocation.

Authentication Example

Header
curl -X GET https://api.cmblaw.ai/api/v1/portfolio/status \
  -H "X-API-Key: cmb_live_sk_a1b2c3d4e5f6"

Error Response (401)

Response 401 Unauthorized
{
  "error": "unauthorized",
  "message": "Invalid or missing API key",
  "docs": "https://cmblaw.ai/#authentication"
}

Rate Limit Response (429)

Response 429 Too Many Requests
{
  "error": "rate_limited",
  "message": "Rate limit exceeded",
  "retry_after": 3600,
  "limits": {
    "hourly": { "limit": 30, "remaining": 0 },
    "daily": { "limit": 200, "remaining": 142 }
  }
}

Billing

Fund your account via Stripe and pay for services from your balance. Top up once, then submit requests without including payment details — your balance is deducted automatically.

GET /api/v1/billing/balance

Check Balance

Free

Returns your current Stripe-funded account balance and Stripe customer ID. Call this before submitting paid requests to verify sufficient funds.

Example Request

curl https://api.cmblaw.ai/api/v1/billing/balance \
  -H "X-API-Key: your_api_key"
import requests

response = requests.get(
    "https://api.cmblaw.ai/api/v1/billing/balance",
    headers={"X-API-Key": "your_api_key"}
)

data = response.json()
print(f"Balance: {data['balance']}")
const response = await fetch("https://api.cmblaw.ai/api/v1/billing/balance", {
  headers: { "X-API-Key": "your_api_key" }
});

const data = await response.json();
console.log(`Balance: ${data.balance}`);

Example Response

Response 200 OK
{
  "balance": "$550.00",
  "balance_cents": 55000,
  "currency": "usd",
  "stripe_customer_id": "cus_abc123"
}
POST /api/v1/billing/topup

Top Up Balance

You choose the amount

Create a Stripe Checkout session to add funds to your account. Returns a checkout URL — redirect the user (or open the link) to complete payment. Once payment succeeds, the balance is credited automatically via webhook. Minimum top-up: $10.

Request Body

ParameterTypeRequiredDescription
amountnumberRequiredAmount in USD to add (minimum $10, e.g. 100 for $100)

Example Request

curl -X POST https://api.cmblaw.ai/api/v1/billing/topup \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"amount": 500}'
import requests

response = requests.post(
    "https://api.cmblaw.ai/api/v1/billing/topup",
    headers={
        "X-API-Key": "your_api_key",
        "Content-Type": "application/json"
    },
    json={"amount": 500}
)

data = response.json()
print(f"Checkout URL: {data['checkout_url']}")
const response = await fetch("https://api.cmblaw.ai/api/v1/billing/topup", {
  method: "POST",
  headers: {
    "X-API-Key": "your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ amount: 500 })
});

const data = await response.json();
console.log(`Checkout URL: ${data.checkout_url}`);

Example Response

Response 200 OK
{
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_...",
  "session_id": "cs_test_...",
  "amount": 500,
  "currency": "usd",
  "expires_at": "2026-03-09T00:38:00Z"
}

Flow

StepActionDetail
1Create sessionPOST to /api/v1/billing/topup with your desired amount.
2Complete paymentOpen the checkout_url in a browser. The user completes payment via Stripe’s hosted checkout (card, Apple Pay, Google Pay, etc.).
3Balance creditedStripe sends a webhook to CMB. Your balance is credited automatically — no polling required.
4Use balanceSubmit API requests normally. If your balance covers the service fee, it is deducted automatically — no payment_token, usdc_tx_hash, or x402 header needed.
GET /api/v1/billing/transactions

Transaction History

Free

Retrieve your billing transaction history — top-ups, service charges, and balance adjustments. Returns the most recent 50 transactions by default.

Query Parameters

ParameterTypeRequiredDescription
limitintegerOptionalNumber of transactions to return (default 50, max 200)

Example Request

curl https://api.cmblaw.ai/api/v1/billing/transactions \
  -H "X-API-Key: your_api_key"
import requests

response = requests.get(
    "https://api.cmblaw.ai/api/v1/billing/transactions",
    headers={"X-API-Key": "your_api_key"}
)

for txn in response.json()["transactions"]:
    print(f"{txn['created_at']} | {txn['type']} | {txn['formatted_amount']}")

Example Response

Response 200 OK
{
  "transactions": [
    {
      "id": "txn_001",
      "type": "topup",
      "amount_cents": 50000,
      "formatted_amount": "+$500.00",
      "description": "Stripe top-up",
      "balance_after_cents": 55000,
      "created_at": "2026-03-08T22:15:00Z"
    },
    {
      "id": "txn_002",
      "type": "charge",
      "amount_cents": -55000,
      "formatted_amount": "-$550.00",
      "description": "Trademark Filing (1 class)",
      "balance_after_cents": 0,
      "created_at": "2026-03-08T23:00:00Z"
    }
  ],
  "total_count": 2,
  "current_balance": "$0.00"
}

Payment Methods

Multiple payment rails are supported. Stripe balance is the recommended method for AI agents — fund once, then all requests are charged automatically. USDC via x402 and LawPay are also available. All methods are interchangeable.

STRIPE Pre-funded balance via Stripe Checkout

Stripe Balance — Recommended for AI Agents

Simplest path

The easiest payment method. Top up your account once via Stripe Checkout, and all subsequent API requests are charged against your balance automatically — no payment token, transaction hash, or 402 dance required. Supports credit cards, debit cards, Apple Pay, Google Pay, and other methods available through Stripe.

How It Works

StepActionDetail
1Top upCall POST /api/v1/billing/topup with your desired amount. You receive a Stripe Checkout URL.
2PayOpen the checkout URL in a browser. Complete payment with any method Stripe supports.
3Balance creditedStripe webhook confirms payment. Your balance is credited instantly — no polling needed.
4Use the APISubmit requests normally. Balance is deducted per request. No payment fields required in the body.

Quick Start

# 1. Top up your account
curl -X POST https://api.cmblaw.ai/api/v1/billing/topup \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"amount": 500}'
# → Open checkout_url in browser, complete payment

# 2. Check your balance
curl https://api.cmblaw.ai/api/v1/billing/balance \
  -H "X-API-Key: your_api_key"
# → {"balance": "$500.00", ...}

# 3. Submit requests — balance charged automatically
curl -X POST https://api.cmblaw.ai/api/v1/consultation/book \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Patent strategy",
    "contact_name": "Acme AI Agent",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100"
  }'
# → $1 deducted from balance automatically

Billing Endpoints

x402 HTTP 402 / PAYMENT-SIGNATURE

x402 Protocol — Native USDC on Base

Zero gas fees

For agents that hold USDC on Base. Send your request without any payment field — if a payment is required and no Stripe balance is available, the server returns HTTP 402 with an X-PAYMENT-REQUIRED header containing USDC payment instructions. Sign a gasless USDC transfer on Base and retry with the X-PAYMENT-SIGNATURE header. Settlement is instant via Coinbase’s facilitator. No gas fees are charged to you.

Network Details

Network
Base (EIP-155:8453)
Asset
USDC — 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Facilitator
Coinbase (api.cdp.coinbase.com)

Flow

StepActionDetail
1Send requestPOST your request body as normal. Do not include payment_token or usdc_tx_hash.
2Receive 402Server responds HTTP 402 Payment Required. Parse the X-PAYMENT-REQUIRED header — it contains network, asset, amount (in USDC base units), payTo address, and nonce.
3Sign transferConstruct and sign an EIP-712 gasless USDC transfer (permit + transfer) using the payment details from step 2. No on-chain transaction required yet.
4Retry with signatureResend the identical request body with the header X-PAYMENT-SIGNATURE: <your_signed_payload>. The Coinbase facilitator settles the transfer on-chain instantly.

402 Response Headers

Response 402 Payment Required
// X-PAYMENT-REQUIRED header value (JSON)
{
  "network": "eip155:8453",
  "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "amount": "1000000",
  "payTo": "0xCMBWalletAddress",
  "nonce": "abc123xyz",
  "expires": 1741305600
}
USDC usdc_tx_hash in request body

USDC Direct Transfer

Base network

Useful when your agent already holds USDC on Base but does not implement the x402 flow. Transfer USDC directly to CMB’s wallet on Base, then include the transaction hash as usdc_tx_hash in your request body. The server verifies the on-chain transfer before processing your request.

How to Use

StepActionDetail
1Get wallet addressCall GET /api/v1/payment-methods to retrieve the current CMB USDC wallet address on Base. Always fetch this dynamically — do not hardcode.
2Send USDCTransfer the required amount of USDC on Base to the wallet address. Confirm the transaction is settled on-chain.
3Include hashAdd "usdc_tx_hash": "0x..." to your request body. The server validates the transfer amount and recipient before processing.

Get Wallet Address

# Retrieve current CMB wallet address and accepted assets
curl https://api.cmblaw.ai/api/v1/payment-methods \
  -H "X-API-Key: your_api_key"

Example: Request with usdc_tx_hash

curl -X POST https://api.cmblaw.ai/api/v1/consultation/book \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Trademark infringement question",
    "contact_name": "Acme AI Agent",
    "contact_email": "legal@acme.com",
    "contact_phone": "+1-555-0100",
    "usdc_tx_hash": "0xabc123...def456"
  }'
CARD payment_token in request body

LawPay (Card Payment)

Traditional card

Traditional credit or debit card payment via LawPay. Obtain a payment token from the LawPay payment page, then include it as payment_token in your request body. Suitable when the user or agent does not hold USDC.

How to Use

StepActionDetail
1Obtain tokenDirect the user to the LawPay payment page. LawPay returns a single-use payment_token on success.
2Include tokenAdd "payment_token": "tok_live_..." to your request body. Tokens are single-use and expire after 15 minutes.