PANBIDS DEVELOPERS / API v1

Build your auction integration.

Connect to bank inventory. Discover live auctions. Place signed bids.

Open API playground Authentication guide →
● ● ● panbids / api v1
GET /api/v1/events?status=live

{
  "status": "live",
  "bid_type": "open",
  "eligible_lots_count": 30
}
Example event fields · HTTPS · HMAC-SHA256

Connect your application

Base URL: http://www.panbids.com/index.php/api/v1. Environment: production.

  1. Obtain an active bank partner account, approved KYB and agreement, and an active bank subscription.
  2. Ask the bank to approve your source IP/CIDR, assign auction lots and permissions, and issue environment-specific client ID, key ID and signing secret.
  3. Use HTTPS and a synchronized server clock. Keep signing secrets on your backend. This playground signs locally in your browser and keeps credentials only in the current page.
  4. Fetch upcoming events, retrieve their lots, and submit bids only within the server-authoritative bidding window.

Requests are limited to 120 per minute. The browser's public source IP must be approved to use the playground. This page calls this deployment directly; it does not bypass authentication or IP checks.

Request authentication

Every request requires these headers: X-Client-ID, X-Key-ID, X-Timestamp (Unix seconds), X-Nonce (unique 16–128 character letters, digits, underscore or hyphen), X-Content-SHA256 and X-Signature.

Calculate a lowercase hexadecimal SHA-256 digest of the exact request body. GET requests use an empty body. Sign these six newline-separated lines using HMAC-SHA256 with the secret string as the key:

METHOD
/api/v1/path
canonical_query_string
unix_timestamp
unique_nonce
body_sha256

Use uppercase METHOD, the exact URL path and a query string sorted by parameter name with RFC 3986 percent encoding. Keep the query line empty when no query parameters are present. Send the lowercase hexadecimal HMAC as X-Signature. The permitted clock difference is five minutes. Generate a fresh nonce for every request and retry.

OperationEndpointScope
Auction catalogueGET /api/v1/lotscatalogue:read
Published vehicle detailsGET /api/v1/vehicles/{lot_public_id}vehicles:read
Submit bidPOST /api/v1/lots/{lot_public_id}/bidsbids:write
Your bid statusGET /api/v1/bidsbids:read
Closed auction lot resultsGET /api/v1/resultsresults:read

Lists paginate at 25 records with ?page=2. Vehicle identifiers are published auction lot IDs; vehicle_details includes bank-saved fields shared with authorized partners. Results expose closed lot status, not a confirmed sale or another dealer's identity.

Bid requests

Send JSON with dealer_id (your bank-issued bidding dealer reference), amount and idempotency_key (UUID). Set the same UUID in the Idempotency-Key header. Reuse that UUID only when retrying the identical bid. Buyer limits, valid EMD, auction state and channel publication must permit the bid.

Environment and access

Sandbox and Production use different credentials and configured service deployments. A Production server rejects Sandbox credentials. Only approved source IPs are accepted. Revoked keys, suspended accounts, expired agreements, repeated nonces and missing scopes are rejected. Use HTTPS in deployed environments.

Winner updates are available by polling GET /api/v1/winner-updates with a durable cursor or by verified, signed sale.approved webhooks. Both represent the same committed bank decision.

Event endpoints

All endpoints below use catalogue:read. Replace braces with public IDs returned by the API.

Method and pathParameters / response
GET /eventsstatus: upcoming, live, over, all. Default: active (live). Legacy aliases scheduled and ended remain accepted. page and per_page (1?100, default 25).
GET /events/{event}Single event in data.
GET /events/{event}/lotspage, per_page, search (max 100), bidder_reference (optional platform/aggregator identity, max 120; letters, digits, underscore, hyphen).
GET /events/{event}/lots/{lot}Single lot in data; optional bidder_reference.
GET /events/{event}/lots/{lot}/media/{media}Numeric authorized media ID; binary inline photo or downloadable file, 404 when unavailable.

Bank-created auctions publish immediately after final validation. Status is upcoming before start, live from start inclusive to close exclusive, and over at close. Timestamps include their UTC offset; timezone identifies the display zone. Cancelled auctions are excluded. Sale approval remains a separate process.

Only assigned lots within current bank permissions are returned. Withdrawn, cancelled or unavailable vehicles are excluded. Open bids expose highest_amount; closed bids hide it. own_amount and bidder_status describe the authenticated bidder; channel_status describes the channel. Platform requests without bidder_reference omit bidder-specific fields. All bid standings are provisional.

FIRST SUCCESSFUL BID

From credentials to an accepted bid

  1. Use your bank-issued Client ID, Key ID and signing secret from the same environment. Approve the actual sending server IP. The PANBIDS docs playground signs in the browser; the ai.napiersoft.com tester forwards through its server, whose outbound IP must be approved.
  2. GET /api/v1/events?status=live. Pick an assigned event and read its bid_type, bid_increment and closing time.
  3. GET /api/v1/events/{event}/lots. Pick a lot and read starting_price and highest_amount. Use public lot IDs in bids, not bank references or private inventory UUIDs.
  4. Find Bidding dealer ID in the partner Overview or activation email. It must belong to the partner behind your API client. Do not send the permanent partner ID or API client ID as dealer_id.
  5. Confirm dealer KYC approved, EMD valid, blocked = 0 and a bank-approved buyer_limit covering the bid. Partner Active alone is insufficient. Agreements, entitlements, expiry dates, bank subscription and auction assignment must also permit bidding.
  6. Platforms and aggregators must send their actual buyer's stable bidder_reference. Direct dealers omit it. Generate and persist a UUID and the exact bid payload before sending.
  7. POST the signed request. Check HTTP status, success, code and every item in errors. A returned bid_id may identify a rejected bid; it does not imply acceptance.
  8. Poll GET /api/v1/bids?bidder_reference=buyer_123 and the event-lot endpoint with the same reference. Acceptance is provisional and does not authorize payment or vehicle release.

Bid body: every field

FieldRequiredFormat / source
dealer_idYesString, max 32. Bank-issued Bidding dealer ID linked to these credentials.
bidder_referencePlatform / aggregator only1-120 letters, digits, _ or -. Stable actual buyer identity in your platform; not the vehicle reference. Direct dealers must omit.
amountYesINR decimal, positive, max 12 integer digits and 2 decimals. Prefer a string, e.g. "281200.00". Must match opening and increment.
idempotency_keyYesUUID generated by your application for one intended bid. Same value in Idempotency-Key header.
client_bid_timeNoParseable date/time; use ISO 8601 with timezone. Server receipt time determines eligibility.

Opening price and increments

Use integer paise for calculations to avoid floating-point rounding. For a positive increment, allowed amounts satisfy amount = opening and (amount - opening) % increment = 0. For open auctions a subsequent bid must also be at least highest_amount + increment. For closed auctions it must be at least your own previous accepted amount + increment; the hidden central leader is not the minimum.

Example only: opening = 281200.00, bid_increment = 2000.00
Allowed: 281200.00, 283200.00, 285200.00, ... , 299200.00, 301200.00
300000.00 is OFF the grid. Read the actual increment from GET /events/{event}.

With no previous accepted bid, the opening price is valid on the grid. Submit only your intended amount, within your approved buyer limit and the live bidding window.

UUIDs, nonces and retries

An idempotency UUID identifies a bid; a nonce identifies one HTTP attempt. Persist the UUID and body before sending. For a timeout or HTTP 500 with uncertain outcome, retry the identical request with the original UUID and a fresh nonce, timestamp and signature. Never create a new bid just because the response was lost. A changed amount or buyer reference is a new bid and needs a new UUID. A recorded rejection replays as a rejection (HTTP 422). Accepted identical retries return HTTP 200 with replayed: true; first acceptance returns HTTP 201. Reusing a key with a changed command returns HTTP 409.

The playground creates a UUID when Submit a bid is selected; it does not regenerate it each time Send is pressed. Replace it for a new intended bid. UUID generation does not contact PANBIDS and does not submit anything.

Language setup and UUID generation

Every endpoint has a complete signed request in all five language tabs in the playground. Choose the endpoint, replace its IDs, set query/body, select a language and copy the code. The copied code uses environment variables; it never embeds playground secrets.

# Bash / Linux / macOS - placeholders only
export PANBIDS_CLIENT_ID='YOUR_CLIENT_ID'
export PANBIDS_KEY_ID='YOUR_KEY_ID'
export PANBIDS_SECRET='YOUR_SIGNING_SECRET'

# PowerShell - use these environment variables for PHP, Node, Python or Ruby
$env:PANBIDS_CLIENT_ID='YOUR_CLIENT_ID'
$env:PANBIDS_KEY_ID='YOUR_KEY_ID'
$env:PANBIDS_SECRET='YOUR_SIGNING_SECRET'
JavaScript - setup and UUID

Node.js with built-in fetch. Save request as request.mjs; run node request.mjs. Keep signing on your backend.

// Browser console on HTTPS:
crypto.randomUUID()

// Node.js:
import { randomUUID } from 'node:crypto';
const idempotencyKey = randomUUID();
// Save idempotencyKey and the intended bid before sending.
Python - setup and UUID

Python 3 standard library. Save request.py; run python request.py.

import uuid
idempotency_key = str(uuid.uuid4())
print(idempotency_key)
PHP - setup and UUID

PHP 8.2+ with cURL extension. Save request.php; run php request.php.

<?php
function uuidV4(): string {
    $b = random_bytes(16);
    $b[6] = chr((ord($b[6]) & 0x0f) | 0x40);
    $b[8] = chr((ord($b[8]) & 0x3f) | 0x80);
    $h = bin2hex($b);
    return substr($h,0,8).'-'.substr($h,8,4).'-'.substr($h,12,4).'-'.substr($h,16,4).'-'.substr($h,20,12);
}
$idempotencyKey = uuidV4();
echo $idempotencyKey;
Ruby - setup and UUID

