### Create a Profile on Your Graph

The first step in most apps on Tapestry is creating composable user identities. This is achieved through profile creation and the [findOrCreate endpoint](https://docs.usetapestry.dev/api).

Each profile on Tapestry is namespaced to a specific app.

We recommend passing in at minimum a `username` and a `walletAddress` in your findOrCreate request. This will create a user profile on your graph and connect it to the user's wallet. The connection between the wallet and profile enables the interoperation of profiles across different apps on Tapestry. Without a wallet address, you will be unable to access features that surface suggested social connections or speed up onboarding through profile imports.

For additional granularity, you can also pass in an `id` parameter (for example, a uuid). If you do not specify an `id`, the API will automatically set the `id` to the same value as the `username`.

##### Other Parameters

`blockchain` refers to the chain the public key is on. If you leave it blank, it will be set to Solana.

`execution` refers to the methodology with which the onchain transaction will be processed. The default execution method is `FAST_UNCONFIRMED`.

- `FAST_UNCONFIRMED` performs the write and returns a 200 before the onchain transaction has landed, while optimistically trying to land the onchain transaction in the background. This is the fastest roundtrip, with average times of under 1s.
- `QUICK_SIGNATURE` returns a transaction signature for the onchain transaction, but does not attempt to confirm it. This option is best if you want to use your own confirmation logic.
- `CONFIRMED_AND_PARSED` waits for the onchain transaction to be sent and confirmed before returning a 200. This is the slowest execution method, with roundtrip times for 200 responses averaging 15s.

## Using the Socialfi Package (Recommended)

We recommend using the socialfi package as it provides a simpler, more convenient way to interact with Tapestry. However, you can also call the API directly if you prefer more control.

First, install and initialize the socialfi package:

```bash
npm install socialfi
```

```ts
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,
});

// Create a profile
try {
  const profile = await client.profiles.findOrCreateCreate(
    {
      apiKey: API_KEY,
    },
    {
      walletAddress: 'WALLET_ADDRESS_HERE',
      username: 'username_here',
      id: 'arbitrary_uuid_or_leave_blank',
      bio: 'User bio here',
      blockchain: 'SOLANA',
      execution: 'FAST_UNCONFIRMED',
      customProperties: [
        {
          key: 'profileImage',
          value: 'https://example.com/image.jpg'
        },
        {
          key: 'location',
          value: 'San Francisco, CA'
        }
      ]
    }
  );
  console.log('Profile created:', profile);
} catch (error) {
  console.error('Error creating profile:', error);
}
```

## Using the API Directly

If you prefer to call the API directly without the socialfi package, you can use fetch:

```ts
try {
  const response = await fetch(
    'https://api.usetapestry.dev/v1/profiles/findOrCreate?apiKey=YOUR_API_KEY',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        walletAddress: 'WALLET_ADDRESS_HERE',
        username: 'username_here',
        id: 'arbitrary_uuid_or_leave_blank',
        bio: 'User bio here',
        blockchain: 'SOLANA',
        execution: 'FAST_UNCONFIRMED',
        customProperties: [
          {
            key: 'profileImage',
            value: 'https://example.com/image.jpg'
          },
          {
            key: 'location',
            value: 'San Francisco, CA'
          }
        ]
      }),
    }
  );

const profile = await response.json();
  console.log('Profile created:', profile);
} catch (error) {
  console.error('Error creating profile:', error);
}
```

If you want to store additional information, you can pass in any data as JSON key-value pairs in the `customProperties` field.

Once the code executes, you can check the status in the visualizer at [https://app.usetapestry.dev/visualize](https://app.usetapestry.dev/visualize) or with a GET request to the profile endpoint.

### Read Profile

To read this information back, use the following. Put the profile's `id` in the GET request:

#### Using Socialfi Package

```ts
try {
  const profile = await client.profiles.getProfile(
    {
      apiKey: API_KEY,
      profileId: 'USER_PROFILE_ID_HERE'
    }
  );
  console.log('Profile data:', profile);
} catch (error) {
  console.error('Error fetching profile:', error);
}
```

#### Using the API Directly

```ts
try {
  const response = await fetch(
    'https://api.usetapestry.dev/v1/profiles/USER_PROFILE_ID_HERE?apiKey=YOUR_API_KEY'
  );
  const profile = await response.json();
  console.log('Profile data:', profile);
} catch (error) {
  console.error('Error fetching profile:', error);
}
```

This will return everything in the profile node you just created. Here's an example response:

```json
{
  "profile": {
    "id": "user_profile",
    "username": "user_profile",
    "bio": "User bio here",
    "walletAddress": "WALLET_ADDRESS_HERE",
    "blockchain": "SOLANA",
    "namespace": "your_namespace",
    "customProperties": {
      "profileImage": "https://example.com/image.jpg",
      "location": "San Francisco, CA"
    },
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-01-15T10:30:00Z"
  },
  "socialCounts": {
    "followers": 0,
    "following": 0,
    "posts": 0,
    "likes": 0
  }
}
```

Try creating a second profile. In the next guide, we'll walk through how to connect them on your graph.
