Overview
HTTPS End Point (Base URL)
https://api.web3connect.jp/rest/v1
HTTP Headers required in the requests
Especially for the APIs that need to know the identity of the client (requester)
HTTP Header
Authorization: Bearer <ACCESS_TOKEN>
ACCESS_TOKEN
is in JWT format.
ACCESS_TOKEN
v.s. API_KEY_SECRET
ACCESS_TOKEN
is used for common APIs, which must be used inAuthorization
header in HTTP request.API_KEY_SECRET
can be obtained from Web3Connect, and it should be stored in a safe place by the organization.API_KEY_SECRET
is used for critical APIs, such as refreshingACCESS_TOKEN
and generating one-time-use javascript code.API_KEY_SECRET
is never used in the header in HTTP request.ACCESS_TOKEN
here is different from the access_token used in OIDC section.
DO NOT USE API KEY SECRET IN PUBLIC ZONE OR ANY FRONTEND.
Common Response Body Format
{
"status": "ok", // "error"
"result": {}, // null, Object, Array, Boolean, String or Number
"error": null // null, Error Message in String or Error Message in Object
}
Auth API
Please obtain your API Key Secret from Web3Connect beforehand.
An API Key Secret can be used to obtain the access token and confirmation token.
Refresh (Obtain) Access Token with API Key Secret
POST
/auth/account/access_token/refresh
- No Authorization Header required
Request Body JSON Sample (
Content-Type: application/json
)
{
"api_key_secret": "<SECRET>"
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": "<ACCESS_TOKEN>",
"error": null
}
Check Account Type and Address
Please obtain your API Key Secret from Web3Connect beforehand.
An API Key Secret can be used to obtain the access token and confirmation token.
POST
/auth/account/access_token/check_account_type_and_address
- No Authorization Header required
Request Body JSON Sample (
Content-Type: application/json
)
{
"api_key_secret": "<SECRET>"
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"account_id": "<YOUR_ACCOUNT_ID>",
"id_wallet_address_eth": "<ID_WALLET_ADDRESS>",
"id_wallet_address_suri": "<ID_WALLET_ADDRESS_SURI>",
"account_type": "organization" // "end_user"
},
"error": null
}
Account Association & End-user Import
Generate Web3Connect Button OnClick JavaScript function code body
This API helps generating required JavaScript code for the Web3Connect button in organization's web page or mobile app.
POST
/auth/account/association/generate_web3connect_button_js
- No Authorization Header required
Request Body JSON Sample (
Content-Type: application/json
)
{
"api_key_secret": "<SECRET>" // YOUR API KEY SECRET,
"redirect_url": "https://company.com/abc/def?g=h&userId=xxx" // For the redirection after the end-user finishes the association process
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": "function globalWeb3ConnectButtonOnClick() {...}", // JavaScript function code body
"error": null
}
In redirect_url
of the request body, the organization should include the identifier of the end-user in order to associate the organization's end-user with an ID Wallet Address in the organization's internal system.
For example, userId=xxx
in the redirect url's query param (any query param is allowed for the organization).
(Cont'd) Embed the JavaScript code in to the organization's web page
The organization needs to embed the function code body in the <script>...</script>
section in the header of the web page,
and bind the onclick event to the button like :
<head>
<script>
/* function globalWeb3ConnectButtonOnClick() {
} */
/* from the result of the previous API call */
</script>
</head>
<body>
<button onclick="event.preventDefault();globalWeb3ConnectButtonOnClick();">
Web3Connect
</button>
</body>
(Cont'd) Let the end-user walk through the association process
Once the end-user clicks the button, the end-user will walk through the association process in a newly opened web page (association page), and Web3Connect backend will associate the end-user account (will be created if needed) with the organization account (the reason why this API needs the API_KEY_SECRET
).
(Cont'd) The organization process the callback http request (redirect_url
)
And finally, a url (the adjusted redirect url) :
GET
https://company.com/abc/def?g=h&userId=xxx&id_wallet_address=0x1234567890123456789012345678901234567890
The url will be opened by the end-user's web browser (a query param id_wallet_address
is appended to the url) at the end of the association process, the organization should process this HTTP request to finish the organization's internal system process.
(Cont'd) The organization should store the id_wallet_address
of the end-user
The organization will need to store the id_wallet_address
of the end-user inside their database or system.
Through this process, the organization will only know the id_wallet_address
of an end-user, but not its email.
An ID Wallet will be automatically created if the end-user's info does not exist in Web3Connect.
Import Existing End-user with its email (Not recommended)
This implies that the end-user already knows which email is used for login.
POST
/account/import
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Request Body JSON Sample (
Content-Type: application/json
)
{
"email": "abc@def.com"
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"email": "abc@def.com",
"id_wallet_address": "0x....",
"id_wallet_address_eth": "0x....",
"id_wallet_address_suri": "5f...."
}
"error": null
}
Import Existing End-users with their emails in batch (Submit)
This implies that the end-user already knows which email is used for login.
POST
/account/import/batch/submit
- No Authorization Header required
Request Body JSON Sample (
Content-Type: application/json
)
{
"api_key_secret": "<API_KEY_SECRET>",
"emails": ["abc@def.com", "abc2@def.com"] // max number of emails in a batch is 10000
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"batch_id": "2023-10-18T04:38:18.615Z:W0Bq3p5GpqxQwh4F"
},
"error": null
}
Please use the batch_id to poll the result in next method.
Import Existing End-users with their emails in batch (Check)
This implies that the end-user already knows which email is used for login.
POST
/account/import/batch/check
- No Authorization Header required
Request Body JSON Sample (
Content-Type: application/json
)
{
"api_key_secret": "<API_KEY_SECRET>",
"batch_id": "2023-10-18T04:38:18.615Z:W0Bq3p5GpqxQwh4F"
}
(Running) Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"batch_result": {
"batch_id": "2023-10-18T04:38:18.615Z:W0Bq3p5GpqxQwh4F",
"finished_at": "",
"result": [],
"started_at": "2023-10-18T04:38:18.615Z",
"status": "running"
}
},
"error": null
}
(Done) Response Body JSON Sample (
Content-Type: application/json
)
There can be "ok": false
, meaning the id-wallet creation with the email was failed.
{
"status": "ok",
"result": {
"batch_result": {
"batch_id": "2023-10-18T04:38:18.615Z:W0Bq3p5GpqxQwh4F",
"finished_at": "2023-10-18T04:38:19.389Z",
"result": [
{
"email": "abc@def.com",
"id_wallet_address": "0xa20165...",
"id_wallet_address_eth": "0xa20165...",
"id_wallet_address_suri": "5DpyvArpUV6H...",
"ok": true
},
{
"email": "abc2@def.com",
"id_wallet_address": "",
"id_wallet_address_eth": "",
"id_wallet_address_suri": "",
"ok": false
}
],
"started_at": "2023-10-18T04:38:18.615Z",
"status": "done"
}
},
"error": null
}
Verify API (for Organization Account)
Web3Connect will support the verification process during the creation of the organization account.
Verify Phone Step 1
This will send a code to the mobile.
POST
/verify/phone/step1
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Request Body JSON Sample (
Content-Type: application/json
)
{
"phone_number": "+8860912345678" // a valid mobile phone number in E.164 format
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"tmp_token": "token string", // this is critical for step 2
"code_sent": true
},
"error": null
}
Verify Phone Step 2
Please take the tmp_token
from the response in step 1.
POST
/verify/phone/step2
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Request Body JSON Sample (
Content-Type: application/json
)
{
"tmp_token": "token string", // from step 1
"code": "123456" // the verification code received by the phone
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": true, // phone verified
"error": null
}
Verify Domain Step 1
Only Organization Account can perform this action.
domain
in the response is from the value during the sign-up process of the Organization Account.
Please set the value of txt_record
under the domain's TXT record (the domain is already set during the sign-up process)
GET
/verify/domain/step1
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"txt_record": "web3connect-domain-verification=XXXXXXXXXX",
"domain": "company.com"
},
"error": null
}
Verify Domain Step 2
Only Organization Account can perform this action.
This step checks the txt record of the domain.
Please set the value of txt_record
under the domain's TXT record in step 1.
GET
/verify/domain/step2
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": true, // domain verified
"error": null
}
Account API
Get Public Account Info by ID Wallet Address
Please replace the <id_wallet_address>
section in the url with the ID Wallet Address (e.g. 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcdef
)
GET
/account/id_wallet/<id_wallet_address>/public_info
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"id_wallet_address": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcdef",
"id_wallet_public_key_jwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "base64url string",
"y": "base64url string"
}
},
"error": null
}
Get My Info
GET
/account/my_info
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"account_id": "6aecfd05-4de5-31c3-052c-ce3dae83057d",
"oidc_issuer_url": null,
"sub": "6aecfd05-4de5-31c3-052c-ce3dae83057d",
"name": null,
"given_name": null,
"family_name": null,
"middle_name": null,
"nickname": null,
"preferred_username": null,
"profile": null,
"picture": null,
"website": null,
"email": "My Email",
"email_verified": true,
"gender": null,
"birthdate": null,
"zoneinfo": null,
"locale": null,
"phone_number": null,
"phone_number_verified": false,
"address": null,
"account_type": "end_user",
"domain": null,
"domain_verified": false,
"id_wallet": {
"address": "0x5d2c54024c8f9d58059da8c47ba7e5bbdab6b249",
"jwk_encrypted": {
"kty": "EC",
"crv": "secp256k1",
"x": "zP1RAll6_fSP83YulysNF3L3YVef6DGa0d0Dlh794K4",
"y": "ON2BME5Sptnptg970Bnuz4qk9tZqSfaHuHg2W-jaKLE"
},
"owner": "62da2c56ec8145256f37f3fc",
"created_date_string": "2022-07-22T04:49:26.105Z",
"created_at": "2022-07-22T04:49:26.134Z",
"updated_at": "2022-07-22T04:49:26.134Z",
},
"created_at": "2022-07-22T04:49:26.125Z",
"updated_at": "2022-07-22T04:49:26.125Z",
},
"error": null
}
NFT API
Mint NFT by Organization Account
Only Organization Account can perform this action.
Organization Account's domain must be verified beforehand.
Please replace <holder_id_wallet_address>
section in the url to the id_wallet_address of the end-user account (who will become the holder of the newly minted nft).
(e.g. 0x1234567890123456789012345678901234567890
)
POST
/nft/mint/to/<holder_id_wallet_address>
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Body JSON Spec and Sample
https://docs.google.com/spreadsheets/d/1y2TTQHOvqhNcPiyFB877_60Nj-PhwQwrNN3Y8CsSiSw
Request Body JSON Sample (
Content-Type: application/json
)
{
"metadata": {
"static": {
// all required, except "expired_at"
"issuer": "string",
"contents_provider": "name",
"name": "name",
"description": "text",
"image": "url",
"link": "url",
"serial_number": 123, // integer
"total_issued": 321, // integer
"animation_url": "url",
"expired_at": "2030-12-31T12:34:56.000Z" // optional, format is Date ISO String, by default it is 9999-12-31T23:59:59.000Z
},
"dynamic": {
// all optional
"external_url": "string",
"youtube_url": "string",
"background_color": "string",
"category": "string",
"id": "string",
"points_earned": 12, // number
"unit_of_points": "string",
"program_name": "string",
"organization": "string",
"brand": "string",
"branch": "string",
"department": "string",
"address": "string",
"sns1": "string",
"sns2": "string",
"sns3": "string",
"role": "string",
"numbered_position": 1, // integer
"email": "string",
"tel": "string",
"reference_name": "string",
"license": "string",
"competency": "string",
"credential_category": "string",
"level": "string",
"status": "string",
"date_created": 1784576401, // integer
"date_modified": 1784576401, // integer
"expires": 1784576401, // integer
"valid_latitude": "string",
"valid_longitude": "string",
"valid_radius": 5.2, // number
"unit_of_length": "string",
"ticketed_seat": "string",
"total_value": 100, // number
"consumable_value": 123, // number
"price_currency": "string",
"discount_rate": 10, // number
"gtin": "string",
"gtin12": "string",
"gtin13": "string",
"gtin14": "string",
"gtin8": "string",
"has_adult_consideration": "string",
"rating": "string",
"copyright_notice": "string",
"copyright_year": 2022, // integer
"credit_text": "string",
"version": "string",
"policy": "string",
"keywords": "string",
"attributes": [], // array
"properties": {}, // object
"localization": {} // object
// and any other keys and values
}
}
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"token_id": "string",
"token_uri": "string",
"minter_digital_signature": "string",
"created_at": "2022-12-31T12:34:56.000Z",
"metadata": {
"static": {
"issuer": "string",
"contents_provider": "name",
"name": "name",
"description": "text",
"image": "url",
"link": "url",
"serial_number": 123, // integer
"total_issued": 321, // integer
"animation_url": "url"
},
"dynamic": {
"external_url": "string",
"youtube_url": "string",
"background_color": "string",
"category": "string",
"id": "string",
"points_earned": 12, // number
"unit_of_points": "string",
"program_name": "string",
"organization": "string",
"brand": "string",
"branch": "string",
"department": "string",
"address": "string",
"sns1": "string",
"sns2": "string",
"sns3": "string",
"role": "string",
"numbered_position": 1, // integer
"email": "string",
"tel": "string",
"reference_name": "string",
"license": "string",
"competency": "string",
"credential_category": "string",
"level": "string",
"status": "string",
"date_created": 1784576401, // integer
"date_modified": 1784576401, // integer
"expires": 1784576401, // integer
"valid_latitude": "string",
"valid_longitude": "string",
"valid_radius": 5.2, // number
"unit_of_length": "string",
"ticketed_seat": "string",
"total_value": 100, // number
"consumable_value": 123, // number
"price_currency": "string",
"discount_rate": 10, // number
"gtin": "string",
"gtin12": "string",
"gtin13": "string",
"gtin14": "string",
"gtin8": "string",
"has_adult_consideration": "string",
"rating": "string",
"copyright_notice": "string",
"copyright_year": 2022, // integer
"credit_text": "string",
"version": "string",
"policy": "string",
"keywords": "string",
"attributes": [], // array
"properties": {}, // object
"localization": {} // object
// and other properties
}
}
},
"error": null
}
Fetch NFT info
If the NFT's visibility is private
, then only the holder or minter can check it.
If the NFT's visibility is public
, then any account can check it.
Please replace <token_id>
section in the url with the real value (a hex string, e.g. 0xabcdef123123123123...
).
Please check the response body json in Mint NFT by Organization Account for the schema of the NFT object.
GET
/nft/<token_id>
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {}, // the NFT object, please refer to the response of mint nft
"error": null
}
Transfer NFT
This action can be performed only by the current holder or minter
Transfer the NFT to another end-user (receiver)
Please replace <token_id>
section in the url with the real value (a hex string, e.g. 0xabcdef123123123123...
).
Please replace <receiver_id_wallet_address>
section in the url with receiver's id_wallet_address (eth).
PUT
/nft/<token_id>/transfer/to/<receiver_id_wallet_address>
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Update NFT dynamic metadata
This action can be performed only by the minter of the NFT (Organization Account)
Please replace <token_id>
section in the url with the real value (a hex string, e.g. 0xabcdef123123123123...
).
Please check the response body json in Mint NFT by Organization Account for the schema of the NFT object.
PUT
/nft/<token_id>/metadata/dynamic
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Request Body JSON Sample (
Content-Type: application/json
)
{
"key1": "value1", // any key-value supported for dynamic metadata, or any custom key-value
"key2": "value2",
"key3": "value3"
// ....
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {}, // the NFT object with updated dynamic metadata, please refer to the response of mint nft
"error": null
}
List NFTs being held by an ID Wallet (End-user Account)
Please replace the value <ID_WALLET_ADDRESS>
to the actual one in the url.
perPageItemNum
query param is for setting how many NFT objects per page. Default value is 10
.
pageNum
query param starts from 1
, for listing the NFT objects of the n-th page. Default value is 1
.
order
query param is for controlling sort order based on created_at
of the NFTs, it can be desc
or asc
, default value is asc
.
Please check the response body json in Mint NFT by Organization Account for the schema of the NFT object.
GET
/nft/held_by_id_wallet/<ID_WALLET_ADDRESS>?perPageItemNum=10&pageNum=1&order=asc
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}], // the Array of NFT object. For each NFT object, please refer to the response of mint nft
"error": null
}
Only the NFTs visible by the requester (http client) will be returned.
List NFTs minted by Organization Account (Minter)
Only the minter (organization account) can perform this action.
perPageItemNum
query param is for setting how many NFT objects per page.
pageNum
query param starts from 1
, for listing the NFT objects of the n-th page.
order
query param is for controlling sort order based on created_at
of the NFTs, it can be desc
or asc
, default value is asc
.
Please check the response body json in Mint NFT by Organization Account for the schema of the NFT object.
GET
/nft/minted_by_me?perPageItemNum=10&pageNum=1&order=asc
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}], // the Array of NFT object. For each NFT object, please refer to the response of mint nft
"error": null
}
Toggle NFT visibility
Only the holder (end-user account) and the minter (organization account) can perform this action.
Please replace <token_id>
section in the url with the real value (a hex string, e.g. 0xabcdef123123123123...
).
PUT
/nft/<token_id>/visibility
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Request Body JSON Sample (
Content-Type: application/json
)
{
"to": "public" // or "private"
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": "public", // or "private"
"error": null
}
Search Public NFTs by field-matching search
This can only find public NFTs.
perPageItemNum
query param is for setting how many NFT objects per page.
pageNum
query param starts from 1
, for listing the NFT objects of the n-th page.
order
query param is for controlling sort order based on created_at
of the NFTs, it can be desc
or asc
, default value is asc
.
Please check the response body json in Mint NFT by Organization Account for the schema of the NFT object.
POST
/nft/search?perPageItemNum=10&pageNum=1&order=asc
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Request Body JSON Sample (
Content-Type: application/json
)
// each field can be set to undefined for ignoring the field matching
{
"issuer": "string match value",
"contents_provider": "string match value",
"name": "string match value",
"description": "string match value",
"category": "string match value",
"program_name": "string match value",
"organization": "string match value",
"brand": "string match value",
"competency": "string match value",
"credential_category": "string match value",
"level": "string match value",
"status": "string match value",
"gtin": "string match value",
"gtin12": "string match value",
"gtin13": "string match value",
"gtin14": "string match value",
"gtin8": "string match value",
"has_adult_consideration": "string match value",
"rating": "string match value",
"keywords": "string match value"
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}], // the Array of NFT object. For each NFT object, please refer to the response of mint nft
"error": null
}
Search NFTs minted by me (Organization Account) by field-matching-search
POST
/nft/minted_by_me/search?perPageItemNum=10&pageNum=1&order=asc
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Please refer to the previous one for the request/response body format.
Generate QR Code for NFT verification by the holder (NFT Verification Step 1)
Only the holder (end-user account) can perform this action.
Please replace <token_id>
section in the url with the real value (a hex string, e.g. 0xabcdef123123123123...
).
POST
/nft/<token_id>/verification/qr_code/step1
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
The holder only needs to post the current gps location of its device to the web3connect api.
The QR Code in the result is base64 encoded image.
The QR Code will be only available for next 5 minutes, the scanner must scan this QR Code ASAP.
Request Body JSON Sample (
Content-Type: application/json
)
{
// this should be the current location of the holder
"gps": {
"latitude": "26.583193",
"longitude": "128.053881"
}
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"code": "1234567890",
"qr_code_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAgAAAQICAYAAACAmekaAAAAAXNSR0IArs4c6QAAIABJREFUeF7snUGW3TgOBF33P7TnTXvtLz5nRQFJxaxFKBlIgBT8u+br9+/fv3/5PwlIQAISkIAEJCABCUhAAhKQgAReTeDLAcGr8+/mJSABCUhAAhKQgAQkIAEJSEAC/xFwQKARJCABCUhAAhKQgAQkIAEJSEACEnBAoAckIAEJSEACEpCABCQgAQlIQAIS8BcEekACEpCABCQgAQlIQAISkIAEJCAB/xMDPSABCUhAAhKQgAQkIAEJSEACEpDA/wn4Nwj0gQQkIAEJSEACEpCABCQgAQlIQAIOCPSABCQgAQlIQAISkIAEJCABCUhAAv6CQA9IQAISkIAEJCABCUhAAhKQgAQk4H9ioAckIAEJSEACEpCABCQgAQlIQAIS+D8B/waBPpCABCQgAQlIQAISkIAEJCABCUjAAYEekIAEJCABCUhAAhKQgAQkIAEJSMBfEOgBCUhAAhKQgAQkIAEJSEACEpCABPxPDPSABCQgAQlIQAISkIAEJCABCUhAAv8n4N8g0AcSkIAEJCABCUhAAhKQgAQkIAEJOCDQAxKQgAQkIAEJSEACEpCABCQgAQn4CwI9IAEJSEACEpCABCQgAQlIQAISkID/iYEekIAEJCABCUhAAhKQgAQkIAEJSOD/BPwbBPpAAhKQgAQkIAEJSEACEpCABCQgAQcEekACEpCABCQgAQlIQAISkIAEJCABf0GgByQgAQlIQAISkIAEJCABCUhAAhLwPzHQAxKQgAQkIAEJSEACEpCABCQgAQn8n4B/g0AfSEACEpCABCQgAQlIQAISkIAEJOCAQA9IQAISkIAEJCABCUhAAhKQgAQk8AO/IPj6+pKzBNYS+P3791ptJ8Lo+mrnc8IweYbmn2g7WdueX5o/zUf9Jy71mb8RoP3ZTp6ur3Y..."
},
"error": null
}
The content of the QR Code is a JSON String
{
"c":"1UV7xBEH6hLWec5s5VzT6MBNrPBaTJJA",
"m":{},
"p":"nft_verification_code",
"v":"0"
}
Verify QR Code for NFT verification by the scanner (NFT Verification Step 2)
The scanner scanned the qrcode.
The query param CODE
is exactly from the qrcode image, the decoded content of the qrcode image is this CODE
.
And the requester (scanner) must add location information into the request body
POST
/nft/verification/qr_code/step2?c=<CODE>
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Request Body JSON Sample (
Content-Type: application/json
)
// this should be the current location of the scanner
{
"gps": {
"latitude": "26.583193",
"longitude": "128.053881"
}
}
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"token_id": "<VERIFIED_NFT_TOKEN_ID>"
}
"error": null
}
Poll NFT Verification result
Put the code
from the response of step1 into the query param
GET
/nft/verification/qr_code/result?c=<CODE>
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"token_id": "<VERIFIED_NFT_TOKEN_ID>" // null if not verified yet
}
"error": null
}
Check NFT related transactions history
GET
/nft/:token_id/history
- Authorization Header required (
Authorization: Bearer <ACCESS_TOKEN>
)
Response Body JSON Sample (
Content-Type: application/json
)
{
"status": "ok",
"result": {
"token_id": "0xf27cb07069a1de3da2f539f79ef7d2d080ecc8e3b7440bed6b975963786d0b5f",
"transactions": [
{
"network": 7,
"trackId": "2023-09-18T22:53:19.065Z:o1eDTXGPYJdC9jby",
"transactionId": "1033784-2",
"blockNumber": "1033784",
"explorerUrl": "https://explorer.testnet.thxnet.org/lmt/extrinsic/1033784-2",
"panelUrl": "https://panel.testnet.thxnet.org/?rpc=wss%3A%2F%2Fnode.lmt.testnet.thxnet.org%2Farchive-001%2Fws#/explorer/query/1033784"
},
{
"network": 7,
"trackId": "2023-09-18T23:36:58.364Z:V6UJMYYNrerdquUr",
"transactionId": "1034001-2",
"blockNumber": "1034001",
"explorerUrl": "https://explorer.testnet.thxnet.org/lmt/extrinsic/1034001-2",
"panelUrl": "https://panel.testnet.thxnet.org/?rpc=wss%3A%2F%2Fnode.lmt.testnet.thxnet.org%2Farchive-001%2Fws#/explorer/query/1034001"
}
],
"mint": {
"network": 7,
"trackId": "2023-09-18T22:53:19.065Z:o1eDTXGPYJdC9jby",
"transactionId": "1033784-2",
"blockNumber": "1033784",
"explorerUrl": "https://explorer.testnet.thxnet.org/lmt/extrinsic/1033784-2",
"panelUrl": "https://panel.testnet.thxnet.org/?rpc=wss%3A%2F%2Fnode.lmt.testnet.thxnet.org%2Farchive-001%2Fws#/explorer/query/1033784"
},
"transfers": [
{
"network": 7,
"trackId": "2023-09-18T23:36:58.364Z:V6UJMYYNrerdquUr",
"transactionId": "1034001-2",
"blockNumber": "1034001",
"explorerUrl": "https://explorer.testnet.thxnet.org/lmt/extrinsic/1034001-2",
"panelUrl": "https://panel.testnet.thxnet.org/?rpc=wss%3A%2F%2Fnode.lmt.testnet.thxnet.org%2Farchive-001%2Fws#/explorer/query/1034001"
}
],
"burn": null
},
"error": null
}
OpenID Connect (OIDC)
Please obtain your client_id
(your organization account's id
) from Web3Connect beforehand.
Also, please register your redirect_uri
(s) with Web3Connect beforehand, otherwise the OIDC Provider will deny the Authorization Request.
OIDC Configuration
https://oidc.web3connect.jp/.well-known/openid-configuration
Auth Endpoint
https://oidc.web3connect.jp/oauth2/auth
Preparation
- Pick a standard OIDC or OAuth Client implementation as the framework or library.
- Choose Hybrid Flow or Implicit Flow based on the scenario.
Hybrid Flow (Obtaining Authorization Code and ID Token) Step 1
- Make sure at the
redirect_uri
, there is a proper HTTP Server can handle theresponse_mode
ofform_post
, where a POST HTTP request (x-www-form-urlencoded
) is made to theredirect_uri
when the Authorization Request finishes. state
andnonce
should be generated randomly and properly in OIDC Client side.- Using PKCE and S-256(SHA-256) is a must for Code Challenge, please check
code_challenge_method
andcode_challenge
in the query params. These should be generated by the OIDC Client library or framework. scope
must beopenid profile
oropenid profile email
- Please note that the
email
returned inid_token
or/userinfo
should not be used as a unique key of the end-user, sinceemail
can be changed by the end-user anytime, please usesub
orid_wallet_address
as the unique key
- Please note that the
response_type
must becode id_token
response_mode
can beform_post
orfragment
,form_post
is recommended for Hybrid Flow.
Please memorize the value of the Code Verifier while generating the code challenge, it will be used in next steps.
To start a Hybrid Flow
https://oidc.web3connect.jp/oauth2/auth
?client_id=<Your Organization Account ID>
&redirect_uri=<The Redirect URI>
&scope=openid profile email
&response_type=code id_token
&response_mode=form_post
&code_challenge_method=S256
&code_challenge=Nn9K_hdiApoT5lZ57NJ3JTrxIUmYiBW2Jm9v2RMGgdw
&state=6oys34lajmw
&nonce=lmqks95eaz
Response (Form Body) to the
redirect_uri
code=WcvHHQQRHJ8dfWaxNMHednOxwvrsP6uh97Q8BJq9dER
id_token=eyJhbGciOiJFUzI1NksiLCJ0eXAi.....FvCwaqwMvw
state=6oys34lajmw
The
id_token
in the response already contains thesub
of the end-user, which is theid_wallet_address
of the end-user.
Hybrid Flow Step 2 : Obtain Access Token with Authorization Code
POST
https://oidc.web3connect.jp/oauth2/token
Content-Type: application/x-www-form-urlencoded
Request
curl --request POST \
--url https://oidc.web3connect.jp/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data code='<The Authorization Code from previous step>' \
--data redirect_uri='<The Redirect URI>' \
--data code_verifier='<The Code Verifier used in the previous step>' \
--data client_id='<Your Organization Account ID>'
Response Body JSON Sample (
Content-Type: application/json
)
{
"access_token": "_7kmwbZI.....vSR",
"expires_in": 3600,
"id_token": "eyJhbGciOiJFUz.....mAf8Vs5vgzg",
"scope": "openid profile email",
"token_type": "Bearer"
}
Please use the value of
access_token
for the next step.
Hybrid Flow Step 3 : Obtain End-user's Claim with Access Token
GET
https://oidc.web3connect.jp/userinfo
Authorization: Bearer <The Access Token obtained from the previous step>
Request
curl --request GET \
--url https://oidc.web3connect.jp/userinfo \
--header 'Authorization: Bearer _7kmwbZI.....vSR'
Response Body JSON Sample (
Content-Type: application/json
)
{
"sub": "0x7c7e0922c583c1764b6d52255d58066af7cb3cfe",
"id_wallet_address": "0x7c7e0922c583c1764b6d52255d58066af7cb3cfe",
"email": "...."
}
Step 2 ~ Step 3 are unnecessary if the ID Token in Step 1 is enough for the scenario.
Implicit Flow (Obtaining ID Token directly)
state
andnonce
should be generated randomly and properly in OIDC Client side.scope
must beopenid profile
oropenid profile email
- Please note that the
email
returned inid_token
or/userinfo
should not be used as a unique key of the end-user, sinceemail
can be changed by the end-user anytime, please usesub
orid_wallet_address
as the unique key
- Please note that the
response_type
must beid_token
response_mode
can beform_post
orfragment
,fragment
is recommended for Implicit Flow.
Please remember to make a proper handler at redirect_uri
if response_mode
is set to form_post
, the HTTP request being made to the redirect_uri
is same as in Hybrid Flow, basically a form body (x-www-form-urlencoded
).
To start an Implicit Flow
https://oidc.web3connect.jp/oauth2/auth
?client_id=<Your Organization Account ID>
&redirect_uri=<The Redirect URI>
&scope=openid profile email
&response_type=id_token
&response_mode=fragment
&state=h57c17pw8b6
&nonce=a2k8m15590n
Response in the fragment (
#id_token=....
) (window.location.hash
) atredirect_uri
id_token=eyJhbGci...nmhg state=h57c17pw8b6
ID Token in the Implicit Flow will contain
id_wallet_address
directly, after decoding the payload will look like:
{
"sub": "0x7c7e0922c583c1764b6d52255d58066af7cb3cfe",
"id_wallet_address": "0x7c7e0922c583c1764b6d52255d58066af7cb3cfe",
"email": "....",
"nonce": "a2k8m15590n",
"s_hash": "MTr5Del-UwmhaC6vVp6rQQ",
"aud": "75a6....13",
"exp": 1666185426,
"iat": 1666181826,
"iss": "https://oidc.web3connect.jp"
}
Errors
WIP