Ruby standard library: net/http, openssl, securerandom and json. Save request.rb; run ruby request.rb.

require 'securerandom'
idempotency_key = SecureRandom.uuid
puts idempotency_key
cURL - setup and UUID

Bash with cURL, OpenSSL, awk; jq for POST. Install uuidgen (often uuid-runtime) or generate a UUID using one of the recipes above. Run bash request.sh.

idempotency_key=$(uuidgen | tr '[:upper:]' '[:lower:]')
printf '%s\n' "$idempotency_key"
# Persist this UUID and body. Do not regenerate for a retry.

Read environment variables in your server process; do not put signing secrets in public frontend code or commit them to source control. For POST, the examples hash the exact serialized body and derive the Idempotency-Key header from that body. For media, they save binary bytes as response.bin; inspect HTTP status and Content-Type before treating a downloaded file as an image.

ALL 10 ENDPOINTS

Request and response reference

Paths below include /api/v1. All requests require the HMAC headers described in Authentication. GET requests have an empty body. Examples are illustrative, not live bids or a promise of current auction state. Use the matching Try example button for signed cURL, PHP, JavaScript, Python and Ruby code.

GET /api/v1/events List events

Discover the auctions your organisation can access. Filter by their server-authoritative bidding window. Required scope: catalogue:read.

ParameterLocationTypeRequiredMeaning
statusqueryenumNoall, upcoming, live or over. Default active means live; scheduled and ended are legacy aliases.
pagequeryintegerNoPage number, starting at 1.
per_pagequeryintegerNo1–100 records per page; default 25.

Request pattern

GET /api/v1/events?status=all&page=1&per_page=25
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "data": [
    {
      "id": "auc_EXAMPLE",
      "name": "September vehicle auction",
      "reference": "PB-2026-0911",
      "distribution_mode": "syndicated",
      "bid_type": "open",
      "status": "live",
      "timezone": "Asia/Kolkata",
      "starts_at": "2026-09-11T13:50:00+00:00",
      "ends_at": "2026-09-13T13:38:00+00:00",
      "bid_increment": "2000.00",
      "eligible_lots_count": 30,
      "revision": 35
    }
  ],
  "current_page": 1,
  "last_page": 1,
  "total": 1
}

Only published events with eligible, assigned lots are returned. Upcoming becomes live at start; live becomes over at close. Cancelled events are excluded.

GET /api/v1/events/{event} Get an event

Read the schedule, bid increment and eligible lot count for one auction. Required scope: catalogue:read.

ParameterLocationTypeRequiredMeaning
eventpathstringYesPublic auction ID returned by List events.

Request pattern

GET /api/v1/events/auc_EXAMPLE
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "data": {
    "id": "auc_EXAMPLE",
    "name": "September vehicle auction",
    "reference": "PB-2026-0911",
    "distribution_mode": "syndicated",
    "bid_type": "open",
    "status": "live",
    "timezone": "Asia/Kolkata",
    "starts_at": "2026-09-11T13:50:00+00:00",
    "ends_at": "2026-09-13T13:38:00+00:00",
    "bid_increment": "2000.00",
    "eligible_lots_count": 30,
    "revision": 35
  }
}

All timestamps include an offset. Use the timezone field when formatting dates for your users.

GET /api/v1/events/{event}/lots List event lots

Build your auction catalogue with the exact lots your organisation is permitted to see. Required scope: catalogue:read.

ParameterLocationTypeRequiredMeaning
eventpathstringYesPublic auction ID returned by List events.
pagequeryintegerNoPage number, starting at 1.
per_pagequeryintegerNo1–100 records per page; default 25.
searchquerystringNoSearch registration, make or model. Maximum 100 characters.
bidder_referencequerystringNoOptional platform/aggregator buyer identity. Max 120 letters, digits, underscores or hyphens. Direct dealers omit this.

Request pattern

GET /api/v1/events/auc_EXAMPLE/lots?page=1&per_page=25
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "data": [
    {
      "vehicle_details": {
        "registration_number": "MH01AB1234",
        "make": "Mahindra",
        "model": "Bolero Pick Up",
        "year": 2020,
        "region": "West",
        "vehicle_type": "CV",
        "yard": null,
        "title": "Mahindra Bolero Pick Up",
        "bank_reference": "VL0000000126740",
        "condition": "Inspection recorded"
      },
      "images": [
        "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/1"
      ],
      "documents": [
        "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/2"
      ],
      "id": "lot_EXAMPLE",
      "auction_id": "auc_EXAMPLE",
      "registration_number": "MH01AB1234",
      "make": "Mahindra",
      "model": "Bolero Pick Up",
      "year": 2020,
      "region": "West",
      "vehicle_type": "CV",
      "starting_price": "143600.00",
      "public_fields": {},
      "own_amount": null,
      "bidder_status": "no_bid",
      "channel_status": "no_bid",
      "provisional": true,
      "highest_amount": null
    }
  ],
  "current_page": 1,
  "last_page": 1,
  "total": 1
}

Open auctions expose highest_amount. Closed auctions omit it. Platform requests without bidder_reference omit own_amount and bidder_status. All standings remain provisional.

GET /api/v1/events/{event}/lots/{lot} Get an event lot

Fetch a vehicle’s public fields and the authenticated bidder’s current standing. Required scope: catalogue:read.

ParameterLocationTypeRequiredMeaning
eventpathstringYesPublic auction ID returned by List events.
lotpathstringYesPublic lot ID, not an inventory vehicle ID.
bidder_referencequerystringNoOptional platform/aggregator buyer identity. Max 120 letters, digits, underscores or hyphens. Direct dealers omit this.

Request pattern

GET /api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "data": {
    "vehicle_details": {
      "registration_number": "MH01AB1234",
      "make": "Mahindra",
      "model": "Bolero Pick Up",
      "year": 2020,
      "region": "West",
      "vehicle_type": "CV",
      "yard": null,
      "title": "Mahindra Bolero Pick Up",
      "bank_reference": "VL0000000126740",
      "condition": "Inspection recorded"
    },
    "images": [
      "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/1"
    ],
    "documents": [
      "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/2"
    ],
    "id": "lot_EXAMPLE",
    "auction_id": "auc_EXAMPLE",
    "registration_number": "MH01AB1234",
    "make": "Mahindra",
    "model": "Bolero Pick Up",
    "year": 2020,
    "region": "West",
    "vehicle_type": "CV",
    "starting_price": "143600.00",
    "public_fields": {},
    "own_amount": null,
    "bidder_status": "no_bid",
    "channel_status": "no_bid",
    "provisional": true,
    "highest_amount": null
  }
}

Saved bank fields are merged into vehicle_details using the bank-saved field names; standard vehicle keys take precedence. Repeated bank names receive numbered suffixes. Images and documents are full PANBIDS URLs for uploaded or assigned extracted files. Download them with HMAC authentication. Ready photos uploaded or extracted in PANBIDS are included for authorized lots, including photos with default private visibility. Documents must be auction-visible.

GET /api/v1/events/{event}/lots/{lot}/media/{media} Download lot media

Retrieve an authorised auction photo or document as a binary response. Required scope: catalogue:read.

ParameterLocationTypeRequiredMeaning
eventpathstringYesPublic auction ID returned by List events.
lotpathstringYesPublic lot ID, not an inventory vehicle ID.
mediapathintegerYesBank-supplied numeric media ID authorised for this lot.

Request pattern

GET /api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/1
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

Content-Type: image/jpeg (or the stored document MIME type)
Cache-Control: private, no-store
Content-Disposition: inline for photos; attachment for documents

[binary bytes - not JSON]

Use a full URL from images[] or documents[] in the lot response and sign its exact path. Photos are inline; documents are attachments. An inaccessible or missing file returns 404.

GET /api/v1/lots List all lots

Retrieve a compact catalogue across all permitted auctions. Required scope: catalogue:read.

ParameterLocationTypeRequiredMeaning
pagequeryintegerNoPage number, starting at 1.

Request pattern

GET /api/v1/lots?page=1
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "data": [
    {
      "vehicle_details": {
        "registration_number": "MH01AB1234",
        "make": "Mahindra",
        "model": "Bolero Pick Up",
        "year": 2020,
        "region": "West",
        "vehicle_type": "CV",
        "yard": null,
        "title": "Mahindra Bolero Pick Up",
        "bank_reference": "VL0000000126740",
        "condition": "Inspection recorded"
      },
      "images": [
        "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/1"
      ],
      "documents": [
        "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/2"
      ],
      "id": "lot_EXAMPLE",
      "auction_id": "auc_EXAMPLE",
      "title": "Mahindra Bolero Pick Up",
      "category": "CV",
      "starting_price": "143600.00",
      "status": "live",
      "ends_at": "2026-09-13T13:38:00+00:00",
      "public_fields": {}
    }
  ],
  "current_page": 1,
  "last_page": 1,
  "total": 1
}

Fixed page size: 25. Withdrawn, cancelled and unavailable inventory is excluded.

GET /api/v1/vehicles/{vehicle} Get vehicle summary

Fetch the compact vehicle representation using its public auction lot ID. Required scope: vehicles:read.

ParameterLocationTypeRequiredMeaning
vehiclepathstringYesUse a lot public ID, not an inventory vehicle ID.

Request pattern

GET /api/v1/vehicles/lot_EXAMPLE
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "data": {
    "vehicle_details": {
      "registration_number": "MH01AB1234",
      "make": "Mahindra",
      "model": "Bolero Pick Up",
      "year": 2020,
      "region": "West",
      "vehicle_type": "CV",
      "yard": null,
      "title": "Mahindra Bolero Pick Up",
      "bank_reference": "VL0000000126740",
      "condition": "Inspection recorded"
    },
    "images": [
      "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/1"
    ],
    "documents": [
      "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/2"
    ],
    "id": "lot_EXAMPLE",
    "auction_id": "auc_EXAMPLE",
    "title": "Mahindra Bolero Pick Up",
    "category": "CV",
    "starting_price": "143600.00",
    "status": "live",
    "ends_at": "2026-09-13T13:38:00+00:00",
    "public_fields": {}
  }
}

