Use Case 2: Issuing Assets for Distribution

API Integration Flow

The following is a walkthrough for integrating into the FinP2P API for the purpose of issuing assets for distribution on the Ownera Network by an issuer. The steps involve:

  1. Onboarding the issuer
  2. Onboarding the asset
  3. Creating a primary sales intent
  4. Polling and processing primary and secondary intent execution requests
  5. Withdrawal of received funds from intent payments
#ActionDescriptionAPI Reference

Onboard the Investor
1Create User Account for IssuerRegisters the investor in the FinP2P network.https://finp2p-docs.ownera.io/reference/createownerprofile
2Add Certificates (optional)Attach certificates to the investor, such as KYC/AML.

For FinP2P recommended certificate specifications refer to https://github.com/owneraio/finp2p-certificates-spec
https://finp2p-docs.ownera.io/reference/createcertificate
3Attached documents (option)Add any other documentation that would be required for the investor to trade with the given counterparties.https://finp2p-docs.ownera.io/reference/addcertificatedoc
4Share the new issuer with the given organizationsAllow the users to trade (associate) with the given organization(s).

Furthermore, associate the user with the given escrow organization that will be used during execution of token issuance. Note: If the user belongs to an organization that also provides escrow payment service to the given user, this step is not required.
https://finp2p-docs.ownera.io/reference/shareprofile

Setup the Account
5Defining the account for receiving payments.This step is not necessary as the payment will be routed during the execution.n/a

Onboarding an Asset
6Create an AssetDefine the asset you are onboarding, including values such as asset denominationhttps://finp2p-docs.ownera.io/reference/createassetprofile
7Attached certificatesAttach certificates, such as “KYA” to the given asset.https://finp2p-docs.ownera.io/reference/createcertificate
8Add documents to certificatesAttached additional documents to the given asset certificate, such as PDFs or images of the asset.https://finp2p-docs.ownera.io/reference/addcertificatedoc
9Share the AssetShare an asset with the given organization(s) that you allow to have access to the asset to invest in.https://finp2p-docs.ownera.io/reference/shareprofile
10Receive a notification that an asset was createdOptional. If the asset is onboarded not on your side (e.g., defined using the Ownera App), you will receive this message once the asset is created.https://finp2p-docs.ownera.io/reference/createasset

Create and Processing Primary Sale
11Create a Primary SaleAllow for investors in which you shared the asset with to investment in the primary sale (issuance).

This is an intent of type “Primary Sales”.
https://finp2p-docs.ownera.io/reference/addassetprofileintent
12Process Primary Sale execution requestDevelop the logic to process the primary sale intent execution request which is sent to your adapter.

This step can include logic for handling regulations and other order execution acceptance parameters

The request can either be processed synchronously or asynchronously (isCompleted set to True or false accordingly)

Respond with a CID which will be used as a method to poll your side for completion.
https://finp2p-docs.ownera.io/reference/issueassets
13Allow for ability to request the status for the transactionImplement the get operation ability in order to allow to query for the status of the execution request sent to you.https://finp2p-docs.ownera.io/reference/getoperation-1
14Subscribe or query for receiptsUses GraphQL to either subscribe or query for the receipts that will serve as confirmation that the investment was executed and payment was processed.https://finp2p-docs.ownera.io/reference/the-graphql-schema
15Implement ability to get receiptAllow to request receipt details from your ledger.https://finp2p-docs.ownera.io/reference/getreceipt-1
16Implement ability to get balanceAllow to request the token balance for the given owner on the asset.https://finp2p-docs.ownera.io/reference/getassetbalance

Process Secondary Intent Executions
17Process secondary intent execution requestDevelop the logic to process the secondary intent execution request which is sent to your adapter.

This step can include logic for handling regulations and other order execution acceptance parameters

The request can either be processed synchronously or asynchronously (isCompleted set to True or false accordingly)

Respond with a CID which will be used as a method to poll your side for completion.
https://finp2p-docs.ownera.io/reference/transferasset
18Allow for ability to request the status for the transactionImplement the get operation ability in order to allow to query for the status of the execution request sent to yohttps://finp2p-docs.ownera.io/reference/getoperation-1
19Implement ability to get receiptAllow to request receipt details from your ledger.https://finp2p-docs.ownera.io/reference/getreceipt-1
20Implement ability to get balanceAllow to request the token balance for the given owner on the asset.https://finp2p-docs.ownera.io/reference/getassetbalance

