- Overview
- Tutorials
- Getting started
- Get started with Canton and the JSON Ledger API
- Get Started with Canton, the JSON Ledger API, and TypeScript
- Get started with Canton Network App Dev Quickstart
- Get started with smart contract development
- Basic contracts
- Test templates using Daml scripts
- Build the Daml Archive (.dar) file
- Data types
- Transform contracts using choices
- Add constraints to a contract
- Parties and authority
- Compose choices
- Handle exceptions
- Work with dependencies
- Functional programming 101
- The Daml standard library
- Test Daml contracts
- Next steps
- Application development
- Getting started
- Development how-tos
- Component how-tos
- Explanations
- References
- Application development
- Smart contract development
- Daml language cheat sheet
- Daml language reference
- Daml standard library
- DA.Action.State.Class
- DA.Action.State
- DA.Action
- DA.Assert
- DA.Bifunctor
- DA.Crypto.Text
- DA.Date
- DA.Either
- DA.Exception
- DA.Fail
- DA.Foldable
- DA.Functor
- DA.Internal.Interface.AnyView.Types
- DA.Internal.Interface.AnyView
- DA.List.BuiltinOrder
- DA.List.Total
- DA.List
- DA.Logic
- DA.Map
- DA.Math
- DA.Monoid
- DA.NonEmpty.Types
- DA.NonEmpty
- DA.Numeric
- DA.Optional
- DA.Record
- DA.Semigroup
- DA.Set
- DA.Stack
- DA.Text
- DA.TextMap
- DA.Time
- DA.Traversable
- DA.Tuple
- DA.Validation
- GHC.Show.Text
- GHC.Tuple.Check
- Prelude
- Smart contract upgrading reference
- Glossary of concepts
JSON Ledger API Service V2¶
Note
THIS SECTION NEEDS TO MOVE TO sdk/sdlc-howtos/applications/integrate/http-json
This section describes the new JSON Ledger API Service that is a part of Canton 3.x. If you are looking for the legacy JSON Ledger API, please navigate to JSON Ledger API V1 <https://docs.daml.com/app-dev/json-api.html>
The JSON Ledger API provides a way to interact with a ledger using HTTP and JSON instead of the gRPC the gRPC Ledger API. The JSON Ledger API provides almost all the functionality available in the gRPC Ledger API, although the HTTP protocol imposes some minor limitations.
- The full reference consists of:
We recommend using OpenAPI/AsyncAPI specification to generate a client for your technology (Java, typescript).
We welcome feedback about the JSON Ledger API on our issue tracker, or on our forum.
Prerequisites¶
It is assumed that you know the basics of HTTP Protocol, HTTP methods, HTTP request and response headers (including authorization), JSON format, and WebSockets.
- In order to test JSON Ledger API you need a tool such as:
command line
curl
postman <https://www.postman.com>
Some tools enable testing of WebSockets; one is, for instance: wscat
.
Run the JSON Ledger API¶
Prepare canton configuration¶
canton {
participants {
participant1 {
storage {
type = memory
}
admin-api {
port = 14012
}
http-ledger-api {
server {
port = 8080
}
}
}
}
}
Save config as (for instance) json_enabled.conf
Note
in canton 3.1 and earlier http-ledger-api is named http-ledger-api-experimental.
Start canton¶
You can run the JSON Ledger API alongside any ledger exposing the gRPC Ledger API you want. If you don’t have an existing ledger, you can start canton with the config as below:
bin/canton -c json_enabled.conf
Ensure that the canton console is started.
Check that JSON Ledger API is running:
In terminal use curl to get openapi documentation
curl localhost:8080/docs/openapi
Alternatively open the web browser and navigate to address:
You should see yaml file contents that starts with:
openapi: 3.1.0 info: title: JSON Ledger API HTTP endpoints
Congratulations, You have successfully started JSON Ledger API.
Note
Your JSON Ledger API service should never be exposed to the Internet. When running in production the JSON Ledger API should be behind a reverse proxy, such as via NGINX.
JSON Ledger API Advanced configuration¶
The full set of configurable options that can be specified via config file is listed below:
{
server {
//IP address that JSON Ledger API service listens on. Defaults to 127.0.0.1.
address = "127.0.0.1"
//JSON Ledger API service port number. A port number of 0 will let the system pick an ephemeral port.
port = 7575
//Prefix added to all JSON endpoints.
path-prefix = "example/prefix"
}
websocket-config {
//Maximum number of elements returned when using the HTTP POST alternative.
http-list-max-elements-limit = 1024
//Wait time for new elements before returning the list via the HTTP POST alternative.
http-list-wait-time = "1s"
}
}
Access Tokens¶
Each request to the JSON Ledger API Service must come with an access token (JWT
). This also includes development setups using an unsecured sandbox.
The JSON Ledger API Service does not
hold on to the access token, which will be only used to fulfill the request it came along with. The same token will be used
to issue the request to the Ledger API.
The only exceptions are documentation endpoints, which do not strictly require tokens.
- For a reference on the JWT Tokens we use, please read:
Note
While the JSON Ledger API receives the token, it doesn’t validate that token itself. Upon receiving a token, it passes it, and all data contained within the request, to the Ledger API’s AuthService, which then determines if the token is valid and authorized.
For a ledger without authorization, e.g., the default configuration of Daml Sandbox, you can use https://jwt.io (or the JWT library of your choice) to generate your token. You can use an arbitrary secret here. The default “header” is fine. Under “Payload”, fill in:
{
"aud": [],
"exp": null,
"iss": null,
"scope": "ExpectedTargetScope",
"sub": "actAs-Alice::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c"
}
The value after actAs
is specified as a list and you provide it with the party that you want to use,
such as in the example above which uses Alice
for a party. actAs
may include more than just one party
as the JSON Ledger API supports multi-party submissions.
The party should reference an already allocated party. In canton console a party can be allocated using:
val alice = participant1.parties.enable("Alice")
alice.toProtoPrimitive //this will display a full party Id
Then the “Encoded” box should have your token, ready for passing to the service as described in the following sections.
Alternatively, here is a token you can use for testing:
{
"aud": [],
"exp": null,
"iss": null,
"scope": "ExpectedTargetScope",
"sub": "participant_admin"
}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOltdLCJleHAiOm51bGwsImlzcyI6bnVsbCwic2NvcGUiOiJFeHBlY3RlZFRhcmdldFNjb3BlIiwic3ViIjoicGFydGljaXBhbnRfYWRtaW4ifQ.8bABNm1t718TuJXwRQOF2gXOclrL38t0uCmWkIT7Pcg
Auth via HTTP¶
Set HTTP header Authorization: Bearer <paste-jwt-here>
Example header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2RhbWwuY29tL2xlZGdlci1hcGkiOnsibGVkZ2VySWQiOiJNeUxlZGdlciIsImFwcGxpY2F0aW9uSWQiOiJIVFRQLUpTT04tQVBJLUdhdGV3YXkiLCJhY3RBcyI6WyJBbGljZSJdfX0.34zzF_fbWv7p60r5s1kKzwndvGdsJDX-W4Xhm4oVdpk
Example using curl
curl -X 'POST' \
'http://localhost:8080/v2/users' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOltdLCJleHAiOm51bGwsImlzcyI6bnVsbCwic2NvcGUiOiJFeHBlY3RlZFRhcmdldFNjb3BlIiwic3ViIjoicGFydGljaXBhbnRfYWRtaW4ifQ.8bABNm1t718TuJXwRQOF2gXOclrL38t0uCmWkIT7Pcg' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d @body_create_user.json
Auth via WebSockets¶
WebSocket clients support a “subprotocols” argument (sometimes simply called “protocols”); this is usually in a list form but occasionally in comma-separated form. Check the documentation for your WebSocket library of choice for details.
For HTTP JSON requests, you must pass two subprotocols:
daml.ws.auth
jwt.token.paste-jwt-here
Example:
jwt.token.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2RhbWwuY29tL2xlZGdlci1hcGkiOnsibGVkZ2VySWQiOiJNeUxlZGdlciIsImFwcGxpY2F0aW9uSWQiOiJIVFRQLUpTT04tQVBJLUdhdGV3YXkiLCJhY3RBcyI6WyJBbGljZSJdfX0.34zzF_fbWv7p60r5s1kKzwndvGdsJDX-W4Xhm4oVdpk
Example using wscat
:
wscat -c http://localhost:8080/v2/state/active-contracts \
-s "jwt.token.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOltdLCJleHAiOm51bGwsImlzcyI6bnVsbCwic2NvcGUiOiJFeHBlY3RlZFRhcmdldFNjb3BlL1dpdGgtRGFzaC9BbmRfVW5kZXJzY29yZSIsInN1YiI6ImFjdEFzLUFsaWNlOjoxMjIwOTllNmI3YzkyZTEyZWIwMjZmNDgzZjU5YTczZTQ4MTQ5ZGM2ZTYzMGE0ZjRmOGZiOTViOGQyNjkyMTliMzU2YyJ9.FmJoP6eK2Yg6CAmO2G0SYosMS4IOai_6HlvO1siYNUA" \
-s "daml.ws.auth"
HTTP Status Codes¶
The JSON Ledger API reports errors using standard HTTP status codes. It divides HTTP status codes into 3 groups indicating:
success (200)
failure due to a client-side problem (400, 401, 403)
failure due to a server-side problem (500)
Most common HTTP status codes are:
200 - OK
400 - Bad Request (Client Error)
401 - Unauthorized, authentication required
403 - Forbidden, insufficient permissions (TODO)
500 - Internal Server Error
JSON Ledger API Errors¶
When the gRPC Ledger API returns an error code, the JSON Ledger API maps it to one of the above codes according to the official gRPC to HTTP code mapping.
If a client’s HTTP GET or POST request reaches an API endpoint, the corresponding response will always contain a JSON object. Either an expected message (corresponding to endpoint) or an error
object specified as in the example below:
{
"cause" : "The submitted request has invalid arguments: Cannot unassign contract `ContractId(00a7feb291fe1be6289c4d77f3a432b623083ed3f49bf8535f8571aa8bdf68b647ca10122006207a71ac6ed62dae27429b43e456dfbbc411a49d67b7e0067bef4c914c6e8a)`: source and target domains are the same",
"code" : "INVALID_ARGUMENT",
"context" : {
"category" : "8",
"definite_answer" : "false",
"participant" : "participant1",
"test" : "JsonV2Tests",
"tid" : "99e67812af315256ef9a02a9fdb94646"
},
"correlationId" : null,
"definiteAnswer" : null,
"errorCategory" : 8,
"grpcCodeValue" : 3,
"resources" : [ ],
"retryInfo" : null,
"traceId" : "99e67812af315256ef9a02a9fdb94646"
}
Where:
cause
– a textual message containing readable error reason,code
– a LedgerAPI error code,context
– a Ledger API context of an error,traceId
– telemetry tracing idgrpcCodeValue
anderrorCategory
- defined in Canton Error Codes.
See The Ledger API error codes (Canton Error Codes Reference) for more details about error codes from Ledger API.
WebSockets Errors¶
In the case of websockets an error might be delivered as a frame. Each incoming frame can either be a correct response (corresponding to the endpoint definition) or an error frame in the format above.
Example of successful Response, HTTP Status: 200 OK¶
Content-Type:
application/json
Content:
{
"partyDetails": {
"party": "Carol:-_ a9c80151-002c-445e-9fae-3caf111e3ac4::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c",
"isLocal": true,
"localMetadata": {
"resourceVersion": "0",
"annotations": {}
},
"identityProviderId": ""
}
}
Create a New Contract¶
To create an Iou
contract from the Quickstart guide:
template Iou
with
issuer : Party
owner : Party
currency : Text
amount : Decimal
observers : [Party]
HTTP Request¶
- URL, one of:
/v2/commands/submit-and-wait-for-transaction-tree
/v2/commands/submit-and-wait-for-transaction
/v2/commands/submit-and-wait
Method:
POST
Content-Type:
application/json
Content:
{
"actAs": [
"Alice::1220ceff195fd59bbc357415ce25d7a6edb95475b134b1bbb6d70c8fa3dd3f8f32ad"
],
"userId": "app1",
"commandId": "somecommandid2",
"commands": [
{
"CreateCommand": {
"createArguments": {
"observers": [],
"issuer": "Alice::1220ceff195fd59bbc357415ce25d7a6edb95475b134b1bbb6d70c8fa3dd3f8f32ad",
"amount": "999.99",
"currency": "USD",
"owner": "Alice::1220ceff195fd59bbc357415ce25d7a6edb95475b134b1bbb6d70c8fa3dd3f8f32ad"
},
"templateId": "#model-tests:Iou:Iou"
}
}
]
}
Where:
template_id
is the contract template identifier which has the following two formats:#<package name>:<module>:<entity>
or<package ID>:<module>:<entity>
.The package name format works with the smart contract upgrading feature so that contracts with different package IDs but the same package name can be used in a uniform manner.
Using the package ID format refers to a single package.
createArguments
field contains contract fields as defined in the Daml template and formatted according to Daml-LF JSON encoding.commandId
– optional field, a unique string identifying the command.actAs
– a non-empty list of parties, overriding the set from the JWT user; must be a subset of the JWT user’s set.
Note
Only a subset of the possible fields is shown in the example. Refer to the OpenAPI specification for additional options.
HTTP Response¶
The response will differ according to endpoint URL chosen to send transaction. Example below assumes
/v2/commands/submit-and-wait-for-transaction-tree
.
Content-Type:
application/json
Content:
{
"transactionTree": {
"updateId": "12208230390f6af5a6e85e70af2f0ad3cdb4f2df2f1e41778a58ce888e128d2a1245",
"commandId": "somecommandid21",
"workflowId": "",
"effectiveAt": "2025-01-27T15:30:36.430940Z",
"offset": 18,
"eventsById": {
"0": {
"CreatedTreeEvent": {
"value": {
"offset": 18,
"nodeId": 0,
"contractId": "005f954f6759aa04b0998676689610fc1d84c5d31a46819f7bfdd7233ecd7e18b3ca1012207866cf05034eddcc7b0619ab06a46514b21732a0da6404f3f2fbb90872ed6289",
"templateId": "19b9fc297d4649bab9fd0eeb3ce23da763cb9ed7dfaedeb1281ac7d7f65a7883:Iou:Iou",
"contractKey": null,
"createArgument": {
"issuer": "Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55",
"owner": "Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55",
"currency": "USD",
"amount": "999.9900000000",
"observers": []
},
"createdEventBlob": "",
"interfaceViews": [],
"witnessParties": [
"Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55"
],
"signatories": [
"Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55"
],
"observers": [],
"createdAt": "2025-01-27T15:30:36.430940Z",
"packageName": "model-tests"
}
}
}
},
"rootNodeIds": [
0
],
"synchronizerId": "da1::122002b3938ee8f7f0a757c5db698fc6020352717ee53da9023485f8b9e0dc2ea360",
"traceContext": {
"traceparent": "00-bfc45078ca09495a4101b227f4c36bef-6471ff18d20230eb-01",
"tracestate": null
},
"recordTime": "2025-01-27T15:30:37.291866Z"
}
}
Where:
eventsById
contains ledger events with details of created contract(s),
Exercise by Contract ID¶
The JSON command below, demonstrates how to exercise an Iou_Transfer
choice on an Iou
contract:
choice Iou_Transfer : ContractId IouTransfer
with
newOwner : Party
controller owner
do create IouTransfer with iou = this; newOwner
HTTP Request¶
- URL, one of:
/v2/commands/submit-and-wait-for-transaction-tree
/v2/commands/submit-and-wait-for-transaction
/v2/commands/submit-and-wait
Method:
POST
Content-Type:
application/json
Content:
{
"actAs": [
"Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55"
],
"userId": "app1",
"commandId": "somecommandid2",
"commands": [
{
"ExerciseCommand": {
"choice": "Iou_Transfer",
"choiceArgument": {
"newOwner": "Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55"
},
"contractId": "005f954f6759aa04b0998676689610fc1d84c5d31a46819f7bfdd7233ecd7e18b3ca1012207866cf05034eddcc7b0619ab06a46514b21732a0da6404f3f2fbb90872ed6289",
"templateId": "#model-tests:Iou:Iou"
}
}
]
}
Where:
templateId
– contract template or interface identifier, same as in create request,choiceInterfaceId
– optional template or interface that defines the choice, same format astemplateId
,contractId
– contract identifier, the value from the create response,choice
– Daml contract choice, that is being exercised,argument
– contract choice argument(s).
HTTP Response¶
Content-Type:
application/json
Content:
{
"completionOffset" : 11,
"updateId" : "12205cec9cccf807dd95df3c0ab270bd286ef1bc9b84aa26f7ecf1180248aaa9d070"
}
Where:
update_id
the id of the transaction that resulted from the submitted command.
completionOffset
is the ledger offset of the transaction containing the exercise’s ledger changes.
Create and Exercise in the Same Transaction¶
This command allows creating a contract and exercising a choice on the newly created contract in the same transaction.
HTTP Request¶
- URL, one of:
/v2/commands/submit-and-wait-for-transaction-tree
/v2/commands/submit-and-wait-for-transaction
/v2/commands/submit-and-wait
Method:
POST
Content-Type:
application/json
Content:
{
"actAs" : [ "Alice::1220870d67dba562b868d0256cb2968dbc59a7a6bdbc4b82ee623ff96c8cda3afb9a" ],
"userId" : "defaultuser2",
"commandId" : "somecommandid3",
"commands" : [ {
"CreateAndExerciseCommand" : {
"choice" : "Iou_Transfer",
"createArguments" : {
"observers" : [ ],
"issuer" : "Alice::1220df15d08ac34527e46492a6ee48a723e3d02ed3ec20a05ebf64be47173f24407f",
"amount" : "999.99",
"currency" : "USD",
"owner" : "Alice::1220df15d08ac34527e46492a6ee48a723e3d02ed3ec20a05ebf64be47173f24407f"
},
"choiceArgument" : {
"newOwner" : "Alice::1220870d67dba562b868d0256cb2968dbc59a7a6bdbc4b82ee623ff96c8cda3afb9a"
},
"templateId" : "#model-tests:Iou:Iou"
}
} ]
}
Where:
templateId
– the initial contract template identifier, in the same format as in the create request,payload
– the initial contract fields as defined in the Daml template and formatted according to Daml-LF JSON encoding,choiceInterfaceId
– optional template or interface that defines the choice, same format astemplateId
,choice
– Daml contract choice, that is being exercised,argument
– contract choice argument(s).
HTTP Response¶
Please note that the response below is for a consuming choice, it contains:
Content-Type:
application/json
Content:
{
"transaction" : {
"command_id" : "somecommandid",
"domainId" : "domain1::12208f22808f6fe77f8689d0d565488e34e9a3abb2eaf37270f6e5b2b2073894db9f",
"effectiveAt" : "1970-01-01T00:00:00Z",
"events" : [ {
"CreatedEvent" : {
"contractId" : "00811e868ffe78638ecf14b8d69a5df6eafd8b16f13a431117ee26981cc39f40e1ca101220c15b891d2cac1287d5067594c81f60b722141204f63f2a27c3328a70467c5018",
"contractKey" : null,
"createArgument" : {
"iou" : {
"amount" : "999.9900000000",
"currency" : "USD",
"issuer" : "Alice_ffe0d699-2978-42d7-a315-b7faec7ba95a::1220d7b8bc76f04500216f07e1576da75db0e811ea1e01d5688140816823615a34bf",
"observers" : [ ],
"owner" : "Alice_ffe0d699-2978-42d7-a315-b7faec7ba95a::1220d7b8bc76f04500216f07e1576da75db0e811ea1e01d5688140816823615a34bf"
},
"newOwner" : "Alice_ffe0d699-2978-42d7-a315-b7faec7ba95a::1220d7b8bc76f04500216f07e1576da75db0e811ea1e01d5688140816823615a34bf"
},
"createdAt" : "1970-01-01T00:00:00Z",
"createdEventBlob" : "",
"eventId" : "#1220ad3e6509fa8977478aa49cf3261b376dd55b06f6409e3ec59553272c89d3616c:2",
"interfaceViews" : [ ],
"nodeId" : 2,
"observers" : [ ],
"offset" : 12,
"packageName" : "model-tests",
"signatories" : [ "Alice_ffe0d699-2978-42d7-a315-b7faec7ba95a::1220d7b8bc76f04500216f07e1576da75db0e811ea1e01d5688140816823615a34bf" ],
"templateId" : "a36cfff1da2f15da3d760c872860bf03140aa699f73b57b639fd40dfe8156cfe:Iou:IouTransfer",
"witnessParties" : [ "Alice_ffe0d699-2978-42d7-a315-b7faec7ba95a::1220d7b8bc76f04500216f07e1576da75db0e811ea1e01d5688140816823615a34bf" ]
}
} ],
"offset" : 12,
"recordTime" : "1970-01-01T00:00:00.000042Z",
"traceContext" : {
"traceparent" : "00-d84d23ff01031adbcf76f19525fa62fb-003327aa6c8ede2d-01",
"tracestate" : null
},
"updateId" : "1220ad3e6509fa8977478aa49cf3261b376dd55b06f6409e3ec59553272c89d3616c",
"workflowId" : ""
}
}
Get All Active Contracts¶
List all currently active contracts for all known templates.
Note
You can only query active contracts with the /v2/state/active-contracts
endpoint. Archived contracts (those that were archived or consumed during an exercise operation) will not be shown in the results.
HTTP Websocket Request¶
URL:
/v2/state/active-contracts
Protocol:
Websocket
Content:
Send a single query frame:
{
"filter":
{
"filtersByParty":{},
"filtersForAnyParty":
{"cumulative": [
{"identifierFilter":
{"WildcardFilter":
{"value":
{"includeCreatedEventBlob":true}
}
}
}
]
}
},
"verbose":false,
"activeAtOffset":23
}
Note
be careful and do enter a proper value for activeAtOffset
Example Response frames¶
The response might look like an example below:
{
"workflowId": "",
"contractEntry": {
"JsActiveContract": {
"createdEvent": {
"offset": 23,
"nodeId": 1,
"contractId": "00afee8d924751d4677ae7f09ed7c38c84b9e8601bb2c75bc30f832f866896755dca101220b62bec39ca9352f599cc432bbca1969a33d368a0ee4cdad56093226f27103dc2",
"templateId": "19b9fc297d4649bab9fd0eeb3ce23da763cb9ed7dfaedeb1281ac7d7f65a7883:Iou:IouTransfer",
"contractKey": null,
"createArgument": {
"iou": {
"issuer": "Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55",
"owner": "Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55",
"currency": "USD",
"amount": "999.9900000000",
"observers": []
},
"newOwner": "Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55"
},
"createdEventBlob": "CgMyLjES0QQKRQCv7o2SR1HUZ3rn8J7Xw4yEuehgG7LHW8MPgy+GaJZ1XcoQEiC2K+w5ypNS9ZnMQyu8oZaaM9NooO5M2tVgkyJvJxA9whILbW9kZWwtdGVzdHMaVApAMTliOWZjMjk3ZDQ2NDliYWI5ZmQwZWViM2NlMjNkYTc2M2NiOWVkN2RmYWVkZWIxMjgxYWM3ZDdmNjVhNzg4MxIDSW91GgtJb3VUcmFuc2ZlciKiAmqfAgrLAQrIAWrFAQpPCk06S0FsaWNlOjoxMjIwNzQzOTI2YWRhMWJhNTIxNTA1OTZjMDc3MTI5OTVmNGExZDJjNDNlZmNjOWQ5ZTU2OWJiODJiMTk5OGE0NmM1NQpPCk06S0FsaWNlOjoxMjIwNzQzOTI2YWRhMWJhNTIxNTA1OTZjMDc3MTI5OTVmNGExZDJjNDNlZmNjOWQ5ZTU2OWJiODJiMTk5OGE0NmM1NQoHCgVCA1VTRAoSChAyDjk5OS45OTAwMDAwMDAwCgQKAloACk8KTTpLQWxpY2U6OjEyMjA3NDM5MjZhZGExYmE1MjE1MDU5NmMwNzcxMjk5NWY0YTFkMmM0M2VmY2M5ZDllNTY5YmI4MmIxOTk4YTQ2YzU1KktBbGljZTo6MTIyMDc0MzkyNmFkYTFiYTUyMTUwNTk2YzA3NzEyOTk1ZjRhMWQyYzQzZWZjYzlkOWU1NjliYjgyYjE5OThhNDZjNTU5Agm71LEsBgBCKgomCiQIARIgyJpshr25uq/bCHZXro6K5Wl3FyO/llMqF2W5DbrzoKAQHg==",
"interfaceViews": [],
"witnessParties": [
"Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55"
],
"signatories": [
"Alice::1220743926ada1ba52150596c07712995f4a1d2c43efcc9d9e569bb82b1998a46c55"
],
"observers": [],
"createdAt": "2025-01-27T15:35:50.124802Z",
"packageName": "model-tests"
},
"synchronizerId": "da1::122002b3938ee8f7f0a757c5db698fc6020352717ee53da9023485f8b9e0dc2ea360",
"reassignmentCounter": 0
}
}
}
Get All Active Contracts via HTTP¶
For each WebSocket endpoint, we provide an alternative HTTP POST endpoint that returns the same results synchronously.HTTP POST alternatives are less robust: However, HTTP POST alternatives are less efficient because:
They impose a higher load on the server.
The result size is always limited (refer to the configuration).
There is a slight performance overhead and delay in retrieving results.
We recommend using WebSockets for production environments, as they offer better performance and scalability. HTTP alternatives are suitable for prototyping and less demanding applications with lower data and load requirements.
HTTP Request¶
URL:
/v2/state/active-contracts
Protocol:
HTTP
Method:
POST
Content:
{
"filter":
{
"filtersByParty":{},
"filtersForAnyParty":
{"cumulative": [
{"identifierFilter":
{"WildcardFilter":
{"value":
{"includeCreatedEventBlob":true}
}
}
}
]
}
},
"verbose":false,
"activeAtOffset":23
}
Note
be careful and do enter a proper value for activeAtOffset
Example HTTP Response:¶
[
{
"workflowId": "",
"contractEntry": {
"JsActiveContract": {
"createdEvent": {
"offset": 18,
"nodeId": 0,
"contractId": "0047c4cc5cf2f0bda731a172fd90f5cc592f9d3ad2e5c45450d9de1cc4aa5adb71ca101220a8faa4673f7e9c28319eb57f98aad84d0bf1395fed971f24eb486bc4f48d9828",
"templateId": "19b9fc297d4649bab9fd0eeb3ce23da763cb9ed7dfaedeb1281ac7d7f65a7883:Iou:Iou",
"contractKey": null,
"createArgument": {
"issuer": "Alice::1220b6683b7d875557055126f8b8f059d9c070ece95e7784d279a135c8c1285a4f1f",
"owner": "Alice::1220b6683b7d875557055126f8b8f059d9c070ece95e7784d279a135c8c1285a4f1f",
"currency": "USD",
"amount": "999.9900000000",
"observers": []
},
"createdEventBlob": "CgMyLjES7wMKRQBHxMxc8vC9pzGhcv2Q9cxZL5060uXEVFDZ3hzEqlrbccoQEiCo+qRnP36cKDGetX+YqthNC/E5X+2XHyTrSGvE9I2YKBILbW9kZWwtdGVzdHMaTApAMTliOWZjMjk3ZDQ2NDliYWI5ZmQwZWViM2NlMjNkYTc2M2NiOWVkN2RmYWVkZWIxMjgxYWM3ZDdmNjVhNzg4MxIDSW91GgNJb3UiyAFqxQEKTwpNOktBbGljZTo6MTIyMGI2NjgzYjdkODc1NTU3MDU1MTI2ZjhiOGYwNTlkOWMwNzBlY2U5NWU3Nzg0ZDI3OWExMzVjOGMxMjg1YTRmMWYKTwpNOktBbGljZTo6MTIyMGI2NjgzYjdkODc1NTU3MDU1MTI2ZjhiOGYwNTlkOWMwNzBlY2U5NWU3Nzg0ZDI3OWExMzVjOGMxMjg1YTRmMWYKBwoFQgNVU0QKEgoQMg45OTkuOTkwMDAwMDAwMAoECgJaACpLQWxpY2U6OjEyMjBiNjY4M2I3ZDg3NTU1NzA1NTEyNmY4YjhmMDU5ZDljMDcwZWNlOTVlNzc4NGQyNzlhMTM1YzhjMTI4NWE0ZjFmOS/eEk3FLAYAQioKJgokCAESIANCONtfqgCanbAYj1wMaIE3YKLDoH+lM9kT19z2h1F4EB4=",
"interfaceViews": [],
"witnessParties": [
"Alice::1220b6683b7d875557055126f8b8f059d9c070ece95e7784d279a135c8c1285a4f1f"
],
"signatories": [
"Alice::1220b6683b7d875557055126f8b8f059d9c070ece95e7784d279a135c8c1285a4f1f"
],
"observers": [],
"createdAt": "2025-01-28T14:49:33.525551Z",
"packageName": "model-tests"
},
"synchronizerId": "da1::1220ff7a4caf08bd4442003c65c2f351ebc15cc3a2063fd876da82e3a64a2348d30b",
"reassignmentCounter": 0
}
}
}
]
Fetch Parties by Identifiers¶
URL:
/v2/parties/{partyId}
Method:
GET
Content-Type:
application/json
Content:
HTTP Response¶
Content-Type:
application/json
Content:
{
"partyDetails": [
{
"party": "Alice::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c",
"isLocal": true,
"localMetadata": {
"resourceVersion": "",
"annotations": {}
},
"identityProviderId": ""
}
]
}
Where
identifier
– a stable unique identifier of a Daml party,isLocal
– true if party is hosted by the backing participant.
The result
might contain an empty JSON array partyDetails.
Fetch All Known Parties¶
URL:
/v2/parties
Method:
GET
Content: <EMPTY>
HTTP Response¶
{
"partyDetails": [
{
"party": "Alice::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c",
"isLocal": true,
"localMetadata": {
"resourceVersion": "",
"annotations": {}
},
"identityProviderId": ""
},
{
"party": "Bob::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c",
"isLocal": true,
"localMetadata": {
"resourceVersion": "",
"annotations": {}
},
"identityProviderId": ""
},
{
"party": "participant1::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c",
"isLocal": true,
"localMetadata": {
"resourceVersion": "",
"annotations": {}
},
"identityProviderId": ""
}
],
"nextPageToken": ""
}
Note
nextPageToken is used by gRPC if there is paging enabled, in the current resource version of JSON Ledger API paging is not yet supported.
Allocate a New Party¶
HTTP Request¶
URL:
/v2/parties
Method:
POST
Content-Type:
application/json
Content:
{
"identityProviderId" : "",
"localMetadata" : null,
"partyIdHint" : "Carol"
}
HTTP Response¶
{
"partyDetails": {
"party": "Carol:-_ a9c80151-002c-445e-9fae-3caf111e3ac4::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c",
"isLocal": true,
"localMetadata": {
"resourceVersion": "0",
"annotations": {}
},
"identityProviderId": ""
}
}
Create a New User¶
HTTP Request¶
URL:
/v2/users
Method:
POST
Content-Type:
application/json
Content:
{
"rights" : [
{
"kind": {
"CanActAs" : {
"value": {
"party" : "Bob::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c"
}
}
}
}
],
"user" : {
"id" : "CreatedUser1",
"identityProviderId" : "",
"isDeactivated" : false,
"metadata" : null,
"primaryParty" : ""
}
}
Only the userId fields in the request is required, this means that an JSON object containing only it is a valid request to create a new user.
HTTP Response¶
{
"user": {
"id": "CreatedUser1",
"primaryParty": "",
"isDeactivated": false,
"metadata": {
"resourceVersion": "0",
"annotations": {}
},
"identityProviderId": ""
}
}
Get Specific User Information¶
HTTP Request¶
URL:
/v2/users/{userId}
Method:
GET
Content-Type:
application/json
Content:
HTTP Response¶
{
"user": {
"id": "CreatedUser1",
"primaryParty": "",
"isDeactivated": false,
"metadata": {
"resourceVersion": "0",
"annotations": {}
},
"identityProviderId": ""
}
}
Delete Specific User¶
HTTP Request¶
URL:
/v2/users/{userId}
Method:
DELETE
Content-Type:
application/json
Content:
HTTP Response¶
{}
An empty response with a status 200 confirms successful deletion.
List Users¶
HTTP Request¶
URL:
/v2/users
Method:
GET
HTTP Response¶
{
"users": [
{
"id": "CreatedUser",
"primaryParty": "",
"isDeactivated": false,
"metadata": {
"resourceVersion": "0",
"annotations": {}
},
"identityProviderId": ""
},
{
"id": "participant_admin",
"primaryParty": "",
"isDeactivated": false,
"metadata": {
"resourceVersion": "0",
"annotations": {}
},
"identityProviderId": ""
}
],
"nextPageToken": ""
}
Grant User Rights¶
HTTP Request¶
URL:
/v2/users/{userId}/rights
Method:
POST
Content-Type:
application/json
Content:
{
"identityProviderId" : "",
"rights" : [ {
"kind" : {
"ParticipantAdmin" : {
"value" : { }
}
}
} ],
"userId" : "CreatedUser1"
}
HTTP Response¶
{
"newlyGrantedRights": [
{
"kind": {
"ParticipantAdmin": {
"value": {}
}
}
}
]
}
Returns the rights that were newly granted.
Revoke User Rights¶
HTTP Request¶
URL:
/v2/users/{userId}/rights
Method:
PATCH
Content-Type:
application/json
Content:
{
"identityProviderId" : "",
"rights" : [ {
"kind" : {
"ParticipantAdmin" : {
"value" : { }
}
}
} ],
"userId" : "CreatedUser1"
}
HTTP Response¶
{
"newlyRevokedRights": [
{
"kind": {
"ParticipantAdmin": {
"value": {}
}
}
}
]
}
Returns the rights that were actually revoked.
List Specific User Rights¶
HTTP Request¶
URL:
/v2/users/{userId}/rights
Method:
GET
Content-Type:
application/json
HTTP Response¶
{
"rights": [
{
"kind": {
"CanActAs": {
"value": {
"party": "Bob::122099e6b7c92e12eb026f483f59a73e48149dc6e630a4f4f8fb95b8d269219b356c"
}
}
}
},
{
"kind": {
"ParticipantAdmin": {
"value": {}
}
}
}
]
}
List All DALF Packages¶
HTTP Request¶
URL:
/v2/packages
Method:
GET
HTTP Response¶
{
"packageIds": [
"9e70a8b3510d617f8a136213f33d6a903a10ca0eeec76bb06ba55d1ed9680f69",
"0e4a572ab1fb94744abb02243a6bbed6c78fc6e3c8d3f60c655f057692a62816",
"5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4",
"a1fa18133ae48cbb616c4c148e78e661666778c3087d099067c7fe1868cbb3a1",
"a36cfff1da2f15da3d760c872860bf03140aa699f73b57b639fd40dfe8156cfe",
"54f85ebfc7dfae18f7d70370015dcc6c6792f60135ab369c44ae52c6fc17c274"
]
}
Where packageIds
is the JSON array containing the package IDs of all loaded DALFs.
Download a DALF Package¶
HTTP Request¶
URL:
/v2/packages/<package ID>
Method:
GET
Content: <EMPTY>
Note that the desired package ID is specified in the URL.
HTTP Response, status: 200 OK¶
Transfer-Encoding:
chunked
Content-Type:
application/octet-stream
Content: <DALF bytes>
The content (body) of the HTTP response contains raw DALF package bytes, without any encoding. Note that the package ID specified in the URL is actually the SHA-256 hash of the downloaded DALF package and can be used to validate the integrity of the downloaded content.
Upload a DAR File¶
HTTP Request¶
URL:
/v2/packages
Method:
POST
Content-Type:
application/octet-stream
Content: <DAR bytes>
The content (body) of the HTTP request contains raw DAR file bytes, without any encoding.
HTTP Response, Status: 200 OK¶
Content-Type:
application/json
Content:
{}