Skip to main content

Using the Profiles Endpoint for Social Interoperation

The Profiles endpoint is a powerful tool for developers looking to create a seamless onboarding experience. By leveraging this endpoint, you can retrieve all profiles associated with a user's wallet address across the Tapestry ecosystem, allowing for quick and easy profile setup in your app. You can use either the socialfi package (recommended for easier integration) or call the API directly.

How It Works

When a new user connects their wallet to your app, you can use this endpoint to:

  1. Fetch all profiles owned by the user's wallet address
  2. Display these profiles to the user
  3. Allow the user to import data from an existing profile

This process significantly reduces friction in the onboarding flow, as users can quickly set up their profile using information they've already provided elsewhere in the Tapestry ecosystem.

We recommend using the socialfi package as it provides a simpler interface for API interactions:

npm install socialfi
import { SocialFi } from 'socialfi';

const API_URL = 'https://api.usetapestry.dev/v1/'; // tapestry prod URL
// const API_URL = 'https://api.dev.usetapestry.dev/v1/'; // tapestry dev URL

const API_KEY = process.env.TAPESTRY_API_KEY; // Get your API key from https://app.usetapestry.dev/

const client = new SocialFi({
baseURL: API_URL,
apiKey: API_KEY,
});

Using the Endpoint

To fetch external profiles, use the profiles search functionality with the shouldIncludeExternalProfiles parameter set to true:

Using the Socialfi Package

try {
const profiles = await client.profiles.searchProfiles(
{
apiKey: API_KEY,
},
{
walletAddress: 'wallet_address_here',
shouldIncludeExternalProfiles: true,
limit: 50,
offset: 0
}
);
console.log('User profiles across Tapestry:', profiles);
} catch (error) {
console.error('Error fetching profiles:', error);
}

Using the API Directly

try {
const response = await fetch('https://api.usetapestry.dev/v1/profiles/search?apiKey=YOUR_API_KEY&shouldIncludeExternalProfiles=true', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
walletAddress: 'wallet_address_here',
limit: 50,
offset: 0
}),
});

const profiles = await response.json();
console.log('User profiles across Tapestry:', profiles);
} catch (error) {
console.error('Error fetching profiles:', error);
}

This endpoint returns an array of Profile objects representing the profiles owned by the specified wallet address.

Request Parameters

ParameterTypeDescription
walletAddressstringThe wallet address to find associated profiles for
apiKeystringYour Tapestry API key
shouldIncludeExternalProfilesbooleanWhether to include profiles from Tapestry apps outside your namespace
limitnumberMaximum number of profiles to return (optional)
offsetnumberNumber of profiles to skip (optional)

Response

The endpoint returns an array of profile objects. Each object contains details about a profile associated with the provided wallet address:

{
"profiles": [
{
"id": "profile-123",
"username": "cryptoenthusiast",
"walletAddress": "WALLET_ADDRESS_HERE",
"blockchain": "SOLANA",
"namespace": "CryptoApp",
"customProperties": {
"bio": "Blockchain developer and NFT collector",
"profileImage": "https://example.com/profile.jpg",
"location": "San Francisco, CA",
"website": "https://cryptodev.example.com"
},
"socialCounts": {
"followers": 1250,
"following": 890,
"posts": 156,
"likes": 3420
},
"createdAt": "2024-01-10T08:30:00Z",
"updatedAt": "2024-01-15T14:22:00Z"
},
{
"id": "profile-456",
"username": "nftlover",
"walletAddress": "WALLET_ADDRESS_HERE",
"blockchain": "SOLANA",
"namespace": "NFTMarketplace",
"customProperties": {
"bio": "Digital art aficionado",
"profileImage": "https://example.com/avatar.png",
"interests": "digital art, NFTs, creativity"
},
"socialCounts": {
"followers": 567,
"following": 234,
"posts": 89,
"likes": 1230
},
"createdAt": "2024-01-05T12:15:00Z",
"updatedAt": "2024-01-14T09:45:00Z"
}
],
"pagination": {
"total": 2,
"limit": 50,
"offset": 0,
"hasMore": false
}
}

Implementing in Your Onboarding Flow

Here's a step-by-step guide to implement this in your onboarding process:

  1. After the user connects their wallet, call the Find All Profiles endpoint.
  2. If profiles are found, present them to the user with an option to import data.
  3. If the user selects a profile, use its data to pre-fill your profile creation form.
  4. Allow the user to review and modify the imported data before finalizing their profile.

Here's a complete example of how this might look in code using the socialfi package:

async function onboardUser(walletAddress: string) {
try {
// Fetch profiles associated with the wallet
const profilesResponse = await client.profiles.searchProfiles(
{
apiKey: API_KEY,
},
{
walletAddress: walletAddress,
shouldIncludeExternalProfiles: true,
limit: 10
}
);

const profiles = profilesResponse.profiles;

if (profiles.length > 0) {
// Display profiles to user and let them choose
const selectedProfile = await displayProfileChoices(profiles);

if (selectedProfile) {
// Pre-fill form with selected profile data
const importedData = {
username: selectedProfile.username,
bio: selectedProfile.customProperties.bio || '',
profileImage: selectedProfile.customProperties.profileImage || '',
location: selectedProfile.customProperties.location || '',
website: selectedProfile.customProperties.website || ''
};

await prefillProfileForm(importedData);

// Optionally, create a new profile in your namespace with imported data
const newProfile = await client.profiles.findOrCreateCreate(
{
apiKey: API_KEY,
},
{
walletAddress: walletAddress,
username: importedData.username,
bio: importedData.bio,
blockchain: 'SOLANA',
customProperties: [
{
key: 'profileImage',
value: importedData.profileImage
},
{
key: 'location',
value: importedData.location
},
{
key: 'website',
value: importedData.website
},
{
key: 'importedFrom',
value: selectedProfile.namespace
}
]
}
);

console.log('Profile created with imported data:', newProfile);
}
} else {
// No existing profiles found, proceed with fresh onboarding
console.log('No existing profiles found, starting fresh onboarding');
}

// Continue with your regular onboarding flow
// ...
} catch (error) {
console.error('Error during onboarding:', error);
// Fallback to regular onboarding
}
}

// Helper function to display profile choices to the user
async function displayProfileChoices(profiles: any[]): Promise<any | null> {
// Implementation depends on your UI framework
// This could be a modal, dropdown, or list component
// Return the selected profile or null if user chooses to start fresh
return profiles[0]; // Simplified example
}

// Helper function to pre-fill the profile form
async function prefillProfileForm(data: any): Promise<void> {
// Implementation depends on your UI framework
// Fill form fields with the imported data
console.log('Pre-filling form with:', data);
}

Advanced Usage

Filtering Profiles by Namespace

You can also filter profiles by specific namespaces if you want to only show profiles from certain apps:

Using the Socialfi Package

try {
const profiles = await client.profiles.searchProfiles(
{
apiKey: API_KEY,
},
{
walletAddress: 'wallet_address_here',
namespace: 'SpecificApp', // Only profiles from SpecificApp
shouldIncludeExternalProfiles: true
}
);
} catch (error) {
console.error('Error fetching filtered profiles:', error);
}

Using the API Directly

try {
const response = await fetch('https://api.usetapestry.dev/v1/profiles/search?apiKey=YOUR_API_KEY&shouldIncludeExternalProfiles=true', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
walletAddress: 'wallet_address_here',
namespace: 'SpecificApp'
}),
});

const profiles = await response.json();
} catch (error) {
console.error('Error fetching filtered profiles:', error);
}

Identity Resolution

The socialfi package also provides identity resolution capabilities to find profiles across different identifiers:

try {
const resolvedProfiles = await client.identity.resolveIdentity(
{
apiKey: API_KEY,
},
{
identifier: 'wallet_address_here',
identifierType: 'walletAddress'
}
);
console.log('Resolved identity profiles:', resolvedProfiles);
} catch (error) {
console.error('Error resolving identity:', error);
}

Benefits

By implementing this feature, you can:

  • Reduce user friction during onboarding
  • Increase the likelihood of completed profiles
  • Provide a seamless experience for users already part of the Tapestry ecosystem
  • Encourage data portability and user ownership across different applications
  • Improve user retention by leveraging existing social connections

Best Practices

  • Handle edge cases: Always provide a fallback for users who don't have existing profiles
  • Respect user choice: Give users the option to start fresh even if profiles are found
  • Validate imported data: Ensure imported data meets your app's requirements
  • Update regularly: Periodically check for new profiles associated with the user's wallet
  • Privacy considerations: Respect user privacy and only import data they consent to share
  • Error handling: Implement robust error handling for network issues or API failures

Next Steps

Now that you understand how to use the Profiles endpoint to fetch external profiles, consider integrating it into your onboarding flow. This will not only improve the user experience but also demonstrate your app's integration with the broader Tapestry ecosystem.

Remember to handle cases where a user might not have any existing profiles, and always give users the option to create a new profile from scratch if they prefer.