Hello World Sample
Hello World: Connecting an Application to the Ownera Router
This guide walks you through connecting a simple application to the Ownera FinP2P Router. By the end, you'll have created an investor profile, linked it to a custody service, and executed a trade.
Terminology: In these guides, SuperApp is shorthand for a Router-connected integration (an Application or Utility/Connector).
Prerequisites
- Access to an Ownera Router sandbox environment
- Your credentials from Ownera:
- API Key - unique identifier for your application
- Organization ID - your organization identifier on the network
- Router URL - base URL for your Router instance (e.g.,
https://router.example.com)
- An RSA key pair for signing JWT tokens
Sandbox Environment Setup
The following services must be pre-configured in your sandbox environment:
| Service | Description |
|---|---|
| Custody Service | Simulated custody provider that manages investor keys and signing. Typically configured as custody-service or simulation. |
| Payment Service | Simulated payment/escrow provider that handles fiat currency movements. Typically configured as payment-service or payments-service. |
| Shared Asset | At least one asset must be shared with your organization by an issuer. The sandbox typically includes pre-configured test assets with open primary sale intents. |
Note: Contact Ownera to provision your sandbox environment with these simulated services and test assets.
Architecture Overview
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Your App │ │ FinP2P Router │ │ Other Parties │
│ (Application) │◄───────►│ Orchestration │◄───────►│ (Custody, Pay, │
│ │ REST │ Layer │ │ Issuers, etc) │
└─────────────────┘ GraphQL └─────────────────┘ └─────────────────┘
Your application communicates with the Router via:
- REST API (
/finapi/*) - for transactional actions (create, execute, update) - GraphQL API (
/graphql) - for queries (assets, positions, execution status)
Step 1: Authentication
Every API request requires a JWT bearer token in the Authorization header.
Token Structure
The JWT consists of three parts: Header, Payload, and Signature.
Header:
{
"alg": "RS256",
"typ": "JWT"
}Payload:
{
"aud": "<ORGANIZATION_ID>",
"apiKey": "<API_KEY>",
"nonce": "<32_BYTES_HEX>",
"iat": 1701173094,
"exp": 1701173124
}| Field | Description |
|---|---|
aud | Your organization ID |
apiKey | Your API key from Ownera |
nonce | 32 bytes: 24 random bytes + 8-byte epoch timestamp (hex encoded) |
iat | Issued-at timestamp (epoch seconds) |
exp | Expiration timestamp (iat + 30 seconds) |
Signature:
- Encode header and payload as base64url
- Concatenate with
.separator - Sign with RS256 using your private key
Final Token:
base64url(header).base64url(payload).base64url(signature)
Request Format
POST /finapi/profiles/owner HTTP/1.1
Host: router.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
{request body}Important: Each token is single-use. Generate a new token for every API call.
Step 2: Create an Investor (Owner) Profile
Create a global identity for an investor on the FinP2P network.
Request
POST /finapi/profiles/owner
Content-Type: application/json
Authorization: Bearer <token>
{}Response
{
"isCompleted": true,
"response": {
"id": "your-org:101:edc5c2cc-6688-457a-a0f6-1e7aea28d144"
},
"type": "profile"
}The returned id is the Resource ID - a globally unique identifier with format:
<organization>:<resource-type>:<uuid>
101= Owner/Investor profile102= Asset profile105= Intent106= Execution Plan
Step 3: Link Investor to Custody Service
Connect the investor to a custody provider to generate their FinID (cryptographic public key identity).
Request
POST /finapi/profiles/owner/{investorId}/account
Content-Type: application/json
Authorization: Bearer <token>
{
"orgId": "custody-service"
}Response (Async Operation)
{
"cid": "e3c59abb-f296-4556-a4c6-9c0e397ad6f9",
"isCompleted": false,
"type": "addAccount"
}Poll for Completion
GET /finapi/operations/status/{cid}
Authorization: Bearer <token>Completed Response
{
"cid": "e3c59abb-f296-4556-a4c6-9c0e397ad6f9",
"isCompleted": true,
"response": {
"custodyOrgId": "custody-service",
"finId": "02d6fea8153a9a64d13e198379dfd4ea3945d03198770e0e5b94f556c4e69f6835"
},
"type": "account"
}The finId is a compressed secp256k1 public key (33 bytes, hex encoded) that identifies the investor cryptographically.
Step 4: Add Compliance Certificates
Attach KYC/AML and accreditation certificates to the investor profile.
Request
POST /finapi/profiles/{investorId}/certificates
Content-Type: application/json
Authorization: Bearer <token>
{
"type": "ownerInfo",
"issuanceDate": 1668598695,
"expirationDate": 1700134695,
"data": "{\"email\":\"[email protected]\",\"name\":\"John Doe\",\"type\":\"individual\"}"
}Response
{
"id": "ec634170-8c62-4d55-b324-0391eb30fac1"
}Common Certificate Types
| Type | Purpose | Data Fields |
|---|---|---|
ownerInfo | Basic investor info | name, email, type |
KYC/AML | Compliance verification | country, info[] |
Accreditation | Investor accreditation | country, info[] |
Step 5: Share Investor Profile with Issuer
Before your investor can participate in an asset's primary sale or secondary market, you must share their profile with the issuer's organization.
Request
POST /finapi/profiles/{investorId}/share
Content-Type: application/json
Authorization: Bearer <token>
{
"organizations": ["issuer-org", "payment-service"]
}Response
{}Note: Share the profile with all organizations involved in the trade: the asset issuer, payment service provider, and any other counterparties.
Step 6: Query Available Assets
Use GraphQL to discover assets and open trading intents.
Request
POST /graphql
Content-Type: application/json
Authorization: Bearer <token>
{
"query": "query { assets { nodes { id name organizationId denomination { code } intents(filter: [{key: \"type\", operator: EQ, value: \"primarySale\"}, {key: \"status\", operator: EQ, value: \"ACTIVE\"}]) { nodes { id type status remainingQuantity intent { ... on PrimarySale { assetTerm { amount } settlementTerm { unitValue asset { ... on FiatAsset { code } } } } } } } } } }"
}Response
{
"data": {
"assets": {
"nodes": [
{
"id": "issuer-org:102:f96240dc-8365-475b-84e2-9611bb5e5bc0",
"name": "Real Estate Fund A",
"organizationId": "issuer-org",
"denomination": { "code": "USD" },
"intents": {
"nodes": [
{
"id": "issuer-org:105:d07ab369-8bf2-4740-a055-1d11d2edfd38",
"type": "primarySale",
"status": "ACTIVE",
"remainingQuantity": "10000",
"intent": {
"assetTerm": { "amount": "1000" },
"settlementTerm": {
"unitValue": "2",
"asset": { "code": "USD" }
}
}
}
]
}
}
]
}
}
}Step 7: Execute an Investment
Execute against an open primary sale intent.
Request
POST /finapi/tokens/execute
Content-Type: application/json
Authorization: Bearer <token>
{
"intentId": "issuer-org:105:d07ab369-8bf2-4740-a055-1d11d2edfd38",
"user": "your-org:101:edc5c2cc-6688-457a-a0f6-1e7aea28d144",
"intent": {
"type": "primarySaleExecution",
"buyer": "your-org:101:edc5c2cc-6688-457a-a0f6-1e7aea28d144",
"issuer": "issuer-org:101:3dd376f0-f03b-43dc-8229-134918f62ad9",
"nonce": "8a03fb05fcd070106d9f346b2abd86a7c72a0bf12acb30f20000000067340000",
"asset": {
"term": {
"asset": {
"type": "finp2p",
"resourceId": "issuer-org:102:f96240dc-8365-475b-84e2-9611bb5e5bc0"
},
"amount": "1000"
},
"instruction": {
"destinationAccount": {
"account": {
"type": "finId",
"finId": "02d6fea8153a9a64d13e198379dfd4ea3945d03198770e0e5b94f556c4e69f6835",
"orgId": "issuer-org",
"custodian": { "orgId": "custody-service" }
},
"asset": {
"type": "finp2p",
"resourceId": "issuer-org:102:f96240dc-8365-475b-84e2-9611bb5e5bc0"
}
}
}
},
"settlement": {
"term": {
"asset": { "type": "fiat", "code": "USD" },
"amount": "2000"
},
"instruction": {
"sourceAccount": {
"account": {
"type": "finId",
"finId": "02d6fea8153a9a64d13e198379dfd4ea3945d03198770e0e5b94f556c4e69f6835",
"orgId": "payment-service",
"custodian": { "orgId": "custody-service" }
},
"asset": { "type": "fiat", "code": "USD" }
},
"destinationAccount": {
"account": {
"type": "finId",
"finId": "03565ed4e4d889ee24b7a6f830aa0df123456789abcdef",
"orgId": "payment-service",
"custodian": { "orgId": "custody-service" }
},
"asset": { "type": "fiat", "code": "USD" }
}
}
}
}
}Response
{
"isCompleted": true,
"response": {
"executionPlanId": "your-org:106:1234567890"
},
"type": "execution"
}Step 8: Monitor Execution Plan
Track the orchestration plan status via GraphQL.
Request
POST /graphql
Content-Type: application/json
Authorization: Bearer <token>
{
"query": "query { plan(id: \"your-org:106:1234567890\") { id status creationTimestamp intent { id } } }"
}Response
{
"data": {
"plan": {
"id": "your-org:106:1234567890",
"status": "Completed",
"creationTimestamp": 1703495180,
"intent": {
"id": "issuer-org:105:d07ab369-8bf2-4740-a055-1d11d2edfd38"
}
}
}
}Execution Plan Statuses
| Status | Description |
|---|---|
Pending | Plan created, waiting for processing |
InProgress | Currently executing |
Completed | Successfully finished |
Failed | Execution failed |
Rejected | Rejected by a party |
Complete Integration Flow
┌─────────────────────────────────────────────────────────────────┐
│ SuperApp Integration Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. POST /profiles/owner │
│ └─► Create investor → Resource ID │
│ │
│ 2. POST /profiles/owner/{id}/account │
│ └─► Link custody → FinID (async, poll /operations/status) │
│ │
│ 3. POST /profiles/{id}/certificates │
│ └─► Add KYC/AML certificates │
│ │
│ 4. POST /profiles/{id}/share │
│ └─► Share investor profile with issuer & payment orgs │
│ │
│ 5. POST /graphql │
│ └─► Query assets & intents (assets must be shared with you) │
│ │
│ 6. POST /tokens/execute │
│ └─► Execute investment → Execution Plan ID │
│ │
│ 7. POST /graphql │
│ └─► Poll plan status until Completed/Failed │
│ │
└─────────────────────────────────────────────────────────────────┘
Key Concepts Reference
| Concept | Description |
|---|---|
| SuperApp | Your application connected to the Router |
| Resource ID | Global identifier: org:type:uuid |
| FinID | Cryptographic identity (secp256k1 public key) |
| Intent | Business action (primarySale, buyingIntent, sellingIntent, loanIntent) |
| Execution Plan | Multi-party workflow orchestrated by the Router |
| Certificate | Compliance/identity attestation attached to profiles |
Resources
Updated 11 days ago