Update balance manually
21Import a transaction in order to adjust holdings balanceThis will allow you to update the Ownera with any balance changes due to transactions performed outside the Ownera network on your side.Import Transaction

Request Fund Withdrawal
22Request fund withdrawalThe issuer has the option to withdraw the funds that are in the given account by putting in a request for withdrawal. This request is routed to the given payment service provider to process.https://finp2p-docs.ownera.io/reference/createwithdrawrequest
23Poll for the request responseIf the request is processed asynchronously, use the get operations to receive the response.[https://finp2p-docs.ownera.io/reference/getoperation](https://finp2p-docs.ownera.io/reference/getoperation)

Using the Ownera App for Testing

You can use the Ownera App to simulate buyers on the Ownera Network investing in your onboarded asset.
● You will receive a node operator type user in which will allow you to onboard an investor for testing.
● The escrow payment process will be that of the node that is assigned to you, in which you will be able to administer the user funds who is investing in your asset

#ActionExample

Set up an Investor to Invest in your Primary Sale
1Run your integration to set up the issuer, the asset, and the primary sale. Remember to share the asset if the investor is going to be created in a different organization than that of the asset.n/a
2Login into the Ownera app using the URL you were provided.image
3Create an investor in which will execute your intent.

Go to the “Owner” tab and click the
+” to add a new investor.
image
4You will need to add funds for the investor. Firstly you will need to open a deposit account for the investor.image
5Select the escrow service that is used, and denomination for the account.image
6Given you have an escrow payment capability deployed for your node, you can use the option of “add cash” for the investor. If not you will need access to an escrow node login.image
7Add the funds for the given investor account. Click confirm. After this the investor is ready to be used for testing.image
8Open the investor’s dashboard. In the Asset tab you will see the asset available for investment. Hit the Invest button.image
9Select the escrow account you created in the previous step for the test investor, and enter the amount to trade against the primary sale. Click “Confirm Transaction” to execute.image
10You should see through your integration the execution request for the given intent you created, and the receipts sent confirming the transaction completion and details.n/a

Example: Asset Onboarding

The following is an example for the onboarding of an issuer and an asset that is offered for primary sale investment:

ParameterDescriptionValue
Issuer Fin IDThe public key used in creating the user profile, which in turn will be used as the finID for the user when transacting.024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a
Issuer User IDThe finP2P resource ID for the given user created.bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181
Issuer Escrow Org IDThe escrow organization that will be used to transact the investmentownera-escrow
Asset IDThe asset ID assigned to the created asset.bank-us:102:631dd696-302b-4f6e-b91f-79cc7bf84f54
Primary Sale Intent IDThe Id assigned to the primary sale intent that is created.bank-us:105:3a360d7a-df60-40b2-9574-eccaa1ed1f08

Create user profile.

curl --location --request POST 'http://localhost:62532/profiles/owner' \
--header 'Content-Type: application/json' \
--data-raw '{
    "publicKey": "024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a",
    "signature": ""
}'
{
    "isCompleted": true,
    "response": {
        "id": "bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181"
    },
    "type": "profile"
}

Attach certificate to the given user.

curl --location --request POST 'http://localhost:62532/profiles/bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181/certificates' \
--header 'Content-Type: application/json' \
--data-raw '{
  "type": "ownerInfo",
  "issuanceDate": 1668598695,
  "expirationDate": 1700134695,
  "data": "{\"email\":\"[email protected]\",\"name\":\"Issuer1\",\"type\":\"issuer\"}"
}'
{
    "id": "ec634170-8c62-4d55-b324-0391eb30fac1"
}

Upload a document to the given certificate, pointing to a location of the file.

curl --location --request POST 'http://localhost:62532/profiles/bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181/certificates/ec634170-8c62-4d55-b324-0391eb30fac1' \
--form '[email protected]"/kyc.pdf"'

Associate the user with the given escrow service.

