Sardine’s NFT checkout widget offers a quick way to integrate the ability to directly purchase NFTs from fiat through a URL.
This is best suited for quick integrations where the developer does not want to build their own UI. The Sardine Risk SDK is natively integrated into the checkout form.
Example URL
Goal
By the end of this guide, you should be able to open a new window with Sardine NFT Checkout, either in a new tab or in a new browser window.
Implementing NFT Checkout
Before we start, you’ll need the following parameters
{
"title": "Authorization Parameters",
"type": "object",
"properties": {
"clientId": {
"type": "string",
"description": "A unique Client Identifier issued by Sardine for an integration. This is safe to be exposed to the public internet. This is needed for client side JS"
},
"clientSecret": {
"type": "number",
"description": "The Secret Key is associated with a specific Client ID. It must be kept secret."
},
},
"required": ["clientId", "clientSecret"]
}
1. Obtain authorization token
The next step is to obtain the clientToken
, which is a unique identifier for each session and user.
Make a POST request to /v1/auth/client-tokens
using Basic Auth by passing base64 encoding of <clientId>:<clientSecret>
The body of this request is used to send information about the NFT and the user to Sardine. More information about this endpoint can be found here
{
"title": "clientToken Request",
"type": "object",
"properties": {
"customerId": {
"type": "string",
"description": "ID of Customer that can be passed, in lieu of Sardine creating one"
},
"referenceId": {
"type": "string",
"description": "Unique ID that should be passed to refer to this transaction. Status of this transaction will be fetched using this field as the key"
},
"expiresIn" : {
"type" : "string",
"description" : "Time in seconds until the NFT will expire"
},
"nft" : {
"type" : "object",
"description": "Metadata about NFT that needs to be passed",
"properties": {
"name": {
"type" : "string",
"description" : "Name of the NFT"
},
"collection": {
"type" : "string",
"description" : "Collection the NFT belongs to"
},
"price" : {
"type" : "number",
"description" : "Cost of the NFT in `currencyCode`"
},
"currencyCode" : {
"type" : "string",
"description" : "Fiat currency payment happens in",
"example" : "usd"
},
"imageUrl" : {
"type" : "string",
"description" : "Url which is hosting the image of the NFT. This the string must be URL encoded".
},
},
"required" : ["name","price","currencyCode","imageUrl","expiration"]
},
"taxRates": {
"type": "object",
"description": "Which contains rates for countries/regions in ISO3166-2 format.",
"properties": {
"US": {
"type": "string",
"description": "Countrycode like US. It's percentage, US: 10 means 10% tax for all US",
"example": "US = 10"
},
"US-NY": {
"type": "string",
"description": "countrycode-subdivisions like US-NY. \"US-NY\": 13 means 13% for NY state.",
"example": "US-NY = 13"
},
"US-CA": {
"type": "string",
"example": "US-CA = 20",
"description": "countrycode-subdivisions like US-CA. \"US-CA\": 20 means 20% for CA state."
}
}
},
"identityPrefill" : {
"type" : "object",
"description" : "User information that can be prefilled into the Checkout UI",
"properties" : {
"firstName" : {
"type" : "string",
"description" : "First name of buyer"
},
"lastName" : {
"type" : "string",
"description" : "Last name of buyer"
},
"dateOfBirth" : {
"type" : "string",
"description" : "Date of Birth of buyer in YYYY-MM-DD format"
},
"emailAddress" : {
"type" : "string",
"description" : "Verified email address of buyer"
},
"phone" : {
"type" : "string",
"description" : "Verified phone number of buyer"
},
"address" : {
"type" : "object",
"properties" : {
"street1" : {
"type" : "string",
"description" : "Street address"
},
"street2" : {
"type" : "string",
"description" : "Suite, Apartment number etc"
},
"city" : {
"type" : "string",
"description" : "City in address"
},
"regionCode" : {
"type" : "string",
"description" : "2 letter state code"
},
"postalCode" : {
"type" : "string",
"description" : "Zip code or equivalent"
},
"countryCode" : {
"type" : "string",
"description" : "2 letter ISO country code"
}
}
}
}
}
},
"required": ["referenceId"]
}
A sample request would look like below
{
"method": "POST",
"url": "https://api.sandbox.sardine.ai/v1/auth/client-tokens",
"headers" : {
"Authorization" : "Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0",
},
"body" : {
"referenceId": "42eadcb0-4a93-45af-9c8c-d295db5aeb6c",
"customerId": "adf02ae2-f633-11ec-b939-0242ac120002",
"expiresIn" : 600,
"nft": {
"name": "NFT #1",
"price": 100,
"currencyCode": "USD",
"contractAddress": "0x7fC0344254E1663C2eF24e3c063cbec231525C20",
"imageUrl": "https://gateway.nftcompany.io/ipfsQmSAQm4gbhjSeUk7fuYppHd7Z8dfWpBvnFmqFSKqkrUJPM",
"network" : "ethereum"
},
"identityPrefill": {
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "2000-01-01",
"emailAddress": "foobar@gmail.com",
"phone": "+19254485826",
"address": {
"street1": "123 Main st",
"street2": "",
"city": "irvine",
"regionCode": "CA",
"postalCode": "02747",
"countryCode": "US"
}
}
}
}
If the request is successful, you should receive a response that contains the clientToken
, which is needed to create the Checkout
Use your base64 encode( clientId:clientSecret ) to make a call
Constraints
- referenceId - unique
- expiresIn - 300 to 3600 ( 5min - 1hr)
Success Response:
{
"clientToken": "<client_token>",
"expiresAt": "2022-07-07T21:32:29Z"
}
**Error Response:**
{
"message": "Duplicate referenceId",
"code": "INVALID_PARAMS"
}
A fully complete URL will look like this:
Additionally, address
can be passed which is the receiving wallet address of the user
2. Understand Post transaction events
Sardine will emit events which can be handled to understand user action
expired
- The user didn’t complete the transaction within the expiration
parameter
{
"status" : "expired",
"data" : {
"referenceId" : "42eadcb0-4a93-45af-9c8c-d295db5aeb6c"
}
}
processed
- The payment is complete, and the NFT can now be transferred the user.
{
"status" : "processed",
"data" : {
"price": 100,
"orderId": "123e4567-e89b-12d3-a456-426614174001",
"transactionFee": 2,
"networkfee": "0.35"
"currencyCode": "usd",
"paymentMethod": "ACH",
"createdAt": 12312321312,
"contractAddress": "0x10b195F7Be9B120efd05C58f16650A13f533eA33",
"referenceId" : "42eadcb0-4a93-45af-9c8c-d295db5aeb6c"
}
}
declined
- The transaction was declined due to issues with their payment method or risk profile.
{
"status" : "declined",
"data" : {
"referenceId" : "42eadcb0-4a93-45af-9c8c-d295db5aeb6c"
}
}
3. Embed NFT checkout
Once the checkout URL has been generated, it can be embedded into your web app as an iframe, with event handlers to catch events sent by the iframe.
Sample code to embed NFT checkout
Recommended size is width=500, height=700 for new window
<head>
<script>
/*
The widget and begins its flow after this line,
and will update the parent about its state via postMessage events.
*/
function attachListener() {
document.addEventListener("message", (data) => console.log("Event is", data)) }
</script>
</head>
<body>
<div class="center">
<iframe src="https://crypto.sandbox.sardine.ai/?address=0x10b195F7Be9B120efd05C58f16650A13f533eA33&clientToken=123-asd-456&show_features=true" onload="attachListener()" id="sardine_iframe" />
</div>
</body>
Recommended size is width=500, height=700 for new window
<head>
<script>
/*
The widget and begins its flow after this line,
and will update the parent about its state via postMessage events.
*/
function attachListener() {
document.addEventListener("message", (data) => console.log("Event is", data)) }
</script>
</head>
<body>
<div class="center">
<iframe src="https://crypto.sandbox.sardine.ai/?address=0x10b195F7Be9B120efd05C58f16650A13f533eA33&clientToken=123-asd-456&show_features=true" onload="attachListener()" id="sardine_iframe" />
</div>
</body>
import { useRef, useEffect, useCallback } from 'react'
SardineIframe = ({ eventHandler }) => {
const iframeRef = useRef(null)
const postMessageListener = useCallback((event) => {
if(event.source !== iframeRef?.current?.contentWindow) {
return;
}
eventHandler(event.data)
})
useEffect(() => {
window.addEventListener('message', postMessageListener)
return () => {
window.removeEventListener('message', postMessageListener)
}
},
[iframeRef])
return <iframe src="https://crypto.sandbox.sardine.ai" ref={iframeRef}/>
}
4. Get Confirmation of Trade Status
After the purchase has been completed, the referenceId
or the clientToken
can be used to fetch information about the respective transaction by calling the Orders endpoint
The order can have one of these statuses
draft
- This is an open or ongoing order
processed
- The payment has been completed.
expired
- The user didn’t complete the transaction within the expiration
time
declined
- The transacation was declined, due to payment method issues
complete
- The payment is complete and the NFT has been delivered to the user
cancelled
- The order is cancelled
{
"method": "GET",
"url": "https://api.sandbox.sardine.ai/v1/orders",
"query" : {
"referenceId" : "7ce511d0-c973-4744-b819-d933a248ae51"
},
"headers" : {
"Authorization" : "Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0",
}
}
Once the status changes to completed, the NFT has been transferred
5 . Testing and Verification
Once the defined URL has been set and triggered, it should open an iframe that goes through the user flows for Sardine’s NFT checkout. This should match the screen show on the [User Flows Page]
You should now be able to route users to the Sardine Checkout Widget via your defined URL where they can instantly buy NFTs!