Use the event-lot endpoint for the extended public fields and bidder standing.

POST /api/v1/lots/{lot}/bids Submit a bid

Submit a bid to the central auction authority. The server validates time, access, deposit, buyer limit and bid increments. Required scope: bids:write.

ParameterLocationTypeRequiredMeaning
lotpathstringYesPublic lot ID, not an inventory vehicle ID.
dealer_idbodystringYesRequired bank-issued bidding dealer reference. Max 32 characters.
amountbodydecimalYesPositive amount; at most 12 integer digits and 2 decimal places.
idempotency_keybodyUUIDYesRequired. Send the same UUID in the Idempotency-Key header. Reuse it only for an identical retry.
bidder_referencebodystringFor platform bidsRequired for platform/aggregator bids: stable actual buyer ID, 1-120 letters, digits, underscores or hyphens. Direct dealers must omit.
client_bid_timebodydatetimeNoOptional client timestamp. Server time determines acceptance.

Request pattern

POST /api/v1/lots/lot_EXAMPLE/bids
Accept: application/json
Content-Type: application/json
Idempotency-Key: SAME_UUID_AS_BODY
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST
{
  "dealer_id": "dlr_EXAMPLE",
  "bidder_reference": "buyer_123",
  "amount": "145600.00",
  "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace the illustrative UUID with a newly generated UUID. Omit bidder_reference for a direct dealer.

Example response - HTTP 201

{
  "success": true,
  "code": "BID_ACCEPTED",
  "message": "Bid accepted; this is not a sale approval.",
  "data": {
    "request_id": "req_EXAMPLE",
    "bid_id": "bid_EXAMPLE",
    "status": "accepted",
    "server_received_at": "2026-09-11T14:00:00+00:00",
    "lot_version": 2,
    "effective_close_at": "2026-09-13T13:38:00+00:00",
    "replayed": false,
    "bidder_status": "leading",
    "channel_status": "leading",
    "highest_amount": "145600.00",
    "current_amount": 145600
  },
  "errors": [],
  "request_id": "req_EXAMPLE",
  "timestamp": "2026-09-11T14:00:00+00:00"
}

201 accepted; 200 identical replay. First bids must meet opening; later open bids must exceed the highest bid. Closed bids can be below the hidden leader but must match the opening grid. Acceptance is not sale approval.

GET /api/v1/bids List your bids

Review the bids submitted by your authenticated dealer and channel. Required scope: bids:read.

ParameterLocationTypeRequiredMeaning
pagequeryintegerNoPage number, starting at 1.
bidder_referencequerystringNoOptional platform/aggregator buyer identity. Max 120 letters, digits, underscores or hyphens. Direct dealers omit this.

Request pattern

GET /api/v1/bids?page=1
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "current_page": 1,
  "data": [
    {
      "public_id": "bid_EXAMPLE",
      "bidder_reference": null,
      "amount": "145600.00",
      "status": "accepted",
      "created_at": "2026-09-11 14:00:00"
    }
  ],
  "first_page_url": "https://panbids.com/api/v1/bids?page=1",
  "from": 1,
  "last_page": 1,
  "last_page_url": "https://panbids.com/api/v1/bids?page=1",
  "links": [
    {
      "url": null,
      "label": "Previous",
      "active": false
    },
    {
      "url": "https://panbids.com/api/v1/bids?page=1",
      "label": "1",
      "active": true
    },
    {
      "url": null,
      "label": "Next",
      "active": false
    }
  ],
  "next_page_url": null,
  "path": "https://panbids.com/api/v1/bids",
  "per_page": 25,
  "prev_page_url": null,
  "to": 1,
  "total": 1
}

Fixed page size: 25. The response includes Laravel pagination metadata. Filter by bidder_reference to isolate one platform buyer.

GET /api/v1/results List auction results

Retrieve accessible lots whose auctions have closed. Required scope: results:read.

ParameterLocationTypeRequiredMeaning
pagequeryintegerNoPage number, starting at 1.

Request pattern

GET /api/v1/results?page=1
Accept: application/json
X-Client-ID: YOUR_CLIENT_ID
X-Key-ID: YOUR_KEY_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: NEW_NONCE_PER_ATTEMPT
X-Content-SHA256: SHA256_OF_EXACT_BODY
X-Signature: HMAC_SHA256_OF_CANONICAL_REQUEST

Example response - HTTP 200

{
  "data": [
    {
      "vehicle_details": {
        "registration_number": "MH01AB1234",
        "make": "Mahindra",
        "model": "Bolero Pick Up",
        "year": 2020,
        "region": "West",
        "vehicle_type": "CV",
        "yard": null,
        "title": "Mahindra Bolero Pick Up",
        "bank_reference": "VL0000000126740",
        "condition": "Inspection recorded"
      },
      "images": [
        "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/1"
      ],
      "documents": [
        "https://panbids.com/api/v1/events/auc_EXAMPLE/lots/lot_EXAMPLE/media/2"
      ],
      "id": "lot_EXAMPLE",
      "auction_id": "auc_EXAMPLE",
      "title": "Mahindra Bolero Pick Up",
      "category": "CV",
      "starting_price": "143600.00",
      "status": "over",
      "ends_at": "2026-09-13T13:38:00+00:00",
      "public_fields": {}
    }
  ],
  "current_page": 1,
  "last_page": 1
}

Requires a results entitlement in addition to API scope. Fixed page size: 25. Closed status is not a sale confirmation or release authorisation.

How to read the response

Field / shapeMeaning
dataOne object for detail routes; an array for list routes. Do not expect a success flag on catalogue responses.
current_page, last_page, totalEvents, event lots and /lots include these. /results omits total. /bids returns Laravel pagination including links and next_page_url.
id / auction_idPublic lot ID and public auction ID. IDs are opaque strings, not vehicle registration or bank references.
starting_price / bid_incrementStarting price belongs to the lot; increment belongs to its event. Amounts are INR; use decimal strings and integer paise arithmetic.
vehicle_detailsStandard keys plus bank-saved field labels as keys, including private saved fields shared with authorized partners. Standard keys win exact collisions; repeated bank labels receive numbered suffixes. Values retain nulls, empty strings and saved types.
public_fieldsAuction-visible form fields keyed by software field ID, each containing label and value. This separate compatibility field still uses IDs.
images / documentsArrays of absolute PANBIDS download URLs. Ready photos include uploaded and assigned extracted photos; documents must be auction-visible. Deleted, quarantined and other-tenant media are excluded. Empty array means no eligible files. Bank media_url is a source field, not this download list.
own_amount / bidder_statusLatest own accepted amount and no_bid/leading/outbid. Platform GET requests without bidder_reference omit these fields; direct dealers omit the query parameter.
channel_statusWhether your channel holds the leading accepted bid; may differ from one buyer's bidder_status.
highest_amountReturned for open auctions, null if none. Omitted for closed auctions.
provisionalBid standing is not final sale approval. Results likewise do not authorize release.
bid_id / status / replayedA rejected bid can have an ID. Check accepted/rejected and errors. replayed means this UUID was already recorded.
lot_version / effective_close_atVersion after processing and effective closing time, including extensions. Timestamps carry timezone offsets; server time governs bidding.
current_amountConditional numeric field in bid responses when an accepted bid belongs to an auction with open visibility_mode.

Displaying photos

Fetch each images[] URL on your backend with a new signed GET request using catalogue:read, then serve the bytes through your own authorized image route. A normal img src cannot attach HMAC headers. Do not put the signing secret in a query string. /inventory/media/{id} is the bank-console route and requires a bank session. Keep documents subject to the same partner authorization.

Errors and recovery

Read every item in errors: code is only the first reason. The API uses both application envelopes and Laravel errors. Do not assume all failures have the same shape. Local tester validation and proxy failures can have message-only responses too.

HTTPCode / conditionAction
401API_CLIENT_NOT_ACTIVE / KEY_REVOKEDUse an active client and current matching key. API_CLIENT_NOT_ACTIVE can also occur with 403 when API access is revoked.
401TIMESTAMP_EXPIRED / INVALID_NONCE / INVALID_SIGNATUREClock within 300 seconds; nonce 16-128 allowed characters; exact body digest, path and sorted RFC3986 query; six canonical lines without trailing newline.
403TLS_REQUIRED / ENVIRONMENT_DENIED / IP_NOT_ALLOWED / SCOPE_DENIEDHTTPS, matching environment, approved actual outbound IP and required client scope.
403PARTNER_NOT_ACTIVE / KYB_REQUIRED / AGREEMENT_REQUIREDBank and partner active, KYB approved/current and required agreements effective.
402 or 403BANK_UNAVAILABLEBank subscription inactive; status depends on the layer rejecting the request.
403BANK_ACCESS_DENIED / AUCTION_ACCESS_DENIEDLot must belong to the partner bank and have the relevant approved assignment and entitlement.
403BUYER_NOT_ELIGIBLEdealer_id must equal the linked dealer public ID; partner must have a linked dealer.
403BUYER_LIMIT_EXPIRED / EMD_EXPIREDBank must renew the approved commercial expiry dates.
422DEALER_NOT_ELIGIBLEDealer blocked, KYC not approved, EMD not valid or amount exceeds buyer_limit. Active partner is insufficient.
422BIDDER_REFERENCE_REQUIRED / DIRECT_DEALER_IDENTITY_REQUIREDPlatform/aggregator must provide stable buyer reference. Direct dealer must omit it.
422BID_OFF_OPENING_GRIDUse opening + N * positive increment. 300000 fails for opening 281200 with increment 2000.
422BID_BELOW_MINIMUMOpen: meet central highest + increment. Closed: meet own previous accepted + increment. Legacy auctions use previous or opening + increment.
422LOT_NOT_LIVEAuction must be published and within its live server-time window; lot not withdrawn/cancelled.
422RESOURCE_NOT_GRANTED / CHANNEL_NOT_GRANTED / BUYER_NOT_ENTITLED_TO_CLIENT / DEALER_NOT_FOUNDCheck bank ownership, channel listing, client/dealer relationship and dealer existence with bank administrator.
422IDEMPOTENCY_KEY_REQUIREDSet Idempotency-Key header equal to JSON idempotency_key.
409NONCE_REPLAYEDGenerate a fresh nonce and signature per attempt, retaining the bid UUID on identical retries.
409IDEMPOTENCY_CONFLICTA stored UUID belongs to different bid content. New intended bid needs a new UUID. May be returned as message rather than code.
404Not FoundResource missing or not accessible to this partner; do not infer another partner's inventory.
422Laravel validation errorsInspect errors object for invalid or missing fields, UUID, amount, reference or query values.
429Too Many RequestsRespect Retry-After; rate limit is 120 requests/minute. Retry a bid only with its original UUID.
500 / networkServer Error / timeoutOutcome can be uncertain. Preserve payload and UUID; reconcile your bids, retry identically and provide request ID/time to support.

