JSON-RPC API

The JSON-RPC interface at /jsonrpc and /web/dataset/call_kw is the canonical BridgeERP RPC surface. It lets clients call any model method (create, write, search_read, custom action) directly, with full ORM semantics.

API settings
API keys + webhooks under Configuration → API / Integrations.
At a glance — Endpoints: /jsonrpc (BridgeERP standard), /web/dataset/call_kw (web client style). Auth: session cookie or API key. Format: JSON-RPC 2.0. Use when: BridgeERP client, internal scripts, or REST API doesn't cover the operation.

When to use JSON-RPC vs REST

Use REST for third-party integrations, public-facing apps, and partners who must not know your BridgeERP schema. Use JSON-RPC for internal BridgeERP-to-BridgeERP links, admin scripts, and anything where you want to call a custom model method without writing a REST wrapper.

Warning — JSON-RPC exposes your full model surface. Granting RPC access to an external party is equivalent to granting them database access — they can read or write anything the bound user can. Use REST for partners.

Authentication

Two options: session cookie (web.session) or API key.

import xmlrpc.client
# JSON-RPC via xmlrpc helper, or use requests + JSON-RPC payload directly
import requests

base = 'https://microfinance.mybridgeerp.com'
db = 'microfinance.mybridgeerp.com'
login = 'integration@bridgeerp.com'
api_key = 'ak_8f72...'

# Authenticate
resp = requests.post(f'{base}/jsonrpc', json={
    'jsonrpc': '2.0',
    'method': 'call',
    'params': {
        'service': 'common',
        'method': 'authenticate',
        'args': [db, login, api_key, {}]
    }
}).json()
uid = resp['result']

Calling model methods

Once authenticated, call any model method by name. The pattern is execute_kw(db, uid, password, model, method, args, kwargs).

# Search and read members
resp = requests.post(f'{base}/jsonrpc', json={
    'jsonrpc': '2.0',
    'method': 'call',
    'params': {
        'service': 'object',
        'method': 'execute_kw',
        'args': [
            db, uid, api_key,
            'mfi.member', 'search_read',
            [[['state', '=', 'active']]],          # domain
            {'fields': ['name', 'phone', 'national_id'], 'limit': 50}
        ]
    }
}).json()
members = resp['result']

# Create a loan
loan_id = requests.post(f'{base}/jsonrpc', json={
    'jsonrpc': '2.0',
    'method': 'call',
    'params': {
        'service': 'object',
        'method': 'execute_kw',
        'args': [
            db, uid, api_key,
            'mfi.loan', 'create',
            [{
                'member_id': 4827,
                'product_id': 12,
                'principal': 5000000,
                'term_months': 12,
            }]
        ]
    }
}).json()['result']

# Call custom action
requests.post(f'{base}/jsonrpc', json={
    'jsonrpc': '2.0',
    'method': 'call',
    'params': {
        'service': 'object',
        'method': 'execute_kw',
        'args': [
            db, uid, api_key,
            'mfi.loan', 'action_approve',
            [[loan_id]]
        ]
    }
})

Most-called models

  • mfi.member — members and KYC
  • mfi.loan — loans
  • mfi.loan.schedule — schedule lines
  • mfi.loan.disbursement — disbursements
  • mfi.loan.repayment — repayments
  • mfi.savings.account — savings accounts
  • mfi.savings.transaction — savings transactions
  • mfi.aml.alert — AML alerts
  • mfi.regulatory.return — regulatory returns
  • account.move — accounting entries (for reconciliation)

Performance tips

  • Always pass a fields list to search_read; never read every column
  • Use create([list_of_dicts]) for bulk create — order of magnitude faster than N calls
  • Use the with_context() pattern by passing context as kwarg to switch language, lang code, or skip computes
  • For pagination prefer search with offset+limit and ordered by id, then read in batches

Worked scenarios

Scenario — Florence runs nightly delinquency tagging via JSON-RPC

Setting: Mwananchi SACCO runs a nightly Python script that queries all loans, computes ageing, and updates a custom delinquency_tier field via JSON-RPC.

CharacterRole
Florence AchiengCredit Risk Analyst
Samuel KibetDevOps Engineer

Timeline

  1. Day 1, 09:00: Samuel writes Python script using requests + JSON-RPC. (Script uses Florence's API key with credit_risk role.)
  2. Day 1, 14:00: Cron scheduled at 02:00 daily on a jump box. (Systemd timer mfi-delinquency.timer enabled.)
  3. Day 2, 02:00: Cron fires. (Script auths, search_read mfi.loan, computes tiers, writes back.)
  4. Day 2, 02:04: 8,431 loans tagged. (163 loans moved from tier 0 to tier 1; 22 to tier 2; 4 to tier 3.)
  5. Day 2, 08:00: Florence opens dashboard. (Tier-based pivot shows overnight delta; she actions tier 3 loans first.)

Outcome — Daily delinquency tiering automated without writing a custom REST endpoint. Performance: 8,431 loans tagged in 4 minutes (bulk write batches of 500).

Reference

Common JSON-RPC error codes

CodeMessageCauseFix
100BridgeERP Session ExpiredSession cookie timed outRe-authenticate
200BridgeERP Server ErrorUnhandled Python exceptionCheck the API Audit Log under Configuration → API / Integrations → API Logs
-32600Invalid RequestMalformed JSON-RPC payloadValidate JSON, check method/params
-32601Method not foundWrong service or method nameUse 'object' service + execute_kw
-32602Invalid paramsWrong argument count or typesMatch BridgeERP method signature exactly

Troubleshooting

SymptomLikely causeFix
execute_kw returns 'access denied' on mfi.loan write.Bound user lacks Loan Officer role.Add the role at Settings > Users.
search_read returns empty list despite records existing.Record rule filters them out for this user.Check record rules on mfi.loan; may be branch-scoped.
Custom action throws 'AttributeError: action_approve'.Module not installed on tenant or method renamed.Confirm mfi_loan version; check method name with dir() via shell.

See also

Was this page helpful?