# Bitmark API design ## Changes * Remove verb APIs, use traditional REST format as much as possible. * `Bitmark` object now reflects from [Bitmark White Paper](https://bitmark.com/assets/bitmark_technical-white-paper.pdf). It consists a chain from Issue Record to last Transfer Record. With passing `full` params, it returns `Bitmark` object with full of transaction records. Otherwise, it will returns just Issue Record and the last Transfer Record. * `Transaction` object now will have `sender` and `receiver` like normal transactions. Also since `Transaction` on blockchain is a chain, it will include `previous_id` and `next_id` for previous and next linked transactions. If `next_id` is `null`, the transaction is considered the newest and head of the chain. * Remove the term of `confirmed` in `Transaction`, instead, it will show `confirmations`, means the confirmation number of each transaction. * Remove supporting of public encryption key and move it to file courier server. * Remove `offset` in favor of a new mechanism for [pagination](#Pagination) and [local data update](##Updating-Data-with-Events). * Introduce [webhook](#Webhook) for notifying blockchain events. ~~Mobile apps needs backend side to listen webhook events and stream them to the apps.~~ ## Basic models ### Block Represent a block. #### Object ```json= { "block": { "number": 30885, "hash": "0037e7fbe9e4f7887602bb7f73c3a5eab20d65fe58adb13a6d7abf5c88631d7f", "foundation_tx_id": "b3a977a2a087fa66c45fc886d1c6b1776e03cdd0597f6af1193962dd78784374", "created_at": "2019-08-20T04:57:34.000000Z" } } ``` ##### Attributes | Attribute | Type | Description | | -------- | -------- | -------- | | number | integer | Block number | | hash | string | Block hash | | foundation_tx_id | string | Foundation tx, send to bitmark account who mined the block. | | created_at | iso8601 | Block created at date | #### List blocks List all blocks on blockchain with conditions. ##### Endpoint `GET /blocks` #### Get a block Get a block with specific `block_number`. ##### Endpoint `GET /blocks/:block_number` ### Asset Represent a digital asset. #### Object ```json= { "asset": { "id": "887319e6314a076dc696f79a466de4e4ad39fe04e13a2f3bfc4a0cb01fbc38f439e7f1f20f859bcc31eded347991abe4a556c3e15d6ad4af83aaf12cf6b5fab7", "name": "GGGGG", "fingerprint": "017c828871c85275e49630c5383dbb865dc0c8f008aace65fa6fd8d8c23a80d46e399e70329532e74fc0528534661f8a8e2171083fcb13ee09e8dd2247e2741716", "metadata": { "medium": "Image" }, "registrant": "fcN6fMuvK6XdKaF6GMf8NSVHDAdwg6oVCiLp3RHKXiiHxKr73H", "status": "registered", "block_number": 16234, "expires_at": null, "created_at": "2019-08-19T19:57:52.000000Z" } } ``` ##### Attributes | Attribute | Type | Description | | -------- | -------- | -------- | | status | string | Status can be either `registered` or `waiting`. | | expires_at | iso8601 | If the status is `waiting`, `expires_at` will show the expiration time for waiting a bitmark assigned to this asset. | | block_number | integer | If the status is `registered`, this attribute indicates the block number of first confirmed bitmark that links to this asset. | #### List assets List all assets on blockchain with conditions. ##### Endpoint `GET /assets` ##### Params | Param | Type | Description | | -------- | -------- | -------- | | registrant | string | Show assets from a specific registrant. | | status | string | Show assets with a specific status. | #### Get an asset Get an asset with specific `id`. ##### Endpoint `GET /assets/:id` #### Register asset Register an asset. It will return error if asset is registered (unique by `id`). Asset is successful registered will be in `waiting` status. Once a linked bitmark is confirmed, status of the asset will be changed to `registered`. Asset on `waiting` status will have expiration date. ##### Endpoint `POST /assets` ### Transaction Represent a single record on Bitmark blockchain. A transaction can be either Issue record or Transfer record. #### Object ```json= { "transaction": { "id": "69eeea53c6bfb4a525973074c5f8628dace323b972fd6423ca85f7a7da0a7870", "previous_id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "next_id": null, "sender": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "receiver": "fqiJzShni4aCDKBy6YB8ruLAsgydPtYShPZkQLXzzPdAuYYhAy", "asset_id": "041aee9ee14ec8faa9df4749d6613c03d4cbad2f07b1810efafa53e4b16c9625ee899581aeafa7e6896dafc9aebb2e72ee29c4e6b70fb0f6ebc7a803b3d70300", "block_number": 30606, "block_offset": 1, "pay_id": "f95fcb22cd82d28084197f8a5599e16d268620bf03539c8949bde9445222332e7c2bbfc8a8381fbd0925b2dd295da932", "confirmations": 1, "countersign": false, } } ``` `Transaction` object conveys information of both `Issuance` record and `Transfer` record on the blockchain. `Issuance` record's representation will show `sender` is `null` and `receiver` is the `issuer`. ##### Attributes | Attribute | Type | Description | | -------- | -------- | -------- | | sender | string | Sender will be `null` if this is an Issue record | | receiver | string | Receiver will be owner of Issue record | | previous_id | string | Previous transaction, will be `null`if this is an Issue record| | next_id | string | Next transaction id if exists | | confirmations | integer | Number of confirmations till the current block height | | coutersign | boolean | Indicates if this transaction consists two signatures from sender and receiver | #### List transactions List all transactions with conditions. ##### Endpoint `GET /transactions` ##### Params | Param | Type | Description | | -------- | -------- | -------- | | asset_id | string | Show transactions with a specific `asset_id` | | sender | string| Show transactions with specific `sender` | | receiver | string | Show transactions with specific `receiver` | | participant | string | Show transactions with `participant` is either `sender` or `receiver` | | .... | ... |... | #### Get a transaction Get a transaction with a specific `id`. ##### Endpoint `GET /transactions/:id` #### Create a transaction Submit a transaction to blockchain, includes 1/2 signatures. 2 signatures transaction can be made on client side only and submit to the blockchain without using Bitmark API as broker. ##### Endpoint `POST /transactions` ### Bitmark A Bitmark consists an Issue record and all following Transfer records. It typically shows Issue record and the **last** Transfer record. With `full` param, it will show **all** Transfer records for a specific bitmark. #### Object ```json= { "bitmark": { "transfers": [ { "id": "69eeea53c6bfb4a525973074c5f8628dace323b972fd6423ca85f7a7da0a7870", "previous_id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "next_id": null, "sender": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "receiver": "fqiJzShni4aCDKBy6YB8ruLAsgydPtYShPZkQLXzzPdAuYYhAy", "block_number": 30606, "block_offset": 1, "pay_id": "f95fcb22cd82d28084197f8a5599e16d268620bf03539c8949bde9445222332e7c2bbfc8a8381fbd0925b2dd295da932", "confirmations": 10, "countersign": false, "expires_at": null } ], "issuance": { "asset_id": "5b44e797ea44761a07ada3c39cbe1bc0c324762674006f9377d28601f7ef624301024d3f2d744a1ae3c293a313a5fb1086ea6d79fbd02d6d315280b997690ad0", "id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "issuer": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "issued_at": "2019-08-13T17:15:23.000000Z", "pay_id": "f95fcb22cd82d28084197f8a5599e16d268620bf03539c8949bde9445222332e7c2bbfc8a8381fbd0925b2dd295da932", "edition": 6, "block_number": 30606, "confirmations": 192, "created_at": "2019-08-14T09:09:32.000000Z", } } } ``` `id` of a bitmark is the `id` of Issue record. #### List bitmarks List all bitmarks. ##### Endpoint `GET /bitmarks` #### Get a bitmarks Get a bitmark with a specific `id`. ##### Endpoint `GET /bitmarks/:id` ##### Params | Param | Type | Description | | -------- | -------- | -------- | | owner | string | Filter bitmark from a specific owner, based on the last transaction owner | | full | boolean | Show all Transfer records for each bitmark. Default is `false` | #### Issue a bitmark Issue one or multiple bitmarks ##### Endpoint `POST /bitmarks` ### TransactionIntent A TransactionIntent guides you to build transaction payload consists 2 signatures from sender and receiver. It's totally offchain, no transactions will make until a complete TransactionIntent is built. #### Object ```json= { "transaction_intent": { "id": "69eeea53c6bf", "sender": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "receiver": "fqiJzShni4aCDKBy6YB8ruLAsgydPtYShPZkQLXzzPdAuYYhAy", "asset_id": "5b44e797ea44761a07ada3c39cbe1bc0c324762674006f9377d28601f7ef624301024d3f2d744a1ae3c293a313a5fb1086ea6d79fbd02d6d315280b997690ad0", "previous_id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "expires_at": null, "created_at": "2019-08-19T19:57:52.000000Z" } } ``` #### Create a TransactionIntent Create a TransactionIntent includes sender's signature ##### Endpoint `POST /transaction-intents` #### Complete a TransactionIntent Complete a TransactionIntent with receiver's signature and broadcast the transaction to Bitmark blockchain ##### Endpoint `POST /transaction-intents/:id/complete` #### Reject a TransactionIntent Reject a TransactionIntent from receiver. Nothing will be broadcasted to blockchain. ##### Endpoint `POST /transaction-intents/:id/reject` #### Cancel a TransactionIntent Delete a TransactionIntent from sender. ##### Endpoint `DELETE /transaction-intents/:id` #### List all TransactionIntent ##### Endpoint `GET /transaction-intents` #### Get a specific TransactionIntent ##### Endpoint `GET /transaction-intents/:id` ### Share Bitmark share. #### Object ```json= { "share_id": "4ff47c5ca692699c3049eccad23ea98892d7a884c088d730f3ec42a966b85c41", "owner": "f7nuKToBByL3jEcArZWoB9PJ8MVmGPjrYkW88v3Yw8p7G5Sxhy", "balance": 2, "available": 2 } ``` #### List shares List all shares ##### Endpoint `GET /shares` #### Get a share ##### Endpoint `GET /shares/:id` #### Create a share `POST /shares` ### Share offer Bitmark share offer #### Object ```json= { "id": "73781d92-6352-4b79-a404-cb8e88f96a85", "share_id": "4ff47c5ca692699c3049eccad23ea98892d7a884c088d730f3ec42a966b85c41", "from": "fXXHGtCdFPuQvNhJ4nDPKCdwPxH7aSZ4842n2katZi319NsaCs", "to": "f7nuKToBByL3jEcArZWoB9PJ8MVmGPjrYkW88v3Yw8p7G5Sxhy", "status": "open", "txId": "", "record": { "shareId": "4ff47c5ca692699c3049eccad23ea98892d7a884c088d730f3ec42a966b85c41", "quantity": 1, "owner": "fXXHGtCdFPuQvNhJ4nDPKCdwPxH7aSZ4842n2katZi319NsaCs", "recipient": "f7nuKToBByL3jEcArZWoB9PJ8MVmGPjrYkW88v3Yw8p7G5Sxhy", "beforeBlock": 150212348, "signature": "63d0492088db46296f8fc220234be211a678dd6de576350250f79c716d9a5c920b4bbd3f1ce1c112365fa496f41e63fddd4899abfa9c1bf94a572e052ba50a0f", "countersignature": "" }, "extra_info": {}, "created_at": "2019-03-11T15:35:23.456511Z" } ``` #### List all share offers ##### Endpoint `GET /share-offers` #### Create a share offer ##### Endpoint `POST /share-offers` #### Accept a share offer ##### Endpoint `POST /share-offers/:id/accept` #### Reject a share offer ##### Endpoint `POST /share-offers/:id/reject` #### Cancel a share offer ##### Endpoint `DELETE /share-offers/:id` ## API ### Response #### Object In case of successful request, an enveloped object will be returned. ```json= { "object": "list", "total": 1, "pagination": { "start": "887319e6314a076dc696f79a466de4e4ad39fe04e13a2f3bfc4a0cb01fbc38f439e7f1f20f859bcc31eded347991abe4a556c3e15d6ad4af83aaf12cf6b5fab7", "end": "887319e6314a076dc696f79a466de4e4ad39fe04e13a2f3bfc4a0cb01fbc38f439e7f1f20f859bcc31eded347991abe4a556c3e15d6ad4af83aaf12cf6b5fab7", "has_more": false, }, "result": [ { "id": "887319e6314a076dc696f79a466de4e4ad39fe04e13a2f3bfc4a0cb01fbc38f439e7f1f20f859bcc31eded347991abe4a556c3e15d6ad4af83aaf12cf6b5fab7", "name": "GGGGG", "fingerprint": "017c828871c85275e49630c5383dbb865dc0c8f008aace65fa6fd8d8c23a80d46e399e70329532e74fc0528534661f8a8e2171083fcb13ee09e8dd2247e2741716", "metadata": { "medium": "Image" }, "registrant": "fcN6fMuvK6XdKaF6GMf8NSVHDAdwg6oVCiLp3RHKXiiHxKr73H", "status": "registered", "block_number": 16234, "expires_at": null, "created_at": "2019-08-19T19:57:52.000000Z" } ] } ``` ##### Attribute | Attribute | Type | Description | | -------- | -------- | -------- | | object | string | Object will be in `result` block. It will be either `list` if result returns an array of objects. Otherwise, it will be object name: `Asset`, `Bitmark`, `Transaction`, `TransactionIntent`, `Share`, `ShareOffer`| | total | integer | In case of returning a list, `total` will be added to indicate total items of all pages. | | pagination | object | [Pagination](#Pagination) shows the detail of current page. | | result | object | Enveloped result object from the request. | #### Error In case of error happening, an error will be returned. ```json= { "error": { "code": 1004, "message": "asset is already registered." } } ``` ### Expanding Objects Many objects contain the ID of a related object in their response properties. For example, a `Transaction` may have an associated `Asset ID`. Those objects can be expanded inline with the expand request parameter. Objects that can be expanded are noted in this documentation. This parameter is available on all API requests, and applies to the response of that request only. There are two modes you expanding objects, depending on how you want to work with the API | Mode | Description | | -------- | -------- | -------- | | inline | Child fields in the object will be replace with real object. For example: in `asset` object, `block_number` will be replaced with `block` with conveys information of the `block_number` | | group | Current objects will not be modified to include the expanding object. Instead, the result will include an additional list of expanding objects. Response payload will probably be smaller as the list of expanding objects already trims duplicated items. | ##### Endpoint `GET /{resources}?expand[object_name]=mode` ##### Params | Param | Type | Description | | -------- | -------- | -------- | | expand | array of string | List of objects need to be expanded. | ### Idempotent Requests The API supports idempotency for safely retrying requests without accidentally performing the same operation twice. This is useful when an API call is disrupted in transit and you do not receive a response. For example, if a request to create a charge does not respond due to a network connection error, you can retry the request with the same idempotency key to guarantee that no more than one charge is created. To perform an idempotent request, provide an additional `Idempotency-Key: <key>` header to the request. Idempotency works by saving the resulting status code and body of the first request made for any given idempotency key, regardless of whether it succeeded or failed. Subsequent requests with the same key return the same result, including `500` errors. An idempotency key is a unique value generated by the client which the server uses to recognize subsequent retries of the same request. How you create unique keys is up to you, but we suggest using V4 UUIDs, or another random string with enough entropy to avoid collisions. Keys are eligible to be removed from the system after they're at least 24 hours old, and a new request is generated if a key is reused after the original has been pruned. The idempotency layer compares incoming parameters to those of the original request and errors unless they're the same to prevent accidental misuse. Results are only saved if an API endpoint started executing. If incoming parameters failed validation, or the request conflicted with another that was executing concurrently, no idempotent result is saved because no API endpoint began execution. It is safe to retry these requests. All `POST` requests accept idempotency keys. Sending idempotency keys in `GET` and `DELETE` requests has no effect and should be avoided, as these requests are idempotent by definition. ### Pagination All top-level API resources have support for bulk fetches via "list" API methods. For instance, you can [list assets](#List-assets), [list transactions](#List-transactions), [list blocks](#List-blocks) and [list bitmarks](#List-bitmarks"). These list API methods share a common structure, taking at least these three parameters: `limit`, `starting_after`, and `ending_before`. #### Endpoint `GET /{resources}?limit=100` #### Response ```json= { "object": "list", "total": 105, "pagination": { "start": "ee9c81835bca023c425336598c0c46c140fcf52b471ea547279a46715b56bccb", "end": "ef6e5b14cf78f542c7bd8d0523e87e16aeeaf62cefadb25030e0005d9eaefd68", "has_more": true, }, "result": [ { "id": "ee9c81835bca023c425336598c0c46c140fcf52b471ea547279a46715b56bccb", "sender": "eXcpyJqzqdgVVMXERLRhvtJqXaVZvhKHdpFKK7eRrxP9RMs8pV", "receiver": "enfoTxHybBVWaDuem9aF2U4V7C8rd1K7XF4HtASCRr3TVyZVij", "asset_id": "041aee9ee14ec8faa9df4749d6613c03d4cbad2f07b1810efafa53e4b16c9625ee899581aeafa7e6896dafc9aebb2e72ee29c4e6b70fb0f6ebc7a803b3d70300", "block_number": 30890, "block_offset": 2, "pay_id": "3368485ebec6cf68fbfcf90e17171b653e189641d59ee989bcb548955bf0e2bb4c2deb875831513e09b3e8f15cc2b62e", "previous_id": "6a422539a87b91922dd780ed5985581a96deadd70a04abc110ed517a0d82d2a1", "next_id": null, "confirmations": 192, "coutersign": false }, { "id": "ef6e5b14cf78f542c7bd8d0523e87e16aeeaf62cefadb25030e0005d9eaefd68", "sender": "eXcpyJqzqdgVVMXERLRhvtJqXaVZvhKHdpFKK7eRrxP9RMs8pV", "receiver": "e9DShZzBQkzPBw65dh8BHUbXB4SeZ2m8traREcZeWHRLiG8VmV", "asset_id": "041aee9ee14ec8faa9df4749d6613c03d4cbad2f07b1810efafa53e4b16c9625ee899581aeafa7e6896dafc9aebb2e72ee29c4e6b70fb0f6ebc7a803b3d70300", "block_number": 30890, "block_offset": 1, "pay_id": "5711556c868b2397b22b4ae75502ff1cab8964f9f2b170a26a414457464e9931124375cd7a5f14906c52ed4e0aa5780d", "previous_id": "559942624486bacc956908f05c9b06ac7e00c495001303d65f337de58638c92c", "next_id": null, "confirmations": 192, "coutersign": false }, {...} ] } ``` Bitmark API utilizes cursor-based pagination via the `starting_after` and `ending_before` parameters. Both parameters take an existing object ID value and return objects in reverse blockchain chronological order. The `ending_before` parameter returns objects listed before the named object. The `starting_after` parameter returns objects listed after the named object. If both parameters are provided, only `ending_before` is used. #### Params | Param | Type | Description | | -------- | -------- | -------- | | limit | integer | A limit on the number of objects to be returned, between 1 and 100. Default is 100 | | starting_after | integer or string | Defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with `obj_foo`, your subsequent call can include `starting_after=obj_foo` in order to fetch the next page of the list. | | ending_before | integer or string | defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with `obj_bar`, your subsequent call can include `ending_before=obj_bar` in order to fetch the previous page of the list. | #### Attributes | Attribute | Type | Description | | -------- | -------- | -------- | | object | string | `list` in case of listing APIs | | total | integer | If it's a listing API, beside `object=list`, it also returns total items in the result | | pagination | object | `pagination` gives you information about current page, the starting object id and ending object id. `has_more` indicates the paging should stop or continue with current direction. | | result | array | array of objects in current page | ### Nesting for Relationship Filtering Bitmark API allows to filter objects in nesting level. For example, a block contains a bunch of transactions. You can query transaction of a specific block like this: ```GET /blocks/:block_number/transactions``` instead of ```GET /transactions?block_number=block_number``` ## Updating Data with Events Data retrieved from the Bitmark API serves as a "snapshot" of what currently exists until a block height. Clients can fetch the changed events since that block. You can also use events to see how this data came to be in the state it's currently in via a "timeline" view. `Event` API only available to sync data for an account. To sync up data for whole blockchain, we recommend to fetch all of `Transaction` from that block onward. Here is the list of events: * `transaction.created`: when a transaction is created. With a filter by account, this will notify when the account is either `sender` or `receiver` of a transaction. * `bitmark.received`: when a bitmark is issued or transfered to an account. With a filter by account, this will notify when the account is `issuer` or `receiver`. * `bitmark.left`: when a bitmark is transfered from an account. With a filter by account, this will notify when the account is `sender`. * `transaction.deleted`: when a transaction is deleted from blockchain. This happens on blockchain fork event. * `bitmark.deleted`: when a bitmark issuance or transfer is deleted from blockchain. This happens on blockchain fork event. ### API API provides method to data local data via pooling. The events will be filtered by specific account. #### Object ```json= { "object": "list", "total": 3, "result": [ { "event_name": "bitmark.received", "block_number": 31231, "value": { "transfers": [ { "id": "69eeea53c6bfb4a525973074c5f8628dace323b972fd6423ca85f7a7da0a7870", "previous_id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "next_id": null, "sender": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "receiver": "fqiJzShni4aCDKBy6YB8ruLAsgydPtYShPZkQLXzzPdAuYYhAy", "block_number": 30606, "block_offset": 1, "pay_id": "f95fcb22cd82d28084197f8a5599e16d268620bf03539c8949bde9445222332e7c2bbfc8a8381fbd0925b2dd295da932", "confirmations": 10, "countersign": false, "expires_at": null } ], "issuance": { "owner": "fqiJzShni4aCDKBy6YB8ruLAsgydPtYShPZkQLXzzPdAuYYhAy", "asset_id": "5b44e797ea44761a07ada3c39cbe1bc0c324762674006f9377d28601f7ef624301024d3f2d744a1ae3c293a313a5fb1086ea6d79fbd02d6d315280b997690ad0", "id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "issuer": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "issued_at": "2019-08-13T17:15:23.000000Z", "edition": 6, "block_number": 30606, "confirmations": 192, "created_at": "2019-08-14T09:09:32.000000Z", } } }, {...} ] } ``` ##### Attributes | Attribute | Type | Description | | -------- | -------- | -------- | | event_name | string | Event name from the list above. | | block_number | integer | Block number that the event occurred. | | value | object | Payload object | #### Endpoint `GET /events` #### Params | Param | Type | Description | | -------- | -------- | -------- | | limit | integer | A limit on the number of events to be returned, between 1 and 100. Default is 100. | | starting_after | integer | Starting block number. | | ending_before | integer or string | Ending block number. Uses `last` to get events until current block height | ### Webhook Webhook provides method to sync data in realtime. Webhook will trigger everytime a new block is spawned. You need to register webhook endpoint in Bitmark API console. Webhook will send all events happen in a block. #### Endpoint `POST {webhook-api-endpoint}/:block_number` #### Object ```json= { "object": "list", "total": 3, "result": [ { "event_name": "bitmark.received", "block_number": 31231, "value": { "transfers": [ { "id": "69eeea53c6bfb4a525973074c5f8628dace323b972fd6423ca85f7a7da0a7870", "previous_id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "next_id": null, "sender": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "receiver": "fqiJzShni4aCDKBy6YB8ruLAsgydPtYShPZkQLXzzPdAuYYhAy", "block_number": 30606, "block_offset": 1, "offset": 3937864, "pay_id": "f95fcb22cd82d28084197f8a5599e16d268620bf03539c8949bde9445222332e7c2bbfc8a8381fbd0925b2dd295da932", "confirmations": 10, "countersign": false, "expires_at": null } ], "issuance": { "owner": "fqiJzShni4aCDKBy6YB8ruLAsgydPtYShPZkQLXzzPdAuYYhAy", "asset_id": "5b44e797ea44761a07ada3c39cbe1bc0c324762674006f9377d28601f7ef624301024d3f2d744a1ae3c293a313a5fb1086ea6d79fbd02d6d315280b997690ad0", "id": "474e2201038699899a5c68a01a8cdbef907479401d81a3758b30c23bdfd23cfa", "issuer": "edSfoRTKgr4vEnAVdSyEzKGmMEfUH3aHv3xex1yBjyQb3FbPy6", "issued_at": "2019-08-13T17:15:23.000000Z", "edition": 6, "block_number": 30606, "offset": 3937864, "confirmations": 192, "created_at": "2019-08-14T09:09:32.000000Z", } } }, {...} ] } ```