Recorded rejection - HTTP 422

{
  "success": false,
  "code": "DEALER_NOT_ELIGIBLE",
  "message": "Bid rejected by authoritative validation.",
  "data": {
    "request_id": "req_EXAMPLE",
    "bid_id": "bid_EXAMPLE",
    "status": "rejected",
    "server_received_at": "2026-09-12T04:11:48+00:00",
    "lot_version": 1,
    "effective_close_at": "2026-09-13T13:38:00+00:00",
    "replayed": false,
    "bidder_status": "no_bid",
    "channel_status": "no_bid",
    "highest_amount": null
  },
  "errors": [
    "DEALER_NOT_ELIGIBLE",
    "BID_OFF_OPENING_GRID"
  ],
  "request_id": "req_EXAMPLE",
  "timestamp": "2026-09-12T04:11:48+00:00"
}

Authentication rejection - HTTP 403

{
  "success": false,
  "code": "BUYER_NOT_ELIGIBLE",
  "message": "Buyer not eligible",
  "data": null,
  "errors": [
    "BUYER_NOT_ELIGIBLE"
  ],
  "request_id": "req_EXAMPLE",
  "timestamp": "2026-09-12T04:11:48+00:00"
}

Input validation - HTTP 422

{
  "message": "The idempotency key field must be a valid UUID.",
  "errors": {
    "idempotency_key": [
      "The idempotency key field must be a valid UUID."
    ]
  }
}

Generic failure - HTTP 500

{
  "message": "Server Error"
}

Never log signing secrets. Record the request ID, HTTP status, error codes, bid ID and original idempotency key for diagnosis. Webhook delivery is not enabled; use polling for standings.

Winner updates: API and webhooks

A bank approval commits one sale.approved event. PANBIDS immediately updates the auctioneer portal, exposes it through the winner-update API, and queues the same event for the partner's verified webhook. The stable bidder_reference tells a marketplace which bidder account to update.

After approval, subscribe to sale.acknowledged, payment.reported, payment.verified, payment.allocated, sale.payment_status_changed, release.authorized, release.revoked, vehicle.status_changed, and vehicle.collected to keep the bidder-facing sale, payment, release, and vehicle status current. A vehicle.status_changed payload includes sale_id, lot_id, vehicle_id, previous_vehicle_status, vehicle_status, and the inventory/resource versions.

OptionContractRecovery
Pull APIGET /api/v1/winner-updates?after=CURSOR&limit=50
Scope: sales:read
Persist next_cursor. Repeat the same cursor safely after a timeout.
Push webhookSubscribe to sale.approved with scope webhooks:manage.Deduplicate event IDs. Use the pull API after downtime or an ordering gap.

Subscription sequence

  1. Create the subscription with an HTTPS URL, event list, and UUID idempotency key. Store the returned whsec_ secret; it is separate from the API signing secret.
  2. Implement the verification response. PANBIDS posts webhook.endpoint_verification; return HTTP 2xx JSON containing the same top-level challenge.
  3. Call the verify endpoint. Only a verified subscription becomes active.
  4. For every delivery, validate the signature against the exact raw request bytes before parsing JSON.
  5. Return 2xx quickly, deduplicate PANBIDS-Event-ID, and update the bidder identified by data.sale.bidder_reference.
POST /api/v1/webhook-subscriptions
{
  "name": "Production winner receiver",
  "url": "https://partner.example/webhooks/panbids",
  "events": ["auction.schedule_changed", "sale.approved", "sale.rejected", "vehicle.status_changed", "release.authorized", "vehicle.collected"],
  "idempotency_key": "UUID"
}

Delivery signature

Read PANBIDS-Timestamp and PANBIDS-Signature. Compute lowercase hex HMAC-SHA256 of timestamp + "." + raw_body with the subscription secret. Compare it to the value after v1= using a constant-time comparison. Reject stale timestamps according to your replay policy.

$expected = hash_hmac('sha256', $timestamp.'.'.$rawBody, $webhookSecret);
$valid = hash_equals('v1='.$expected, $signatureHeader);

Approved winner payload

{
  "id": "workflow-event-uuid",
  "type": "sale.approved",
  "schema_version": 1,
  "created_at": "2026-09-13T12:00:00+00:00",
  "data": {
    "resource_id": "sale_EXAMPLE",
    "resource_version": 2,
    "lot_id": "lot_EXAMPLE",
    "sale": {
      "id": "sale_EXAMPLE",
      "state": "approved",
      "winner": true,
      "bank_decision_final": true,
      "bank_confirmation_required": false,
      "buyer_acknowledgment_required": true,
      "bid_id": "bid_EXAMPLE",
      "bidder_reference": "buyer_123",
      "amount": "301200.00",
      "currency": "INR",
      "terms_version": "terms-4",
      "due_at": "2026-09-15T12:00:00+05:30"
    }
  }
}

Buyer acknowledgment records receipt or terms acceptance when required; it does not wait for another bank confirmation. Payment and release remain separate bank-controlled states.

Auction closing-time payload

When the bank extends or shortens a published auction, PANBIDS sends this event to every active assigned auctioneer subscription. Treat effective_close_at as authoritative, discard an older resource_version, and refresh the event resource after reconnecting.

{
  "id": "schedule-event-uuid",
  "type": "auction.schedule_changed",
  "schema_version": 1,
  "created_at": "2026-09-13T12:00:00+00:00",
  "data": {
    "auction_id": "auc_EXAMPLE",
    "resource_version": 7,
    "direction": "extended",
    "scheduled_end_at": "2026-09-13T15:00:00+00:00",
    "previous_effective_close_at": "2026-09-13T15:00:00+00:00",
    "effective_close_at": "2026-09-13T16:00:00+00:00",
    "timezone": "Asia/Kolkata",
    "refresh_path": "/api/v1/events/auc_EXAMPLE"
  }
}

Delivery behavior

Delivery is at least once. PANBIDS does not follow redirects, revalidates the destination before each attempt, blocks private and reserved network addresses, uses bounded timeouts, and retries transient failures with backoff for up to eight attempts. HTTP 2xx records transport acknowledgment. Authorized partners can inspect delivery logs and replay a delivered or terminally failed event.

Integration and post-auction API catalog

54 implemented operations are listed in this deployment. Download the OpenAPI operation index. The remaining workbook operations are listed separately below.

This reference, API permission choices and onboarding email operation lists use the same catalog. Bank-service credentials and partner-service credentials are distinct. An API scope never grants another bank's records or bank decision authority. Existing credentials do not automatically receive new scopes.

Workflow commands require an idempotency_key UUID and matching Idempotency-Key header. Versioned decisions also require the record's current expected_version. Retries must preserve the exact JSON bytes. Accepted workflow commands return HTTP 200; Idempotent-Replayed: true identifies a replay. This differs from the bid endpoint's 201/200 response convention.

The shared host blocks native PATCH and PUT. For these operations, send HTTP POST with "_method": "PATCH" or "_method": "PUT" included in the signed JSON. Use that effective method in the HMAC canonical string. The generated examples and playground use this transport; authentication, permissions and idempotency still apply to the effective operation.

GET /api/v1/integration/profile A01 - Integration

Return environment, bank/partner/client IDs, actor type, permissions and permitted operations.

Scope: integration:read. Allowed actors: bank, partner.

Derive tenant from credentials. Never return signing secrets. Separate bank-service and partner-service credentials.

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": {
        "environment": "production",
        "bank_id": "bank_EXAMPLE",
        "partner_id": "ptn_EXAMPLE",
        "client_id": "pb_production_EXAMPLE",
        "actor_type": "partner",
        "partner_type": "platform",
        "dealer_id": "dlr_EXAMPLE",
        "scopes": [
            "integration:read"
        ],
        "operations": [
            {
                "id": "A01",
                "method": "GET",
                "path": "/api/v1/integration/profile",
                "scope": "integration:read",
                "title": "Integration",
                "actors": [
                    "bank",
                    "partner"
                ]
            },
            {
                "id": "A02",
                "method": "GET",
                "path": "/api/v1/integration/capabilities",
                "scope": "integration:read",
                "title": "Integration",
                "actors": [
                    "bank",
                    "partner"
                ]
            }
        ]
    },
    "server_time": "2026-09-13T10:00:00+00:00"
}
GET /api/v1/integration/capabilities A02 - Integration

Discover API versions, cancellation mode, visibility policy, quotas, webhook support and server_time.

Scope: integration:read. Allowed actors: bank, partner.