curl --location --request POST 'http://localhost:62532/profiles/bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181\share' \
--header 'Content-Type: application/json' \
--data-raw '{
     "organizations": [
          "ownera-escrow"
     ]
}'
n/a

Create the asset.

curl --location --request POST 'http://localhost:62532/profiles/asset' \
--header 'Content-Type: application/json' \
--data-raw '{     "denomination": {
          "type": "fiat",
          "code": "USD"
     },
     "config": " ",
     "name": "BUILDING123456789",
     "type": "Building",
     "issuerId": "bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181"
}'
{
    "isCompleted": true,
    "response": {
        "id": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
    },
    "type": "profile"
}

Attached a Know Your Asset (KYA) certificate to the asset.

curl --location --request POST 'http://localhost:62532/profiles/bank-us:102:873e82a0-274a-4762-8535-7b9540cf680b/certificates' \
--header 'Content-Type: application/json' \
--data-raw '{

  "type": "KYA",
  "issuanceDate": 1668598695,
  "expirationDate": 1672399561,
  "data": "{\"info\":[{\"type\":\"text\",\"name\":\"Issuer\",\"value\":\"Test Company 1\"},{\"type\":\"text\",\"name\":\"Headquarters\",\"value\":\"NYC\"},{\"type\":\"text\",\"name\":\"Industry\",\"value\":\"Real Estate\"},{\"type\":\"link\",\"name\":\"Website\",\"value\":\"www.asset.com\"}]}"
}'

Create a Primary Sale Intent.

The intent below is an example of making 50 tokens available each at the price of 1 USD. The intent indicates the finId and the escrow organization that is going to be used for managing the issuance, and the destination for the payment for the investment.**

curl --location --request POST 'http://localhost:62532/profiles/asset/:assetId/intent' \
--header 'Content-Type: application/json' \
--data-raw '{
     "assetTerm": {
          "asset": {
               "type": "finp2p",
               "resourceId": "\"bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
          },
          "amount": "50"
     },
     "assetInstruction": {
          "account": {
               "account": {
                    "type": "finId",
                    "finId": "024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a",
                    "orgId": "ownera-escrow"
               },
               "asset": {
                    "type": "finp2p",
                    "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
               }
          }
     },
     "settlementTerm": {
          "asset": {
               "type": "fiat",
               "code": "USD"
          },
          "unitValue": "1"
     },
     "intent": {
          "type": "primarySale",
          "settlementInstruction": {
               "type": "escrow",
               "destinationAccounts": [
                    {
                         "account": {
                              "type": "finId",
                              "finId": "024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a",
                              "orgId": "ownera-escrow"
                         },
                         "asset": {
                              "type": "fiat",
                              "code": "USD"
                         }
                    }
               ]
          },
          "issuer": "bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181"
     },
     "start": 1671108000,
     "end": 1672399561
}'
{
    "id": "bank-us:105:cd3a32e0-da32-4161-a00b-d138a56712d6"
}

Receive a message and respond back to primary sale investment request.

Insert example here
Insert example here

Process polling request on status of execution request.

Insert example here

**Use GraphQL subscription to get receipts in order to receive indication of investment executions, including confirmation of payment.

There will be two generated receipts:

  1. Token Exchange Confirmation
  2. Payments Confirmation

Note both paired receipts are related via the "settlementRef" value.
**

