VPDS Blockchain API
Blockchain-as-a-Service over Hyperledger Fabric. An authorised government application calls REST endpoints with an API key and never handles a Fabric private key, certificate, wallet, MSP or peer address. That boundary is the product.
- 50operations
- 19write to the ledger
- 31read only
- 23platform endpoints
X-API-Key. A body field maps one-to-one onto a chaincode parameter — nothing was renamed or invented — and the numbering is the positional order the contract receives them in. Signed by is what the chaincode itself enforces at the peers, not a courtesy: a call from the wrong organisation is refused on-chain even if this gateway let it through.X-Officer-Role, bounded by the set that key may assert — or an officer, in which case the role, the organisation and whether they are still active are read from the credential itself and there is nothing left to assert. Either way the signing identity is derived from the key and can never be chosen by a request, and no caller is ever issued Fabric key material. Officer credentials are created, rotated and revoked through /api/blockchain/officers by a key registered with officerAdmin.Showing 50 of 50 operations, and 23 of 23 platform endpoints
RegistryContract
Beneficiary and family identity — the DID registry, officer approval records, and ingestion manifests.
- POST
/api/blockchain/approvalsWriteAnchor an officer's signed registration decision.
Parameters of ApproveRegistration, in the order the chaincode receives them # Name Type In Required 1 caseCodestring body yes 2 familyDIDstring body yes 3 payloadHashhash64 body yes 4 decisionstring body yes 5 signaturestring body yes - POST
/api/blockchain/didsWriteRegister a W3C-style DID for a card, family or member.
Parameters of CreateDID, in the order the chaincode receives them # Name Type In Required 1 didstring body yes 2 subjectTypestring body yes 3 subjectRefstring body yes 4 controllerstring body yes 5 publicKeyHashhash64 body yes 6 metadatastring body optional - POST
/api/blockchain/ingestion-manifestsWriteAnchor the digest of an ePDS / Smart-PDS ingestion batch.
Parameters of RecordIngestionManifest, in the order the chaincode receives them # Name Type In Required 1 batchCodestring body yes 2 sourceRefstring body yes 3 mappingVersionstring body yes 4 recordCountinteger body yes 5 manifestHashhash64 body yes - POST
/api/blockchain/dids/:did/revokeWriteRevoke a DID. State-level act — district officers are excluded on-chain.
Parameters of RevokeDID, in the order the chaincode receives them # Name Type In Required 1 didstring path yes 2 reasonstring body optional - PUT
/api/blockchain/dids/:didWriteRe-anchor a DID document (new key hash and/or metadata).
Parameters of UpdateDID, in the order the chaincode receives them # Name Type In Required 1 didstring path yes 2 publicKeyHashhash64 body optional 3 metadatastring body optional - GET
/api/blockchain/approvals/:caseCodeReadRead the current approval record for a registration case.
Parameters of GetApproval, in the order the chaincode receives them # Name Type In Required 1 caseCodestring path yes - GET
/api/blockchain/approvals/:caseCode/historyReadEvery decision ever recorded against a case, including reversals.
Parameters of GetApprovalHistory, in the order the chaincode receives them # Name Type In Required 1 caseCodestring path yes - GET
/api/blockchain/dids/:did/historyReadFull version history of a DID document.
Parameters of GetDIDHistory, in the order the chaincode receives them # Name Type In Required 1 didstring path yes - GET
/api/blockchain/ingestion-manifests/:batchCodeReadRead an ingestion manifest.
Parameters of GetIngestionManifest, in the order the chaincode receives them # Name Type In Required 1 batchCodestring path yes - GET
/api/blockchain/ingestion-manifests/:batchCode/historyReadEvery manifest version recorded for an ingestion batch.
Parameters of GetIngestionManifestHistory, in the order the chaincode receives them # Name Type In Required 1 batchCodestring path yes - GET
/api/blockchain/dids/:didReadRead a DID document.
Parameters of ResolveDID, in the order the chaincode receives them # Name Type In Required 1 didstring path yes - GET
/api/blockchain/dids/:did/verifyReadCheck whether a DID exists, is active and is unrevoked.
Parameters of VerifyDID, in the order the chaincode receives them # Name Type In Required 1 didstring path yes
VerificationContract
What the system has CONCLUDED about a household — screening verdicts and risk assessments.
- POST
/api/blockchain/risk-assessmentsWriteAnchor a fraud risk score, band and the rule codes that fired.
Parameters of RecordRiskAssessment, in the order the chaincode receives them # Name Type In Required 1 cardRefstring body yes 2 riskScorestring body yes 3 riskBandstring body yes 4 ruleCodesstring body yes 5 evidenceHashhash64 body yes 6 rulesVersionstring body yes - POST
/api/blockchain/screeningsWriteAnchor an eligibility screening verdict (AAY / PHH / NPHH / Rejected).
Parameters of RecordScreening, in the order the chaincode receives them # Name Type In Required 1 cardRefstring body yes 2 resultHashhash64 body yes 3 eligibilityCategorystring body yes 4 screeningStatusstring body yes - GET
/api/blockchain/screenings/:cardRefReadRead the current screening record for a card.
Parameters of GetScreening, in the order the chaincode receives them # Name Type In Required 1 cardRefstring path yes - GET
/api/blockchain/screenings/:cardRef/historyReadEvery screening and risk assessment recorded for a card.
Parameters of GetScreeningHistory, in the order the chaincode receives them # Name Type In Required 1 cardRefstring path yes
LifecycleContract
The append-only beneficiary lifecycle log — births, deaths, migrations, bifurcations.
- POST
/api/blockchain/registry-eventsWriteAppend a lifecycle event (birth, death, migration, bifurcation, …).
Parameters of RecordRegistryEvent, in the order the chaincode receives them # Name Type In Required 1 eventIDstring body yes 2 cardRefstring body yes 3 memberRefstring body optional 4 eventTypestring body yes 5 detailHashhash64 body yes - GET
/api/blockchain/registry-events/by-card/:cardRefReadA card's full lifecycle log, oldest first.
Parameters of QueryRegistryEventsByCard, in the order the chaincode receives them # Name Type In Required 1 cardRefstring path yes
SupplyChainContract
Grain movement from procurement to FPS receipt — batches, dispatches, transport, receipts, exceptions, and the 3-way delivery match.
- POST
/api/blockchain/dispatches/:dispatchID/receiptWriteConfirm delivery receipt at a State Warehouse or Fair Price Shop.
Parameters of ConfirmReceipt, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes 2 receivedQtynumber body yes 3 fpsSignstring body optional 4 qrScanstring body yes - POST
/api/blockchain/batchesWriteCreate a procurement batch at an FCI godown, with quality capture.
Parameters of CreateBatch, in the order the chaincode receives them # Name Type In Required 1 batchIDstring body yes 2 grainTypestring body yes 3 quantityMTnumber body yes 4 sourceWHstring body yes 5 destFPSstring body yes 6 schemestring body yes 7 stageinteger body yes 8 originTypestring body yes 9 destTypestring body yes 10 parentBatchIDstring body optional 11 qualityGradestring body optional 12 moisturePctnumber body optional 13 inspectionRefstring body optional 14 inspectorDIDstring body optional - POST
/api/blockchain/batches/childWriteSplit a received batch into an onward consignment for an FPS.
Parameters of CreateChildBatch, in the order the chaincode receives them # Name Type In Required 1 childBatchIDstring body yes 2 parentBatchIDstring body yes 3 stateWarehouseIDstring body yes 4 destFPSstring body yes 5 schemestring body optional - POST
/api/blockchain/dispatchesWriteDispatch a consignment: vehicle, driver, GPS device and planned route.
Parameters of CreateDispatch, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring body yes 2 batchIDstring body yes 3 vehicleRegstring body yes 4 driverIDstring body yes 5 gpsDeviceIDstring body yes 6 routeJSONjson body yes 7 dispatchQtynumber body yes - POST
/api/blockchain/dispatches/:dispatchID/exceptionWriteRaise a receipt discrepancy (shortage, damage, quality).
Parameters of EscalateReceiptException, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes 2 receivedQtynumber body yes 3 reasonstring body optional 4 detailstring body optional - POST
/api/blockchain/dispatches/:dispatchID/exception/resolveWriteClose a receipt exception with a resolution note.
Parameters of ResolveReceiptException, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes 2 notestring body optional - POST
/api/blockchain/dispatches/:dispatchID/transportWriteValidate a consignment in transit against its AIS-140 GPS trail.
Parameters of ValidateTransport, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes 2 gpsEventsJSONjson body yes 3 driverSignaturestring body yes 4 transportQtyMTnumber body yes 5 deviationToleranceKMnumber body yes - POST
/api/blockchain/dispatches/:dispatchID/verificationWriteRun the 3-way match and anchor the VERIFIED / FAILED verdict.
Parameters of VerifyDelivery, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes - GET
/api/blockchain/batches/:batchIDReadRead one batch.
Parameters of GetBatch, in the order the chaincode receives them # Name Type In Required 1 batchIDstring path yes - GET
/api/blockchain/batches/:batchID/historyReadEvery ledger version of a batch, with transaction ids.
Parameters of GetBatchHistory, in the order the chaincode receives them # Name Type In Required 1 batchIDstring path yes - GET
/api/blockchain/dispatches/:dispatchIDReadRead one dispatch.
Parameters of GetDispatch, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes - GET
/api/blockchain/dispatches/:dispatchID/exceptionReadRead the open exception on a dispatch.
Parameters of GetDispatchException, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes - GET
/api/blockchain/exceptions/:exceptionIDReadRead one exception by its own id.
Parameters of GetException, in the order the chaincode receives them # Name Type In Required 1 exceptionIDstring path yes - GET
/api/blockchain/dispatches/:dispatchID/exception/historyReadEvery state an exception passed through, with transaction ids.
Parameters of GetExceptionHistory, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes - GET
/api/blockchain/dispatches/:dispatchID/receiptReadRead the receipt recorded against a dispatch.
Parameters of GetReceipt, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes - GET
/api/blockchain/dispatches/:dispatchID/verificationReadRead the 3-way match verdict for a dispatch.
Parameters of GetVerification, in the order the chaincode receives them # Name Type In Required 1 dispatchIDstring path yes - GET
/api/blockchain/batches/by-stage/:stageReadList batches at one stage of the two-stage chain.
Parameters of QueryBatchesByStage, in the order the chaincode receives them # Name Type In Required 1 stageinteger path yes - GET
/api/blockchain/batchesReadList batches, optionally filtered by status. Empty status = all.
Parameters of QueryBatchesByStatus, in the order the chaincode receives them # Name Type In Required 1 statusstring query optional - GET
/api/blockchain/batches/by-warehouse/:warehouseIDReadList batches originating at one warehouse.
Parameters of QueryBatchesByWarehouse, in the order the chaincode receives them # Name Type In Required 1 warehouseIDstring path yes - GET
/api/blockchain/dispatchesReadList dispatches, optionally filtered by status. Empty status = all.
Parameters of QueryDispatches, in the order the chaincode receives them # Name Type In Required 1 statusstring query optional - GET
/api/blockchain/batches/:batchID/dispatchesReadEvery dispatch raised against a batch.
Parameters of QueryDispatchesByBatch, in the order the chaincode receives them # Name Type In Required 1 batchIDstring path yes - GET
/api/blockchain/exceptionsReadList exceptions, optionally filtered by status and severity.
Parameters of QueryExceptions, in the order the chaincode receives them # Name Type In Required 1 statusstring query optional 2 severitystring query optional
DistributionContract
The last mile — the immutable proof that grain was issued from a Fair Price Shop to a household.
- POST
/api/blockchain/distributionsWriteAnchor grain issued from an FPS to a household. No PII on-chain.
Parameters of RecordDistribution, in the order the chaincode receives them # Name Type In Required 1 receiptNumberstring body yes 2 cardDIDstring body optional 3 memberDIDstring body optional 4 fpsIDstring body yes 5 itemsJSONjson body yes 6 cycleMonthstring body yes 7 receiptHashhash64 body optional - POST
/api/blockchain/entitlement-qrsWriteAnchor a cycle's entitlement QR. Refuses a second QR for the same card and cycle.
Parameters of RecordEntitlementQR, in the order the chaincode receives them # Name Type In Required 1 familyDIDstring body optional 2 cardDIDstring body yes 3 cycleMonthstring body yes 4 qrHashhash64 body yes 5 expiresAtstring body yes - GET
/api/blockchain/distributions/:receiptNumberReadRead one distribution receipt.
Parameters of GetDistribution, in the order the chaincode receives them # Name Type In Required 1 receiptNumberstring path yes - GET
/api/blockchain/entitlement-qrs/:cardDID/:cycleMonthReadRead the anchored QR for a card and cycle.
Parameters of GetEntitlementQR, in the order the chaincode receives them # Name Type In Required 1 cardDIDstring path yes 2 cycleMonthstring path yes - GET
/api/blockchain/distributions/by-card/:cardDIDReadA household's full collection history.
Parameters of QueryDistributionsByCardDID, in the order the chaincode receives them # Name Type In Required 1 cardDIDstring path yes - GET
/api/blockchain/distributions/by-fps/:fpsIDReadEverything one Fair Price Shop has issued.
Parameters of QueryDistributionsByFPS, in the order the chaincode receives them # Name Type In Required 1 fpsIDstring path yes
AuditContract
Platform audit anchors — the record of an administrative ACTION, and the type-agnostic ledger key history reader.
- POST
/api/blockchain/audit-anchorsWriteAnchor the digest of a platform action so its off-chain row cannot be edited undetected.
Parameters of RecordAuditAnchor, in the order the chaincode receives them # Name Type In Required 1 auditIDstring body yes 2 categorystring body yes 3 actorRolestring body yes 4 payloadHashhash64 body yes - GET
/api/blockchain/audit-anchors/:auditIDReadRead one audit anchor.
Parameters of GetAuditAnchor, in the order the chaincode receives them # Name Type In Required 1 auditIDstring path yes - GET
/api/blockchain/ledger/keys/:key/historyReadType-agnostic history of any ledger key — the explorer's trail reader.
Parameters of GetHistoryForKey, in the order the chaincode receives them # Name Type In Required 1 keystring path yes - GET
/api/blockchain/audit-anchorsReadList audit anchors in one category.
Parameters of QueryAuditAnchorsByCategory, in the order the chaincode receives them # Name Type In Required 1 categorystring query yes
Platform endpoints
Everything that is not a chaincode call: issuing and revoking the credentials that decide who may make one, following the chain, reading it, and the gateway’s own health. Authenticated with the same X-API-Key.
Officers
Per-officer credentials — an API key that identifies a PERSON, and the signing keypair the gateway holds for them. Administered by a client registered with "officerAdmin": true; an officer credential can never administer credentials, including its own.
- GET
/api/blockchain/officersThe officer roster.
role (query)status (query)limit (query) - POST
/api/blockchain/officersCreate an officer and issue their first API key.
Issues an API key and an EC P-256 signing keypair. The private half never leaves this service; the API key is returned once and stored only as a SHA-256 hash, so a lost key is rotated rather than recovered.
- GET
/api/blockchain/officers/{id}One officer, with their key history.
id (path, required) - PATCH
/api/blockchain/officers/{id}Change the label.
The label, and nothing else. Role and MSP are immutable: the certificate carries the role, and every signature made before a change must keep meaning what it meant. Changing an officer's role means a new credential.
id (path, required) - POST
/api/blockchain/officers/{id}/attestationsSign a payload hash as this officer.
What crosses the wire is a hash, never a document: whatever the officer approved is the calling application's business, and what this attests is that the holder of that officer's key saw a payload with this digest.
id (path, required) - POST
/api/blockchain/officers/{id}/keysRotate: issue a new key and revoke every previous one.
The officer keeps their id, their signing keypair and every signature they have already made. Only what they authenticate with changes — which is why a lost laptop is a rotation rather than a re-creation.
id (path, required) - DELETE
/api/blockchain/officers/{id}/keys/{keyId}Revoke one key.
id (path, required)keyId (path, required) - PATCH
/api/blockchain/officers/{id}/statusDeactivate or re-activate an officer.
Deactivating refuses their calls with a 403 that names them and LEAVES the key intact, so re-activating works with the key the caller already holds. revokeKeys: true is the separate, louder act for a credential believed exposed.
id (path, required) - GET
/api/blockchain/officers/meWho this key belongs to.
The one officer route an OFFICER credential may call. It discloses nothing the holder of the key does not already have.
Events
Follow the chain. Server-Sent Events, resumable from any height with ?startBlock= — which is how a consumer that was down catches up without a Fabric connection.
- GET
/api/blockchain/events/blocksFollow every committed block, decoded.
Every block as it commits, already decoded — the feed a consumer builds its own read model from. The VPDS application's PostgreSQL ledger index is fed entirely from this stream. Full detail (arguments and read/write sets, the default) requires GetHistoryForKey on the caller's allowlist; ?full=false streams summaries to anyone.
startBlock (query)full (query) - GET
/api/blockchain/events/chaincodeFollow every chaincode event, decoded.
Every event the chaincode emits, as it commits. This is how a consumer reacts to what OTHER organisations write — a dispatch created by a warehouse, a receipt confirmed at a shop — without opening a Fabric connection of its own.
startBlock (query)
Explorer
Read the chain: blocks, transactions and search, decoded from Fabric protobuf on demand.
- GET
/api/blockchain/explorer/blocksRecent blocks, newest first. Pages backward with before.
limit (query)before (query) - GET
/api/blockchain/explorer/blocks/{number}One block, decoded, with its transactions.
number (path, required)full (query) - GET
/api/blockchain/explorer/chainChain height and the tip's hashes.
- GET
/api/blockchain/explorer/overviewMonitoring snapshot: chain tip, peer status, and recent throughput in one request.
blocks (query) - GET
/api/blockchain/explorer/searchOne box, several identifier kinds. A block number, a transaction id, or any ledger key.
q (query, required) - GET
/api/blockchain/explorer/transactionsRecent transactions, newest first, by walking blocks back from the tip.
limit (query) - GET
/api/blockchain/explorer/transactions/{txId}One transaction, fully decoded — arguments, endorsers, read/write set. Without GetHistoryForKey on the allowlist, the summary only, marked redacted: true.
txId (path, required)
Service
The gateway's own surface — health, signing identities, the catalogue, and the committed status of a transaction id.
- GET
/api/blockchain/operationsMachine-readable catalogue, filtered to what the caller may invoke.
- GET
/api/blockchain/transactions/{transactionId}Committed status of a transaction id.
Read from the ledger via qscc, not from a local record — this service keeps no database.
transactionId (path, required) - GET
/clientsThe calling client's own registration.
- GET
/healthno keyLiveness plus per-organisation peer status.
Unauthenticated, so a load balancer can reach it. Reports from the connection cache by default; ?probe=1 actively dials every peer.
probe (query) - GET
/identitiesWhich certificate the gateway signs with, per organisation.
Never returns key material. This answers the question asked during every access-denied investigation.
VPDS-API_GATEWAY/api/src/sdk/operations.js, the same declaration the gateway derives its router, validation and OpenAPI document from — so it cannot drift from the running service. A live instance additionally serves Swagger UI at /docs with Try it out, the machine-readable spec at /openapi.json, and a block explorer at /explorer.