Return effective bank policy and policy_version. A feature flag must reflect deployed capability.

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": {
        "api_versions": [
            "v1"
        ],
        "policy_version": "conservative-1",
        "bid_visibility": {
            "open": "highest_and_own_status",
            "closed": "own_status_without_highest"
        },
        "cancellation_mode": "bank_approval_required",
        "sale_approval": "explicit_bank_decision",
        "payment_verification": "bank_receipt_verification",
        "webhooks": {
            "enabled": false
        },
        "realtime": {
            "enabled": false
        },
        "operations": []
    },
    "server_time": "2026-09-13T10:00:00+00:00"
}
GET /api/v1/bidding-eligibility A03 - Eligibility

Read own KYC, EMD, limit, expiry and lot eligibility. Query lot_id and scoped buyer reference.

Scope: eligibility:read. Allowed actors: partner.

Diagnostic snapshot only. Recheck every constraint inside bid acceptance transaction.

Query example

lot_id=lot_EXAMPLE&bidder_reference=buyer_123&amount=281200.00

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": {
        "eligible": false,
        "diagnostic_only": true,
        "errors": [
            "DEALER_NOT_ELIGIBLE"
        ],
        "dealer_id": "dlr_EXAMPLE",
        "kyc_status": "approved",
        "emd_status": "pending",
        "blocked": false,
        "buyer_limit": "0.00",
        "limit_until": null,
        "emd_until": null,
        "lot_id": "lot_EXAMPLE",
        "starting_price": "281200.00",
        "bid_increment": "1000.00",
        "notice": "This snapshot reserves no buying power. Bid acceptance rechecks authoritative constraints."
    },
    "server_time": "2026-09-13T10:00:00+00:00"
}
GET /api/v1/bids/{bid} A05 - Bidding

Read accepted/rejected state, owner reference, receipt, lot version and request ID for one bid.

Scope: bids:read. Allowed actors: bank, partner.

Owning partner sees its own records. Bank sees its tenant. A bid ID alone never proves acceptance.

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "bid_EXAMPLE",
        "lot_id": "lot_EXAMPLE",
        "bidder_reference": "buyer_123",
        "amount": "300000.00",
        "status": "rejected",
        "request_id": "req_EXAMPLE",
        "server_received_at": "2026-09-13T10:00:00+00:00",
        "lot_version": 1,
        "errors": [
            "BID_OFF_OPENING_GRID"
        ]
    },
    "server_time": "2026-09-13T10:00:00+00:00"
}
GET /api/v1/bid-requests/{idempotency_key} A06 - Bidding

Resolve an uncertain timeout by original key: processing, accepted, rejected or absent.

Scope: bids:read. Allowed actors: partner.

Key namespace includes environment and API client. Absent is time-bounded evidence; retry original command only.

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": {
        "idempotency_key": "c5fefb02-6b55-4992-8c45-4f75994d4b28",
        "state": "absent",
        "observed_at": "2026-09-13T10:00:00+00:00",
        "receipt": null,
        "retry": "Retry only the original command and key. Absent does not prove no in-flight request exists."
    },
    "server_time": "2026-09-13T10:00:00+00:00"
}
POST /api/v1/bids/{bid}/cancellation-requests A07 - Cancellation

Submit reason_code, explanation and evidence. Return request ID and pending/approved decision state.

Scope: bids:cancel-request. Allowed actors: partner.

Default requires bank approval. Only explicitly permitted policy can auto-approve. Do not delete the bid.

Request body