subscription Receipts {
  receiptAdded {
    id
    asset {
      __typename
      ... on FinP2PAsset {
        resourceId
      }
    }
    source {
      id
      publicKey
      certificates {
        nodes {
          expiry
          type
          data
        }
      }
    }
    sourceAccount {
        __typename
        ... on Iban {
          __typename
        }
        ... on FinIdAccount {
          finId
        }
        ... on CryptoWalletAccount {
          address
        }
        ... on FinIdAccount {
          __typename
        }
      }
      destination {
        id
        publicKey
        certificates {
          nodes {
            expiry
            type
            data
          }
        }
      }
      destinationAccount {
        __typename
      }
      quantity
      tradeDetails {
        intent {
          id
          start
          end
          status
          assetTerm {
            amount
          }
          assetInstruction {
            account {
              asset {
                __typename
              }
            }
          }
          settlementTerm {
            asset {
              __typename
            }
            unitValue
          }
          remainingQuantity
          type
          intent {
            __typename
          }
        }
      }
      settlementRef
      transactionId
    }
  
}
{
  "data": {
    "receipts": {
      "nodes": [
        {
          "id": "c8f1d7c3-1868-4ec0-a4ee-8a342023cd68",
          "asset": {
            "__typename": "FinP2PAsset",
            "resourceId": "bank-us:102:631dd696-302b-4f6e-b91f-79cc7bf84f54"
          },
          "source": {
            "id": "",
            "publicKey": "",
            "certificates": {
              "nodes": []
            }
          },
          "sourceAccount": {
            "__typename": "FinIdAccount",
            "finId": ""
          },
          "destination": {
            "id": "bank-us:101:7572e35f-f9c4-42f6-adee-9669656e6806",
            "publicKey": "039e83762efdb9f4efd8acff6afd4c66a214dee8e288a689a2e9aaf409db75c979",
            "certificates": {
              "nodes": [
                {
                  "expiry": 1700134695,
                  "type": "ownerInfo",
                  "data": "{\"email\":\"[email protected]\",\"name\":\"Investor_us_5_api\",\"type\":\"company\"}"
                }
              ]
            }
          },
          "destinationAccount": {
            "__typename": "FinIdAccount"
          },
          "quantity": "1",
          "tradeDetails": {
            "intent": {
              "id": "bank-us:105:249e3d4e-0530-46c9-bde2-e76c1709ce67",
              "start": 1672236375,
              "end": 1672495560,
              "status": "ACTIVE",
              "assetTerm": {
                "amount": "100"
              },
              "assetInstruction": {
                "account": {
                  "asset": {
                    "__typename": "FinP2PAsset"
                  }
                }
              },
              "settlementTerm": {
                "asset": {
                  "__typename": "FiatAsset"
                },
                "unitValue": "1"
              },
              "remainingQuantity": "99",
              "type": "primarySale",
              "intent": {
                "__typename": "PrimarySale"
              }
            }
          },
          "settlementRef": "44b7c009-beb2-8b7c-5a47-6b843d4e6b2a",
          "transactionId": ""
        }
      ]
    }
  }
}
{
  "data": {
    "receiptAdded": {
      "id": "79af30c5-634f-465a-a740-45a4cb23f064",
      "asset": {
        "__typename": "FiatAsset"
      },
      "source": {
        "id": "bank-us:101:7572e35f-f9c4-42f6-adee-9669656e6806",
        "publicKey": "039e83762efdb9f4efd8acff6afd4c66a214dee8e288a689a2e9aaf409db75c979"
      },
      "sourceAccount": {
        "__typename": "FinIdAccount",
        "finId": "039e83762efdb9f4efd8acff6afd4c66a214dee8e288a689a2e9aaf409db75c979"
      },
      "destination": {
        "id": "bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181",
        "publicKey": "024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a"
      },
      "destinationAccount": {
        "__typename": "FinIdAccount"
      },
      "quantity": "1.00",
      "tradeDetails": {
        "intent": null
      },
      "settlementRef": "44b7c009-beb2-8b7c-5a47-6b843d4e6b2a",
      "transactionId": ""
    }
  }
}

Example: Processing Secondary Intent Execution Request

Approve or reject secondary intent execution request:

You will receive this message and can respond synchronously or asynchronously to the intent execution request, with an acceptance or rejection of the trade.

