CL2C raw specification
The OpenAPI 3.0.3 document backing the CL2C API reference, viewable as YAML or JSON.
openapi: 3.0.3
info:
title: Taliware CL2C API
version: 1.0.0
description: |
The CL2C API lets your software do everything the Taliware Developer Platform
dashboard does: create smart contracts, invite users, issue digital assets that
their owners approve in the Confida app, and check credit balances.
## Authentication
Every request needs an API key. Create one in the Developer Platform under
**API keys**, keep it on your server, and send it in either header:
- `x-api-key: <your-api-key>` (recommended)
- `Authorization: Bearer <your-api-key>`
## Base URL
`https://developer.taliware.com/api/v1`
## What you can manage
| Resource | Path | What it's for |
|---|---|---|
| Contract | `/cl2c/contract` | The on-chain collection your assets are issued from |
| User | `/cl2c/user` | The people who own and approve your assets |
| NFT | `/cl2c/nft` | The digital assets themselves, their owners, and certificates |
| Token | `/cl2c/token` | CRDB credits that pay for blockchain activity |
> **Approved partners** that need their own in-app biometric approval or Confida QR
> login should also read the **Cordoba API** (`/api/v1/cordoba`). It uses the same
> API key and data model.
## How an asset is issued
1. `POST /cl2c/contract` creates a contract (status `CREATED`).
2. `PUT /cl2c/contract/{id}` deploys it to the blockchain (status `DEPLOYED`).
3. `POST /cl2c/user` invites each owner (or `POST /cl2c/user/bulk` for up to 100).
They finish setting up in Confida and become `ACTIVE`.
4. `POST /cl2c/nft` issues the asset (status `CREATED`) and asks every owner to approve.
5. Owners approve in Confida. Once all have approved, the asset is recorded on the
blockchain automatically (status `MINTED`).
6. `GET /cl2c/nft/{id}` returns the result, including on-chain details (transaction
hash, IPFS addresses, gas fee) in `metadata`.
## CRDB credits
- **Test (faucet) CRDB** is free and runs on the Polygon Amoy test network. Use it while you build.
- **Live (mainnet) CRDB** runs on Polygon mainnet and is required for production assets.
Buy or claim credits in the Developer Platform (card via Stripe, or MATIC via MetaMask).
servers:
- url: https://developer.taliware.com/api/v1
description: Production
tags:
- name: Contract
description: Create and deploy the on-chain collection your assets are issued from
- name: User
description: Invite the people who own and approve your assets
- name: NFT
description: Issue digital assets, track owner approvals, and get certificates
- name: Tokens
description: Check and send the CRDB credits that pay for blockchain activity
components:
securitySchemes:
apiKeyAuth:
type: apiKey
in: header
name: x-api-key
apiKeyBearerAuth:
type: http
scheme: bearer
bearerFormat: API key
cookieAuth:
type: apiKey
in: cookie
name: next-auth.session-token
schemas:
# Generic error shape used across endpoints
Error:
type: object
description: Standard error payload
properties:
error:
type: string
details:
type: array
items:
type: string
# Simple pagination envelope used by list endpoints
Pagination:
type: object
properties:
page:
type: integer
description: Current page (1-indexed)
limit:
type: integer
description: Items per page
total:
type: integer
description: Total number of matching records
totalPages:
type: integer
hasNext:
type: boolean
hasPrev:
type: boolean
PaginatedResponse:
type: object
properties:
data:
type: array
items:
type: object
pagination:
$ref: '#/components/schemas/Pagination'
filters:
type: object
additionalProperties: true
# Contract
Contract:
type: object
properties:
id:
type: string
name:
type: string
symbol:
type: string
description:
type: string
network:
type: string
env:
type: string
status:
type: string
enum: [CREATED, DEPLOYED, FAILED]
contractAddress:
type: string
deployedAt:
type: string
format: date-time
metadata:
type: object
totalNFTs:
type: integer
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
ContractCreate:
type: object
required: [name, symbol]
properties:
name:
type: string
symbol:
type: string
description:
type: string
network:
type: string
enum: [POLYGON]
env:
type: string
enum: [TESTNET, MAINNET]
metadata:
type: object
ContractUpdate:
type: object
required: [id]
properties:
id:
type: string
status:
type: string
enum: [CREATED, DEPLOYED, FAILED]
contractAddress:
type: string
deployedAt:
type: string
format: date-time
ContractDelete:
type: object
required: [contractId]
properties:
contractId:
type: string
# User
CreateUser:
type: object
required:
- email
properties:
email:
type: string
format: email
phone:
type: string
nullable: true
BulkUserEntry:
type: object
required:
- email
properties:
email:
type: string
format: email
phone:
type: string
nullable: true
BulkCreateUser:
type: object
required:
- users
properties:
users:
type: array
minItems: 1
maxItems: 100
items:
$ref: '#/components/schemas/BulkUserEntry'
BulkUserResult:
type: object
properties:
email:
type: string
format: email
status:
type: string
enum: [invited, skipped, failed]
reason:
type: string
nullable: true
description: Present when status is skipped or failed.
id:
type: string
nullable: true
description: Invitation ID, present when status is invited.
BulkCreateUserResponse:
type: object
properties:
data:
type: object
properties:
results:
type: array
items:
$ref: '#/components/schemas/BulkUserResult'
summary:
type: object
properties:
total:
type: integer
description: Number of unique emails processed.
invited:
type: integer
skipped:
type: integer
description: Already a member or pending invitation.
failed:
type: integer
description: Unexpected errors during invitation creation.
UserOrgSummary:
type: object
properties:
id:
type: string
email:
type: string
walletAddress:
type: string
nullable: true
totalNFTs:
type: integer
status:
type: string
enum: [ACTIVE, INVITED]
createdAt:
type: string
format: date-time
nullable: true
updatedAt:
type: string
format: date-time
nullable: true
user:
$ref: '#/components/schemas/UserInfo'
UserOrgItem:
type: object
properties:
data:
$ref: '#/components/schemas/UserOrgSummary'
UserInfo:
type: object
properties:
id:
type: string
nullable: true
name:
type: string
nullable: true
image:
type: string
nullable: true
emailVerified:
type: boolean
nullable: true
isRegistered:
type: boolean
UpdateUser:
type: object
properties:
email:
type: string
format: email
resend:
type: boolean
description: Resend invitation (only for pending invitations)
UserOrgDetail:
type: object
properties:
id:
type: string
email:
type: string
walletAddress:
type: string
nullable: true
user:
type: object
properties:
name:
type: string
nullable: true
image:
type: string
nullable: true
endUserNfts:
type: array
items:
type: object
properties:
status:
type: string
percentage:
type: number
copyAuthLocation:
type: string
nullable: true
copyAuthTimestamp:
type: string
format: date-time
nullable: true
nft:
type: object
properties:
id:
type: string
status:
type: string
mintedAt:
type: string
format: date-time
supply:
type: integer
name:
type: string
description:
type: string
nullable: true
externalUrl:
type: string
nullable: true
imagePath:
type: string
nullable: true
smartContract:
type: object
properties:
name:
type: string
symbol:
type: string
contractAddress:
type: string
status:
type: string
enum: [ACTIVE, INVITED]
UserOrgUpdateResponse:
type: object
properties:
id:
type: string
email:
type: string
format: email
walletAddress:
type: string
nullable: true
# NFT
MintRequest:
type: object
required: [name, smartContractId, copyright]
properties:
name:
type: string
description:
type: string
externalUrl:
type: string
imagePath:
type: string
description: >
Optional. ipfs:// URI, data URI, raw base64, http(s) URL, or local path for
the asset's image. If omitted, the NFT is created as traceability-only —
an on-chain record and metadata JSON are created with no IPFS file upload.
metadata:
type: object
smartContractId:
type: string
supply:
type: integer
copyright:
type: array
items:
type: object
required: [userId, percentage]
properties:
userId:
type: string
percentage:
type: number
UpdateNFT:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
status:
type: string
# enum: [PENDING, CREATED, MINTED, ATTACHED, FAILED]
enum: [PENDING, CREATED, MINTED, FAILED]
mintedAt:
type: string
format: date-time
DeleteNFTRequest:
type: object
properties:
nftId:
type: string
NFTSummary:
type: object
properties:
id:
type: string
status:
type: string
name:
type: string
description:
type: string
externalUrl:
type: string
imagePath:
type: string
supply:
type: integer
mintedAt:
type: string
format: date-time
smartContract:
type: object
properties:
id:
type: string
name:
type: string
symbol:
type: string
contractAddress:
type: string
status:
type: string
network:
type: string
env:
type: string
NFTDetail:
allOf:
- $ref: '#/components/schemas/NFTSummary'
- type: object
properties:
metadata:
type: object
description: |
On-chain metadata recorded after minting. Common fields:
- `transactionHash` — blockchain tx hash (0x…, 66 chars)
- `gasFee` — gas paid in wei (string, convert with /1e18 to get ETH)
- `confirmationTime` — ISO 8601 timestamp when tx was confirmed
- `ipfsMetadata` — IPFS CID of the metadata JSON (Qm…)
- `ipfsCopyright` — IPFS CID of the copyright JSON
additionalProperties: true
copyright:
type: array
description: Per-owner copyright and confirmation records.
items:
type: object
properties:
id:
type: string
status:
type: string
enum: [PENDING, CONFIRMED, REJECTED, MINTED]
description: Confirmation status for this copyright holder.
percentage:
type: number
description: Ownership percentage (0–100). All owners must sum to 100.
email:
type: string
copyAuthLocation:
type: string
nullable: true
description: Geolocation or description recorded at time of biometric confirmation.
copyAuthTimestamp:
type: string
format: date-time
nullable: true
description: When the owner confirmed (or rejected) the copyright.
walletAddress:
type: array
nullable: true
items:
type: object
properties:
address:
type: string
isPrimary:
type: boolean
userName:
type: string
nullable: true
userImage:
type: string
nullable: true
totalOwners:
type: integer
UpdateNFTbyID:
type: object
properties:
name:
type: string
description:
type: string
externalUrl:
type: string
format: uri
supply:
type: integer
minimum: 1
metadata:
type: object
additionalProperties: true
TokenBalanceResponse:
type: object
properties:
balance:
type: number
walletAddress:
type: string
nullable: true
TokenBalancesResponse:
type: object
properties:
mainnet:
$ref: '#/components/schemas/TokenBalanceResponse'
faucet:
allOf:
- $ref: '#/components/schemas/TokenBalanceResponse'
nullable: true
TokenSendRequest:
type: object
required: [memberId, amount]
properties:
memberId:
type: string
amount:
type: number
minimum: 0
exclusiveMinimum: true
tokenType:
type: string
enum: [mainnet, faucet]
default: mainnet
TokenSendResponse:
type: object
properties:
success:
type: boolean
example: true
transactionHash:
type: string
nullable: true
tokenType:
type: string
enum: [mainnet, faucet]
StripeCheckoutRequest:
type: object
required: [amount]
properties:
amount:
type: number
minimum: 1
StripeCheckoutResponse:
type: object
properties:
sessionId:
type: string
checkoutUrl:
type: string
paths:
# Contracts
/cl2c/contract:
get:
tags:
- Contract
summary: List contracts
description: 'Returns your organization''s smart contracts. Filter by `status` or `search`, and page through results with `page` and `limit`.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: query
name: page
schema:
type: integer
- in: query
name: limit
schema:
type: integer
- in: query
name: search
schema:
type: string
- in: query
name: status
schema:
type: string
enum: [CREATED, DEPLOYED, FAILED]
- in: query
name: sortBy
schema:
type: string
- in: query
name: sortOrder
schema:
type: string
enum: [asc, desc]
responses:
'200':
description: Array of contracts with pagination info
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Contract'
pagination:
$ref: '#/components/schemas/Pagination'
filters:
type: object
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- Contract
summary: Create a contract
description: 'Creates a smart contract record. It is not on the blockchain yet: deploy it next with `PUT /cl2c/contract/{id}`. Use `"env": "TESTNET"` while you build.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ContractCreate'
responses:
'201':
description: Contract created
content:
application/json:
schema:
$ref: '#/components/schemas/Contract'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Contract already exists
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Contract
summary: Update a contract record
description: 'Updates a contract''s `status`, `contractAddress`, or `deployedAt`. Most integrations never need this; to deploy a contract, use `PUT /cl2c/contract/{id}`.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ContractUpdate'
responses:
'200':
description: Contract updated
content:
application/json:
schema:
$ref: '#/components/schemas/Contract'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Contract not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- Contract
summary: Delete a contract (ID in body)
description: 'Deletes the contract named by `contractId` in the request body. Only possible while it is not deployed and has no assets.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ContractDelete'
responses:
'200':
description: Contract deleted successfully
content:
application/json:
schema:
type: object
properties:
message:
type: string
deletedContract:
type: object
properties:
id:
type: string
name:
type: string
'400':
description: Bad request / cannot delete
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Contract not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Contracts by ID
/cl2c/contract/{id}:
put:
tags:
- Contract
summary: Deploy a contract
description: 'Publishes the contract to the blockchain so you can start issuing assets from it. Fails if it is already deployed.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the contract to deploy
responses:
'200':
description: Contract deployed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Contract'
'400':
description: Bad request (e.g., invalid ID or contract already deployed)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Contract not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- Contract
summary: Delete a contract
description: 'Deletes a contract by its ID. Only possible while it is not deployed and has no assets.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the contract to delete
responses:
'200':
description: Contract deleted successfully
content:
application/json:
schema:
type: object
properties:
message:
type: string
deletedContract:
type: object
properties:
id:
type: string
name:
type: string
'400':
description: Bad request (contract deployed or has associated NFTs)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Contract not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Users (organization-scoped)
/cl2c/user:
get:
tags:
- User
summary: List users
description: 'Returns everyone in your organization: active users and pending invitations. Users who have finished setting up Confida have `status: ACTIVE`; use their `id` as the `userId` when issuing an asset.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: query
name: page
schema:
type: integer
- in: query
name: limit
schema:
type: integer
- in: query
name: search
schema:
type: string
- in: query
name: status
schema:
type: string
- in: query
name: sortBy
schema:
type: string
- in: query
name: sortOrder
schema:
type: string
enum: [asc, desc]
- in: query
name: hasWallet
schema:
type: boolean
responses:
'200':
description: Paginated list of userOrganization records
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/UserOrgSummary'
pagination:
$ref: '#/components/schemas/Pagination'
filters:
type: object
additionalProperties: true
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- User
summary: Invite a user
description: 'Sends an invitation email. The person installs Confida to finish setting up, then appears as `ACTIVE` in `GET /cl2c/user`. If the email already belongs to a registered Taliware user, they are linked straight away.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUser'
responses:
'201':
description: Created userOrganization
content:
application/json:
schema:
$ref: '#/components/schemas/UserOrgItem'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Conflict (already exists)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Bulk user invite
/cl2c/user/bulk:
post:
tags:
- User
summary: Invite many users at once
description: |
Invite up to 100 people in one request. Each email is handled separately, and the
response (HTTP 207) lists the result for each one. Duplicate emails in the request
are merged. Emails that already belong to a member or have a pending invitation come
back as `skipped`, not `failed`.
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BulkCreateUser'
example:
users:
- email: alice@example.com
- email: bob@example.com
phone: "+1 555 000 0001"
responses:
'207':
description: Multi-status — individual results per email address
content:
application/json:
schema:
$ref: '#/components/schemas/BulkCreateUserResponse'
'400':
description: Bad request (invalid body, exceeds 100-user limit, etc.)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Organization not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# User by ID
/cl2c/user/{id}:
get:
tags:
- User
summary: Get a user
description: 'Returns one user or pending invitation, with their account details and the assets they own.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the userOrganization or invitation
responses:
'200':
description: userOrganization detail
content:
application/json:
schema:
$ref: '#/components/schemas/UserOrgDetail'
'400':
description: Bad request (invalid ID)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Not found (user or invitation does not exist)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- User
summary: Update a user's email
description: 'Changes the email address of a user or invitation. Re-sending the invitation email is only possible for invitations.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the userOrganization or invitation
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUser'
responses:
'200':
description: Updated userOrganization or invitation
content:
application/json:
schema:
$ref: '#/components/schemas/UserOrgUpdateResponse'
'400':
description: Bad request (invalid body, resend for member, etc.)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Conflict (duplicate email or wallet)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- User
summary: Remove a user
description: 'Removes a user or cancels a pending invitation. Users who already have a wallet or own assets cannot be removed.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the userOrganization or invitation
responses:
'200':
description: Deleted successfully
content:
application/json:
schema:
type: object
properties:
message:
type: string
'400':
description: Bad request (user has wallet or NFTs)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# NFT collection
/cl2c/nft:
get:
tags:
- NFT
summary: List digital assets
description: 'Returns the assets (NFTs) issued from your organization''s contracts. Filter by `search`, `status`, or `contractId`, and page through results with `page` and `limit`.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: query
name: page
schema:
type: integer
- in: query
name: limit
schema:
type: integer
- in: query
name: search
schema:
type: string
description: Search NFTs by name or description
- in: query
name: status
schema:
type: string
description: Filter by NFT status (CREATED, PENDING, MINTED, FAILED)
- in: query
name: contractId
schema:
type: string
description: Filter NFTs by a specific smart contract ID
- in: query
name: sortBy
schema:
type: string
- in: query
name: sortOrder
schema:
type: string
enum: [asc, desc]
responses:
'200':
description: Paginated list of NFTs
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/NFTSummary'
pagination:
$ref: '#/components/schemas/Pagination'
filters:
type: object
additionalProperties: true
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- NFT
summary: Issue a digital asset
description: 'Registers a new asset with status `CREATED` and asks every owner listed in `copyright` to approve it in Confida. Owner percentages must add up to exactly 100. Once every owner approves, the asset is recorded on the blockchain and its status becomes `MINTED`. Include `imagePath` to store an image, or leave it out for a record-only asset.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MintRequest'
responses:
'201':
description: NFT created (userNft entries created and notifications sent)
content:
application/json:
schema:
$ref: '#/components/schemas/NFTDetail'
'400':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Related resource not found (e.g., smart contract or user)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- NFT
summary: Update an asset (ID in body)
description: 'Updates an asset''s `name`, `description`, `status`, or `mintedAt`.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateNFT'
responses:
'200':
description: NFT updated
content:
application/json:
schema:
$ref: '#/components/schemas/NFTSummary'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: NFT not found in organization
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- NFT
summary: Delete an asset (ID in body)
description: 'Deletes an asset and its pending owner approvals. Minted assets cannot be deleted.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteNFTRequest'
responses:
'200':
description: NFT deleted successfully
content:
application/json:
schema:
type: object
properties:
message:
type: string
deletedNft:
type: object
properties:
id:
type: string
name:
type: string
'400':
description: Bad request (e.g., cannot delete minted NFT)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: NFT not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# NFT collection by ID
/cl2c/nft/{id}:
get:
tags:
- NFT
summary: Get a digital asset
description: 'Returns one asset with each owner''s share and approval status, plus its blockchain details once minted.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: NFT ID
responses:
'200':
description: NFT detail
content:
application/json:
schema:
$ref: '#/components/schemas/NFTDetail'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden (NFT does not belong to organization)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: NFT not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- NFT
summary: Update an asset
description: 'Updates an asset''s `name`, `description`, `status`, or `mintedAt`. Only possible before it is finalized (while `CREATED` or `PENDING`).'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateNFTbyID'
responses:
'200':
description: Updated NFT
content:
application/json:
schema:
$ref: '#/components/schemas/NFTSummary'
'400':
description: Bad request / invalid state (e.g., NFT already MINTED or ATTACHED)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden (NFT does not belong to your organization)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: NFT not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- NFT
summary: Delete an asset
description: 'Deletes an asset and its owner records. Not possible once it is `MINTED` or `ATTACHED`.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: Deleted
content:
application/json:
schema:
type: object
properties:
message:
type: string
'400':
description: Bad request (e.g., cannot delete minted NFT)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden (NFT does not belong to your organization)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: NFT not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# Token balance and transfer
/cl2c/nft/{id}/certificate:
get:
tags:
- NFT
summary: Get a certificate of authenticity
description: >-
Returns a printable certificate of authenticity for an asset owned by the
authenticated organization, including shared ownership and the chain of
ownership. Pass `format=html` to be redirected (303) to the printable page.
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
- in: query
name: format
required: false
schema:
type: string
enum: [json, html]
default: json
responses:
'200':
description: Certificate and its links
content:
application/json:
schema:
type: object
properties:
verificationUrl:
type: string
description: Public, printable certificate page. The link is an unguessable capability, not derived from the asset id.
example: https://developer.taliware.com/certificate/3q2-7Xk9mVYb0cRf4Lw8pZ1sTnHaUe6J
printUrl:
type: string
description: Same page with `?print=1`, which opens the print dialog (print or save as PDF).
certificate:
type: object
description: >-
Certificate data: certificateNumber, state (VERIFIED | PROVISIONAL | VOID),
asset, issuer, blockchain record, owners with their shares and
authorization times, the chain of ownership, and a document fingerprint
that changes if any recorded detail changes.
'303':
description: "`format=html`: redirect to the printable certificate page"
'401':
description: Missing or invalid credentials
'403':
description: The NFT belongs to another organization
'404':
description: NFT not found
/certificates/{token}:
get:
tags:
- NFT
summary: Verify a certificate (public)
description: >-
Public verification of a certificate by its token — the last path segment of
`verificationUrl`. No credentials are needed; holding the link is the access.
security: []
parameters:
- in: path
name: token
required: true
schema:
type: string
responses:
'200':
description: Certificate and its links
content:
application/json:
schema:
type: object
properties:
verificationUrl:
type: string
description: Public, printable certificate page. The link is an unguessable capability, not derived from the asset id.
example: https://developer.taliware.com/certificate/3q2-7Xk9mVYb0cRf4Lw8pZ1sTnHaUe6J
printUrl:
type: string
description: Same page with `?print=1`, which opens the print dialog (print or save as PDF).
certificate:
type: object
description: >-
Certificate data: certificateNumber, state (VERIFIED | PROVISIONAL | VOID),
asset, issuer, blockchain record, owners with their shares and
authorization times, the chain of ownership, and a document fingerprint
that changes if any recorded detail changes.
'404':
description: No certificate has this token
/cl2c/token:
get:
tags:
- Tokens
summary: Check credit balances
description: 'Returns the organization owner''s CRDB balance. Pass `type=mainnet` (live) or `type=faucet` (test) for one balance, or leave it out to get both.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
- cookieAuth: []
parameters:
- in: query
name: type
required: false
schema:
type: string
enum: [mainnet, faucet]
description: When provided, returns a single balance object. If omitted, returns both balances.
responses:
'200':
description: Token balance response
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/TokenBalanceResponse'
- $ref: '#/components/schemas/TokenBalancesResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- Tokens
summary: Send credits to a user
description: 'Sends CRDB credits from the organization owner''s wallet to one user. Only organization owners can do this.'
security:
- apiKeyAuth: []
- apiKeyBearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TokenSendRequest'
responses:
'200':
description: Tokens sent successfully
content:
application/json:
schema:
$ref: '#/components/schemas/TokenSendResponse'
'400':
description: Invalid request body or wallet configuration
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Only owners can send tokens
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Recipient or member not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Server or token transfer error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