{
    "reason_code": "ENTERED_IN_ERROR",
    "explanation": "Explain the cancellation request",
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "cancellation_EXAMPLE",
        "kind": "cancellation",
        "state": "pending",
        "resource_version": 1,
        "data": {
            "reason_code": "ENTERED_IN_ERROR",
            "explanation": "Explain the cancellation request"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/bid-cancellation-requests A08 - Cancellation

Filter requests by bid, lot and decision status for bank review and dealer tracking.

Scope: bids:cancel-read. Allowed actors: bank, partner.

Tenant and bidder ownership filters apply before pagination.

Query example

page=1

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "items": [
            {
                "id": "cancellation_EXAMPLE",
                "kind": "cancellation",
                "state": "pending",
                "resource_version": 1,
                "data": {
                    "bid_id": "bid_EXAMPLE",
                    "reason_code": "ENTRY_ERROR",
                    "explanation": "Request bank review of this bid",
                    "policy_version": "conservative-1"
                },
                "created_at": "2026-09-13T10:00:00+00:00",
                "updated_at": "2026-09-13T10:00:00+00:00"
            }
        ],
        "current_page": 1,
        "last_page": 1,
        "total": 1
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/bid-cancellation-requests/{request}/decisions A09 - Cancellation

Approve or reject with reason, expected_version and decision ID.

Scope: bids:cancel-approve. Allowed actors: bank.

Atomically change effective bid, standings and exposure. Superseded bids do not revive. After close, re-award needs separate bank approval.

Request body

{
    "decision": "approved",
    "reason": "Bank reviewed cancellation",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "cancellation_EXAMPLE",
        "kind": "cancellation",
        "state": "approved",
        "resource_version": 2,
        "data": {
            "decision": "approved",
            "reason": "Bank reviewed cancellation"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/lots/{lot}/status A10 - Lot status

Read auction_state, inventory_state, own standing, sale/payment/release summaries and allowed_actions.

Scope: lot-status:read. Allowed actors: partner.

Project fields by role and visibility policy. Provide resource_version, effective_close_at and updated_at.

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": {
        "lot_id": "lot_EXAMPLE",
        "auction_state": "live",
        "inventory_state": "ready",
        "resource_version": 1,
        "updated_at": "2026-09-13T10:00:00+00:00",
        "effective_close_at": "2026-09-14T10:00:00+00:00",
        "sale": null,
        "payment": null,
        "release": null,
        "allowed_actions": [
            "read"
        ],
        "provisional": true,
        "own_standing": "no_bid",
        "own_amount": null,
        "highest_amount": null
    },
    "server_time": "2026-09-13T10:00:00+00:00"
}
POST /api/v1/lots/status-batch A11 - Lot status

Read status for a bounded list of lot IDs in one request.

Scope: lot-status:read. Allowed actors: partner.

Read-only POST. Per-item authorization and errors. Proposed maximum 100 IDs; confirm through load testing.

Request body

{
    "lot_ids": [
        "lot_EXAMPLE"
    ],
    "bidder_reference": "buyer_123"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": [
        {
            "lot_id": "lot_EXAMPLE",
            "status": 200,
            "data": {
                "lot_id": "lot_EXAMPLE",
                "auction_state": "live",
                "inventory_state": "ready",
                "resource_version": 1,
                "updated_at": "2026-09-13T10:00:00+00:00",
                "effective_close_at": "2026-09-14T10:00:00+00:00",
                "sale": null,
                "payment": null,
                "release": null,
                "allowed_actions": [
                    "read"
                ],
                "provisional": true,
                "own_standing": "no_bid",
                "own_amount": null,
                "highest_amount": null
            }
        },
        {
            "lot_id": "lot_UNAVAILABLE",
            "status": 404,
            "code": "NOT_FOUND"
        }
    ],
    "server_time": "2026-09-13T10:00:00+00:00"
}
GET /api/v1/sale-cases A20 - Sale approval

Read provisional winner, pending bank decision, confirmed award and deadlines.

Scope: sales:read. Allowed actors: bank, partner.

Separate sale-case identity from lot and vehicle. Only eligible buyer receives private offer detail.

Query example

page=1

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "items": [
            {
                "id": "sale_EXAMPLE",
                "kind": "sale",
                "state": "approved",
                "resource_version": 2,
                "data": {
                    "bid_id": "bid_EXAMPLE",
                    "bidder_reference": "buyer_123",
                    "amount": "281200.00",
                    "currency": "INR",
                    "terms_version": "terms-1",
                    "acknowledged_at": null,
                    "lot_id": "lot_EXAMPLE",
                    "due_at": "2026-09-15T10:00:00+00:00",
                    "payee_instructions": "Use the bank-approved payment instructions",
                    "payee_version": 1
                },
                "created_at": "2026-09-13T10:00:00+00:00",
                "updated_at": "2026-09-13T10:00:00+00:00"
            }
        ],
        "current_page": 1,
        "last_page": 1,
        "total": 1
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/sale-cases/{sale} A21 - Sale approval

Read sale version, approved bid, decision history, payable amount and document references.

Scope: sales:read. Allowed actors: bank, partner.

Highest accepted bid remains provisional until authorized bank decision.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "sale_EXAMPLE",
        "kind": "sale",
        "state": "approved",
        "resource_version": 2,
        "data": {
            "bid_id": "bid_EXAMPLE",
            "bidder_reference": "buyer_123",
            "amount": "281200.00",
            "currency": "INR",
            "terms_version": "terms-1",
            "acknowledged_at": null,
            "lot_id": "lot_EXAMPLE",
            "due_at": "2026-09-15T10:00:00+00:00",
            "payee_instructions": "Use the bank-approved payment instructions",
            "payee_version": 1
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/sale-cases/{sale}/decisions A22 - Sale approval

Approve or reject a provisional award with bid_id, terms_version, reason and expected_version.

Scope: sales:approve. Allowed actors: bank.

Enforce bank approval limits and maker-checker if configured. Verify bid still valid and vehicle still available.

Request body

{
    "decision": "approved",
    "bid_id": "bid_EXAMPLE",
    "reason": "Bank approved the sale",
    "terms_version": "1",
    "due_at": "2026-10-01T12:00:00+05:30",
    "payee_instructions": "Bank-approved remittance instructions",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event. If a negotiation offer exists, approval also requires offer_id matching the active accepted offer, unexpired validity and matching terms_version. The negotiated amount is applied only by this explicit bank decision.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "sale_EXAMPLE",
        "kind": "sale",
        "state": "approved",
        "resource_version": 2,
        "data": {
            "decision": "approved",
            "bid_id": "bid_EXAMPLE",
            "reason": "Bank approved the sale",
            "terms_version": "1",
            "due_at": "2026-10-01T12:00:00+05:30",
            "payee_instructions": "Bank-approved remittance instructions"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/sale-cases/{sale}/acknowledgments A23 - Bidder confirmation

Record that the bidder received the bank decision and terms.

Scope: sales:acknowledge. Allowed actors: partner.

Acknowledgment is not a new bid, bank approval or payment. If buyer acceptance is required, model a separate acceptance state.

Request body

{
    "terms_version": "1",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "sale_EXAMPLE",
        "kind": "sale",
        "state": "approved",
        "resource_version": 2,
        "data": {
            "terms_version": "1"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/sale-cases/{sale}/offers A24 - Negotiation

Issue a priced counteroffer with validity deadline and terms version.

Scope: offers:write. Allowed actors: bank.

One active offer version. Preserve original auction bids; never overwrite history or reveal rival bids.

Request body

{
    "amount": "281200.00",
    "currency": "INR",
    "terms_version": "terms-1",
    "valid_until": "2026-12-01T12:00:00+00:00",
    "reason": "Bank proposes a revised sale price",
    "expected_version": 1,
    "idempotency_key": "REPLACE_WITH_NEW_UUID"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200: open offer record. Prior open or accepted offers are superseded. Original auction bid stays unchanged. GET sale detail includes active_offer. The sale remains pending bank approval.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "offer_EXAMPLE",
        "kind": "offer",
        "state": "open",
        "resource_version": 2,
        "data": {
            "amount": "281200.00",
            "currency": "INR",
            "terms_version": "terms-1",
            "valid_until": "2026-12-01T12:00:00+00:00",
            "reason": "Bank proposes a revised sale price"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/offers/{offer}/responses A25 - Negotiation

Accept, decline or propose a counteroffer if policy permits.

Scope: offers:respond. Allowed actors: partner.

Recheck expiry and version atomically. Revised prices require the configured bank approval sequence.

Request body

{
    "decision": "accepted",
    "terms_version": "terms-1",
    "reason": "Buyer accepts these proposed terms",
    "expected_version": 1,
    "idempotency_key": "REPLACE_WITH_NEW_UUID"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200: accepted or declined offer record. Conservative policy does not allow buyer-created counteroffers. Acceptance does not approve the sale: the bank must submit A22 with this offer_id, matching terms_version and the current sale expected_version before the offer expires.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "offer_EXAMPLE",
        "kind": "offer",
        "state": "accepted",
        "resource_version": 2,
        "data": {
            "decision": "accepted",
            "terms_version": "terms-1",
            "reason": "Buyer accepts these proposed terms"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/sale-cases/{sale}/cancellation-requests A26 - Sale cancellation

Request cancellation after bank approval, citing reason and evidence.

Scope: sales:cancel-request. Allowed actors: bank, partner.

Use this instead of bid cancellation after sale approval. Trigger assessment of money and release obligations.

Request body

{
    "reason_code": "CANCELLATION",
    "explanation": "Explain the sale cancellation",
    "expected_version": 1,
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200 workflow record. Refund approval reserves funds and returns approved_pending_execution; it does not claim a completed bank transfer.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "sale_cancellation_EXAMPLE",
        "kind": "sale_cancellation",
        "state": "pending",
        "resource_version": 2,
        "data": {
            "reason_code": "CANCELLATION",
            "explanation": "Explain the sale cancellation"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/sale-cancellation-requests/{request}/decisions A27 - Sale cancellation

Approve/reject cancellation and create required reversal/refund work items.

Scope: sales:cancel-approve. Allowed actors: bank.

Never erase approved sale or cash records. Delivered vehicle requires an exception/dispute workflow.

Request body

{
    "decision": "approved",
    "reason": "Bank reviewed the request",
    "expected_version": 1,
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200 workflow record. Refund approval reserves funds and returns approved_pending_execution; it does not claim a completed bank transfer.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "sale_cancellation_EXAMPLE",
        "kind": "sale_cancellation",
        "state": "approved",
        "resource_version": 2,
        "data": {
            "decision": "approved",
            "reason": "Bank reviewed the request"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/sale-cases/{sale}/payment-dues A34 - Payment dues

Return instalments, due dates, verified credits, remaining balance and verified payee instructions.

Scope: payments:read. Allowed actors: bank, partner.

Compute from approved terms and allocation ledger. Version payee instructions; secure any bank-account change.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "sale_id": "sale_EXAMPLE",
        "currency": "INR",
        "due_amount": "281200.00",
        "verified_credits": "0.00",
        "remaining": "281200.00",
        "excess": "0.00",
        "state": "unpaid",
        "due_at": "2026-09-15T10:00:00+00:00",
        "payee_instructions": "Use the bank-approved payment instructions",
        "payee_version": 1,
        "resource_version": 2
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/payment-reports A36 - Payment reporting

Submit sale_id, amount, currency, method, UTR/provider ID, paid_at, evidence and external reference.

Scope: payments:report. Allowed actors: partner.

Return reported_pending_verification. Dealer cannot assert verified, settled or release-authorized.

Request body

{
    "sale_id": "sale_EXAMPLE",
    "amount": "281200.00",
    "currency": "INR",
    "method": "bank_transfer",
    "utr": "BANK_UTR",
    "paid_at": "2026-09-12T10:00:00+05:30",
    "external_reference": "payment_1",
    "evidence_id": "document_EXAMPLE",
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "payment_report_EXAMPLE",
        "kind": "payment_report",
        "state": "reported_pending_verification",
        "resource_version": 1,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "amount": "281200.00",
            "currency": "INR",
            "method": "bank_transfer",
            "utr": "BANK_UTR",
            "paid_at": "2026-09-12T10:00:00+05:30",
            "external_reference": "payment_1",
            "evidence_id": "document_EXAMPLE"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/payment-reports/{report} A37 - Payment reporting

Track verification, rejection reasons, matched receipt and allocation outcomes.

Scope: payments:read. Allowed actors: bank, partner.

Return source, verifier, verified_at and reconciliation reference when available.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "payment_report_EXAMPLE",
        "kind": "payment_report",
        "state": "reported_pending_verification",
        "resource_version": 1,
        "data": [],
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/payment-reports/{report}/decisions A38 - Payment verification

Accept or reject a reported transfer after checking the bank receipt/statement.

Scope: payments:verify. Allowed actors: bank.

Require evidence of bank receipt and independent approver when policy requires. Idempotent decision with version check.

Request body

{
    "decision": "verified",
    "reason": "Bank receipt checked",
    "bank_receipt_id": "bank_receipt_EXAMPLE",
    "bank_account_reference": "BANK_ACCOUNT",
    "received_amount": "281200.00",
    "currency": "INR",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "payment_report_EXAMPLE",
        "kind": "payment_report",
        "state": "verified",
        "resource_version": 2,
        "data": {
            "decision": "verified",
            "reason": "Bank receipt checked",
            "bank_receipt_id": "bank_receipt_EXAMPLE",
            "bank_account_reference": "BANK_ACCOUNT",
            "received_amount": "281200.00",
            "currency": "INR"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/payments/{payment} A40 - Payment status

Read authoritative verified receipt, allocations, refund/dispute status and separate settlement state.

Scope: payments:read. Allowed actors: bank, partner.

A report ID and payment ID are different. Summaries never add unverified reports to paid balance.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "payment_EXAMPLE",
        "kind": "payment",
        "state": "succeeded",
        "resource_version": 1,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "amount": "281200.00",
            "currency": "INR",
            "settlement_state": "bank_received"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/bank-receipts/imports A42 - Bank receipts

Ingest statement/API receipt entries with external transaction identity and value date.

Scope: receipts:import. Allowed actors: bank.

Allowlisted schema and trusted bank credentials. Deduplicate by bank account and transaction identity; never by amount alone.

Request body

{
    "sale_id": "sale_EXAMPLE",
    "bank_account_reference": "BANK_ACCOUNT",
    "utr": "BANK_UTR",
    "external_transaction_id": "BANK_TXN",
    "amount": "281200.00",
    "currency": "INR",
    "value_date": "2026-09-12",
    "evidence_id": "document_EXAMPLE",
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "bank_receipt_EXAMPLE",
        "kind": "bank_receipt",
        "state": "verified",
        "resource_version": 1,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "bank_account_reference": "BANK_ACCOUNT",
            "utr": "BANK_UTR",
            "external_transaction_id": "BANK_TXN",
            "amount": "281200.00",
            "currency": "INR",
            "value_date": "2026-09-12",
            "evidence_id": "document_EXAMPLE"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/payments/{payment}/allocations A45 - Payment allocation

Allocate verified funds to one or more sale dues with per-sale amounts.

Scope: payments:allocate. Allowed actors: bank.

Lock allocation totals. Never exceed verified unallocated funds or credit the same receipt twice.

Request body

{
    "sale_id": "sale_EXAMPLE",
    "amount": "281200.00",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "allocation_EXAMPLE",
        "kind": "allocation",
        "state": "allocated",
        "resource_version": 2,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "amount": "281200.00",
            "payment_id": "payment_EXAMPLE",
            "amount_paise": 10000,
            "currency": "INR"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/sale-cases/{sale}/receipts A46 - Receipts

Fetch verified payment receipt and invoice/document references.

Scope: documents:read. Allowed actors: bank, partner.

Issuer, document version and private download authorization required. Do not infer statutory invoice fields.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "sale_id": "sale_EXAMPLE",
        "payments": [],
        "allocations": [],
        "documents": []
    },
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/payments/{payment}/refund-requests A47 - Refunds

Request full or partial refund with amount and reason.

Scope: refunds:request. Allowed actors: bank, partner.

Request only. Bank approval and provider processing occur separately. Refundable amount excludes previous/pending refunds.

Request body

{
    "amount": "100.00",
    "reason": "Explain the refund request",
    "expected_version": 1,
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200 workflow record. Refund approval reserves funds and returns approved_pending_execution; it does not claim a completed bank transfer.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "refund_request_EXAMPLE",
        "kind": "refund_request",
        "state": "pending",
        "resource_version": 2,
        "data": {
            "amount": "100.00",
            "reason": "Explain the refund request"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/refund-requests/{request}/decisions A48 - Refunds

Approve/reject; approved request starts a provider refund operation.

Scope: refunds:approve. Allowed actors: bank.

Keep decision, provider request, completion and settlement/reversal separate. Never label refund complete on initiation.

Request body

{
    "decision": "approved",
    "reason": "Bank reviewed the request",
    "expected_version": 1,
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200 workflow record. Refund approval reserves funds and returns approved_pending_execution; it does not claim a completed bank transfer.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "refund_request_EXAMPLE",
        "kind": "refund_request",
        "state": "approved",
        "resource_version": 2,
        "data": {
            "decision": "approved",
            "reason": "Bank reviewed the request",
            "refund_id": "refund_EXAMPLE"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/refunds/{refund} A49 - Refunds

Track requested, processing, succeeded or failed and provider/ARN references.

Scope: refunds:read. Allowed actors: bank, partner.

Reconcile callbacks with provider inquiry. Idempotent operation key survives retries.

HTTP 200 workflow record. Refund approval reserves funds and returns approved_pending_execution; it does not claim a completed bank transfer.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "refund_EXAMPLE",
        "kind": "refund",
        "state": "approved_pending_execution",
        "resource_version": 1,
        "data": {
            "request_id": "refund_request_EXAMPLE",
            "payment_id": "payment_EXAMPLE",
            "amount_paise": 10000,
            "currency": "INR",
            "execution": "provider_or_bank_confirmation_required"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/disputes A50 - Disputes

Raise bid, payment, condition or delivery dispute with evidence and desired resolution.

Scope: disputes:write. Allowed actors: bank, partner.

Freeze only affected actions under bank policy. Record deadlines and owner; preserve all original records.

Request body

{
    "sale_id": "sale_EXAMPLE",
    "reason_code": "PAYMENT_QUERY",
    "explanation": "Explain the dispute",
    "evidence_id": "document_EXAMPLE",
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "dispute_EXAMPLE",
        "kind": "dispute",
        "state": "open",
        "resource_version": 1,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "reason_code": "PAYMENT_QUERY",
            "explanation": "Explain the dispute",
            "evidence_id": "document_EXAMPLE"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/disputes/{dispute} A51 - Disputes

Read evidence requests, timeline, current hold and resolution.

Scope: disputes:read. Allowed actors: bank, partner.

Only authorized parties see documents. External chargebacks are separately linked provider disputes.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "dispute_EXAMPLE",
        "kind": "dispute",
        "state": "open",
        "resource_version": 1,
        "data": [],
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/sale-cases/{sale}/release-authorizations A52 - Vehicle release

Issue an expiring release authorization with recipient, yard and allowed collection date.

Scope: release:approve. Allowed actors: bank.

Require approved sale, buyer requirements, required verified funds and no active hold. Payment report alone cannot unlock release.

Request body

{
    "recipient": "Approved collector",
    "yard": "Assigned yard",
    "expires_at": "2026-10-02T12:00:00+05:30",
    "collection_date": "2026-10-01",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "release_EXAMPLE",
        "kind": "release",
        "state": "valid",
        "resource_version": 2,
        "data": {
            "recipient": "Approved collector",
            "yard": "Assigned yard",
            "expires_at": "2026-09-15T10:00:00+00:00",
            "collection_date": "2026-10-01",
            "sale_id": "sale_EXAMPLE"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/release-authorizations/{release} A53 - Vehicle release

Read valid/revoked/expired/used state and necessary collection instructions.

Scope: release:read. Allowed actors: bank, partner.

Minimize buyer PII by role. QR/token contains opaque reference, not unrestricted personal data.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "release_EXAMPLE",
        "kind": "release",
        "state": "valid",
        "resource_version": 1,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "expires_at": "2026-09-15T10:00:00+00:00"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/release-authorizations/{release}/revocations A54 - Vehicle release

Revoke an unused authorization due to hold, reversal or cancellation.

Scope: release:revoke. Allowed actors: bank.

Race-safe with collection redemption. A used authorization opens an exception; history is not rewritten.

Request body

{
    "reason": "Bank revoked authorization",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "release_EXAMPLE",
        "kind": "release",
        "state": "revoked",
        "resource_version": 2,
        "data": {
            "reason": "Bank revoked authorization",
            "sale_id": "sale_EXAMPLE",
            "expires_at": "2026-09-15T10:00:00+00:00"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/release-authorizations/{release}/collections A56 - Collection

Redeem authorization once and record collector check, handover time and evidence.

Scope: collection:confirm. Allowed actors: bank.

Atomic one-time redemption. Recheck active release, funds/hold policy and vehicle identity at pickup.

Request body

{
    "collector": "Approved collector",
    "vehicle_identity": "lot_EXAMPLE",
    "evidence_id": "document_EXAMPLE",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "release_EXAMPLE",
        "kind": "release",
        "state": "used",
        "resource_version": 2,
        "data": {
            "collector": "Approved collector",
            "vehicle_identity": "lot_EXAMPLE",
            "evidence_id": "document_EXAMPLE",
            "sale_id": "sale_EXAMPLE",
            "expires_at": "2026-09-15T10:00:00+00:00"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/sale-cases/{sale}/transfer-updates A57 - Ownership transfer

Record submitted, pending-documents, completed or rejected transfer milestones.

Scope: transfer:write. Allowed actors: bank.

Label operator-reported versus independently verified status. Government data access requires an authorized provider agreement.

Request body

{
    "status": "submitted",
    "responsible_party": "Bank transfer team",
    "reason": "Transfer application submitted",
    "evidence_id": "document_EXAMPLE",
    "document_checklist": [
        "Application receipt"
    ],
    "occurred_at": "2026-09-12T10:00:00+05:30",
    "idempotency_key": "00000000-0000-4000-8000-000000000001",
    "expected_version": 1
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "transfer_EXAMPLE",
        "kind": "transfer",
        "state": "submitted",
        "resource_version": 2,
        "data": {
            "status": "submitted",
            "responsible_party": "Bank transfer team",
            "reason": "Transfer application submitted",
            "evidence_id": "document_EXAMPLE",
            "document_checklist": [
                "Application receipt"
            ],
            "occurred_at": "2026-09-12T10:00:00+05:30",
            "sale_id": "sale_EXAMPLE",
            "verification": "operator_reported",
            "government_verified": false
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/sale-cases/{sale}/transfer-status A58 - Ownership transfer

Read document checklist, milestones, responsible party and evidence timestamps.

Scope: transfer:read. Allowed actors: bank, partner.

Do not imply direct access to RC/VAHAN or legal completion without verified evidence.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "sale_id": "sale_EXAMPLE",
        "state": "not_started",
        "government_verified": false,
        "milestones": [],
        "resource_version": 2
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/bank/inventory/vehicles A59 - Inventory

Create canonical vehicle using versioned dynamic schema and bank external_id.

Scope: inventory:write. Allowed actors: bank.

Private inventory identity is distinct from published lot ID. Detect duplicate external references within bank.

Request body

{
    "title": "Example vehicle",
    "external_id": "BANK_INVENTORY_001",
    "schema_version": 1,
    "values": [],
    "idempotency_key": "REPLACE_WITH_NEW_UUID"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200: inventory_command record. data.vehicle_id is the private inventory UUID, data.inventory_version is the value required as expected_version on a later patch. Creates draft inventory only. PATCH merges supplied dynamic field IDs; omitted values are preserved. Ready or published inventory requires a controlled portal amendment and returns 409. Retrieve field IDs using the bank schema API; bank display labels remain unchanged in published vehicle responses.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "inventory_command_EXAMPLE",
        "kind": "inventory_command",
        "state": "completed",
        "resource_version": 1,
        "data": {
            "vehicle_id": "5f5fcbb0-934f-4f85-92ca-f0b6753c8a53",
            "inventory_version": 1,
            "status": "draft",
            "external_id": "BANK_INVENTORY_001",
            "schema_version": 1,
            "title": "Example vehicle"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

PATCH /api/v1/bank/inventory/vehicles/{vehicle} A60 - Inventory

Update approved inventory fields using expected_version and field IDs.

Scope: inventory:write. Allowed actors: bank.

Changes material to a live sale require a controlled revision and partner notification. No direct bid edits.

Request body

{
    "title": "Corrected vehicle title",
    "values": [],
    "expected_version": 1,
    "idempotency_key": "REPLACE_WITH_NEW_UUID",
    "_method": "PATCH"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

HTTP 200: inventory_command record. data.vehicle_id is the private inventory UUID, data.inventory_version is the value required as expected_version on a later patch. Creates draft inventory only. PATCH merges supplied dynamic field IDs; omitted values are preserved. Ready or published inventory requires a controlled portal amendment and returns 409. Retrieve field IDs using the bank schema API; bank display labels remain unchanged in published vehicle responses. On this shared host send HTTP POST with _method: PATCH inside the exact signed JSON. Sign PATCH as the canonical method; Laravel authenticates the effective method. Native PATCH is blocked by the host before the application.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "inventory_command_EXAMPLE",
        "kind": "inventory_command",
        "state": "completed",
        "resource_version": 1,
        "data": {
            "vehicle_id": "5f5fcbb0-934f-4f85-92ca-f0b6753c8a53",
            "inventory_version": 2,
            "status": "draft",
            "external_id": "BANK_INVENTORY_001",
            "schema_version": 1,
            "title": "Example vehicle"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/bank/inventory/schemas A63 - Dynamic schema

Return allowed field IDs, labels, types, enum values and schema version.

Scope: inventory-schema:read. Allowed actors: bank.

Field visibility is explicit. Stable IDs survive renaming. Partner projection excludes private bank fields.

JSON data plus server_time; HMAC authenticated and permission-scoped.

Illustrative response (not a live transaction)

{
    "data": [
        {
            "schema_version": 1,
            "name": "Vehicle inventory",
            "version": 1,
            "fields": []
        }
    ],
    "server_time": "2026-09-13T10:00:00+00:00"
}
POST /api/v1/document-uploads A72 - Documents

Create an upload session with purpose, media type, byte size and associated object.

Scope: documents:write. Allowed actors: bank, partner.

Bound size/type, quarantine and scan before use. Access checked on upload finalization and each download.

Request body

{
    "sale_id": "sale_EXAMPLE",
    "purpose": "payment_evidence",
    "filename": "receipt.pdf",
    "content_base64": "REPLACE_WITH_BASE64_FILE",
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "document_EXAMPLE",
        "kind": "document",
        "state": "awaiting_scan",
        "resource_version": 1,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "purpose": "payment_evidence",
            "filename": "receipt.pdf",
            "mime": "application/pdf",
            "bytes": 1234,
            "digest": "SHA256_OF_UPLOADED_FILE"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/documents/{document} A73 - Documents

Read metadata, checksum, version and authorized download link/route for payment or sale evidence.

Scope: documents:read. Allowed actors: bank, partner.

Short-lived downloads remain object-scoped. Existing C05 media stays backward compatible.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "document_EXAMPLE",
        "kind": "document",
        "state": "awaiting_scan",
        "resource_version": 1,
        "data": {
            "sale_id": "sale_EXAMPLE",
            "purpose": "payment_evidence",
            "filename": "receipt.pdf",
            "mime": "application/pdf",
            "bytes": 1234,
            "digest": "SHA256_OF_UPLOADED_FILE"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00",
        "download_url": "https://panbids.com/api/v1/documents/document_EXAMPLE?download=1"
    }
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

GET /api/v1/notifications A74 - Notifications

Read bank decisions, due reminders and release messages for the authenticated audience.

Scope: notifications:read. Allowed actors: bank, partner.

Durable inbox complements webhook delivery. Message locale is separate from stable API status codes.

Query example

page=1

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": [
        {
            "id": "c5fefb02-6b55-4992-8c45-4f75994d4b28",
            "type": "sale.approved",
            "subject": "sale_EXAMPLE",
            "resource_version": 2,
            "created_at": "2026-09-13T10:00:00+00:00",
            "acknowledgment": null
        }
    ],
    "current_page": 1,
    "last_page": 1,
    "total": 1
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

POST /api/v1/notifications/{notification}/acknowledgments A75 - Notifications

Record delivered/read acknowledgment with external reference.

Scope: notifications:acknowledge. Allowed actors: partner.

A message read receipt does not accept a sale or verify payment. Preserve distinct business acknowledgments.

Request body

{
    "status": "read",
    "external_reference": "notice_1",
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
}

Replace placeholder IDs, dates, amounts and UUID with the intended request. expected_version must come from the current record. Never reuse an example UUID for a new command.

JSON data contains an owned workflow record, or the read shape documented below. Commands require matching Idempotency-Key, use exact-body replay and return HTTP 200. State changes are committed with a workflow event.

Illustrative response (not a live transaction)

{
    "data": {
        "id": "notification_ack_EXAMPLE",
        "kind": "notification_ack",
        "state": "read",
        "resource_version": 1,
        "data": {
            "status": "read",
            "external_reference": "notice_1"
        },
        "created_at": "2026-09-13T10:00:00+00:00",
        "updated_at": "2026-09-13T10:00:00+00:00"
    },
    "request_id": "req_EXAMPLE",
    "server_time": "2026-09-13T10:00:00+00:00"
}

Record fields: id, kind, state, resource_version, data, created_at, updated_at. GET list routes A08/A20 return data.items plus pagination inside data. Notifications use a top-level data array and top-level pagination. Document metadata adds download_url; use signed GET with download=1 for binary bytes after state becomes ready. Receipts return sale_id, payments, allocations and document references. Transfer status returns sale_id, state, government_verified, milestones and resource_version. Payment dues return amounts and payee instructions, not a workflow record.

SMTP notifications and server commands

Committed workflow events queue messages for active, verified partner contacts and the bank's active, verified super-admin users. SMTP delivery runs every minute, retries transport failures up to five times and records the outcome. A notification acknowledgment records delivery or reading; it does not approve a sale, credit a payment or authorize release. SMTP can deliver duplicates if a process stops after delivery but before recording success; use the notification event ID to recognize duplicates.

php artisan schedule:run
php artisan workflows:reconcile
php artisan workflows:scan-documents
php artisan workflows:payment-reminders
php artisan workflows:send-mail
php artisan workflows:send-webhooks
php artisan workflows:retry-mail OUTBOX_ID

The server cron must run php artisan schedule:run once per minute from the Laravel application directory. The application uses its existing SMTP host, credentials and sender configuration. workflows:retry-mail requeues one failed or unconfigured message after the transport is corrected; it does not resend successful messages.

Private evidence remains awaiting_scan until the configured INVENTORY_SCANNER executable reports it clean. Configure a compatible scanner before using bank receipts, payment evidence, collection or transfer evidence. The API does not bypass this check when the scanner is unavailable.

Bank-service credential provisioning

Bank decisions use separate credentials tied to an existing verified bank super-admin. A server administrator provisions explicit scopes and public source IPs with the command below. Use actual approved values. The secret is written to a private file with restricted permissions and is not printed in the command output. Transfer that file securely to the bank service and remove the export afterward. Partner credentials cannot perform bank approvals.

php artisan bank-api:issue BANK_PUBLIC_ID USER_ID --scope=integration:read --scope=sales:read --scope=sales:approve --ip=PUBLIC_SOURCE_IP

Grant partner scopes through the auctioneer API permission screen. New scopes are not added to existing credentials automatically. Discovery at GET /api/v1/integration/profile reports the operations allowed to the caller.

Planned operations - not callable

These workbook operations are not advertised as available and their scopes cannot be selected. Provider-dependent capabilities require approved connections; no simulated verification, funds or government status is returned.

IDPriorityRequestDependencies
A12P0GET /api/v1/changesTransactional outbox
A13P0POST /api/v1/webhook-subscriptionsA01; delivery service
A14P0GET /api/v1/webhook-subscriptionsA13
A15P0PATCH /api/v1/webhook-subscriptions/{subscription}A13
A16P0GET /api/v1/webhook-deliveriesA13
A17P0POST /api/v1/webhook-deliveries/{delivery}/replayA16
A18P0POST /api/v1/webhook-subscriptions/{subscription}/testA13
A19P0POST /api/v1/realtime/sessionsA01; event fan-out
A28P0GET /api/v1/depositsDeposit ledger
A29P1POST /api/v1/depositsA28; A39
A30P1POST /api/v1/deposits/{deposit}/refund-requestsA28; A47
A31P0GET /api/v1/buying-powerBuyer ledger; A03
A32P1POST /api/v1/buyer-limit-requestsA31
A33P1POST /api/v1/buyer-limit-requests/{request}/decisionsA32
A35P1POST /api/v1/sale-cases/{sale}/payment-ordersA34; approved provider account
A39P0POST /api/v1/payment-reports/{report}/verification-attemptsA36; provider adapter
A41P0POST /api/v1/provider-webhooks/payu/{connection}Provider adapter; A40
A43P0POST /api/v1/reconciliationsA36; A40; A42 when automated
A44P0GET /api/v1/reconciliations/{reconciliation}A43
A55P1POST /api/v1/sale-cases/{sale}/collection-appointmentsA52
A61P0POST /api/v1/bank/inventory/vehicles/{vehicle}/status-transitionsA10; vehicle/lot mapping; A12
A62P1POST /api/v1/bank/inventory/importsA59; A63; A78
A64P1POST /api/v1/bank/auctionsBank service identity
A65P1POST /api/v1/bank/auctions/{auction}/lotsA64; A59
A66P1PUT /api/v1/bank/auctions/{auction}/assignmentsA65; A12
A67P1POST /api/v1/bank/auctions/{auction}/publicationsA65; A66
A68P1POST /api/v1/bank/auctions/{auction}/transitionsA67; A12
A69P0POST /api/v1/bank/auctions/{auction}/extensionsAuthoritative timing service; A12
A70P1POST /api/v1/bank/partnersBank service identity
A71P1POST /api/v1/bank/partners/{partner}/transitionsA70; A01
A76P0GET /api/v1/audit-eventsAuthoritative audit log
A77P1POST /api/v1/report-exportsA78; A76
A78P1GET /api/v1/operations/{operation}Async task store
A79P2POST /api/v1/lots/{lot}/proxy-bid-instructionsStable bidding engine; approved policy
A80P2POST /api/v1/proxy-bid-instructions/{instruction}/revocationsA79; A07
A81P2POST /api/v1/risk-review-jobsA76; permissioned data
A82P2POST /api/v1/valuation-jobsA59; authorized data provider
A83P2POST /api/v1/vehicle-check-jobsA59; provider access agreement
A84P2POST /oauth/tokenIdentity service; enterprise requirement
A85P1POST /api/v1/api-clients/{client}/key-rotationsA01; key management
A86P2POST /api/v1/integration-acknowledgmentsA13; event ledger

API playground

Explore every endpoint. Choose a language, inspect the signed request, and try it with your own credentials.

Requests run against http://www.panbids.com/index.php/api/v1. POST executes the selected command in this environment; the bid endpoint submits a real bid. No requests run until you press Send.

● ● ● REQUEST EXAMPLE

Terminal command

Example response Illustrative data

Language icons by Magnific (Freepik) on Flaticon: PHP, JavaScript, Python, Ruby. Terminal icon by Bharat Icons - Flaticon.

Live response

Ready.