curl --location --request POST 'http://localhost:62532/assets/transfer' \
--header 'Content-Type: application/json' \
--data-raw '
    {"nonce": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d",  
  "asset": {
    "resourceId": "bank-il:102:d6b2d0fa-8876-48ec-930f-de364b697f6d",
    "type": "finp2p"
  },
  "destination": {
    "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c",
   "account": {
      "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c",
      "type": "finId"
    }   
  },
  "quantity": "5",
  "settlementRef": "82e8a507-5939-8369-6163-f70d071e67f1",
  "signature": {
    "signature": "4161063d6353d991b5ff58c666fc5c5fa3b8a56863639eef7f19fc5e6e4d61747d3dcd5aed9d9a1978f5bc0486086e8798ffa8d3613c1367e112e8649a831856",
    "template": {
      "hash": "2433e6287831821d342c1b744495982ef579d41dc5af629c8f3fcaa1e4cb071f",
      "hashGroups": [
        {
          "fields": [
            {
              "name": "nonce",
              "type": "bytes",
              "value": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d"
            },
            {
              "name": "operation",
              "type": "string",
              "value": "transfer"
            },
            {
              "name": "assetType",
              "type": "string",
              "value": "finp2p"
            },
            {
              "name": "assetId",
              "type": "string",
              "value": "bank-il:102:d6b2d0fa-8876-48ec-930f-de364b697f6d"
            },
            {
              "name": "srcAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "srcAccount",
              "type": "string",
              "value": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3"
            },
            {
              "name": "dstAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "dstAccount",
              "type": "string",
              "value": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c"
            },
            {
              "name": "amount",
              "type": "string",
              "value": "5"
            }
          ],
          "hash": "55cb7e7c12fe68b010e92bcd68eaaa0983c871fd2bf029d4b84af32b059d366c"
        },
        {
          "fields": [
            {
              "name": "assetType",
              "type": "string",
              "value": "fiat"
            },
            {
              "name": "assetId",
              "type": "string",
              "value": "USD"
            },
            {
              "name": "srcAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "srcAccount",
              "type": "string",
              "value": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c"
            },
            {
              "name": "dstAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "dstAccount",
              "type": "string",
              "value": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3"
            },
            {
              "name": "amount",
              "type": "string",
              "value": "10"
            }
          ],
          "hash": "85fe087c5915b6ba1a9fca230c752d78095e633c22195591de0944338765c6eb"
        }
      ]
    }
  },
  "source": {
    "account": {
      "finId": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3",
      "type": "finId"
    },
    "finId": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3"
  }
}
Insert example here

Process polling request to check on status of execution .

Insert example here
Insert example here

Example: Importing Transactions Manually

**Import transaction**

POST /ledger/transaction/import

The following allows you to send manual updates to Ownera for the case adjustments need to be performed on the user token holdings for the given asset.

Message Schema outlined below. The "source" section should be used to take out of the given account the specified amount. The "destination" section should be used to put into the given account the specified amount. Meaning, it incrementally increase or decreases the balance of the quantity specified.

{
  "transactions": [
    {
      "id": "A unique reference id to this message",
      "asset": {
        "code": ""
      },
      "quantity": "amount change to apply",
      "timestamp": Epochtimestamp,
      "source": {
        "finId": "Fin ID of the source account",
        "account": {
          "type": "finId",
          "finId": "Fin ID of the source account",
          "orgId": "Organization ID that manages the asset
        }
      },
      "destination": {
        "finId": "Fin ID of the destination account",
        "account": {
          "type": "finId",
          "finId": "FIn ID of the destination account",
          "orgId": "Organization ID"
        }
      },
      "settlementRef": "A reference number for the settlement",
      "transactionDetails": {
        "transactionId": "ID generated for the unqiue transaction"  
      }
    }
  ]
}
curl --location --request POST 'http://localhost:53400/ledger/transaction/import' \
--header 'Content-Type: application/json' \
--data-raw '{
    "transactions": [
        {
            "id": "fa5e7391-fce9-4cf6-98e4-b53cdf38d79d",
            "asset": {
                "type": "fiat",
                "code": "USD"
            },
            "quantity": "10000",
            "timestamp": 1673863664,
            "destination": {
                "finId": "02acb467116c385e49feeb639c934dde1fcaa50ee12568fcb8856c87c1ac861632",
                "account": {
                    "type": "finId",
                    "finId": "02acb467116c385e49feeb639c934dde1fcaa50ee12568fcb8856c87c1ac861632",
                    "orgId": "bank-us"
                }
            },
            "settlementRef": "d9ea365e-56c8-43df-9674-c7132ee1c197",
            "transactionDetails": {
                "transactionId": "73358f79-3b3a-4080-90c3-cbb7edd26668"
            }
        }
    ]
}'