> For the complete documentation index, see [llms.txt](https://connect.greenruhm.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://connect.greenruhm.com/fundamentals/user-profiles.md).

# User Profiles

To issue a drop, you will need to establish a Greenruhm user profile for the artist. A Greenruhm profile is a digital identity backed by [open Web3 standards](https://eips.ethereum.org/EIPS/eip-1155).

Greenruhm user accounts are owned by Web3 wallets protected by Delegated Key Management: Private keys are stored in the cloud, protected by [Hardware Security Modules](https://en.wikipedia.org/wiki/Hardware_security_module) (HSMs). Wallets are non-custodial, meaning that they are user-owned and user-controlled. When a user needs to sign a message or make a transaction, we delegate the request directly to their cloud-hosted wallet. Think of it like **a safety deposit box in the cloud.** We don't have any access to or control over user wallets, and the user is free to transfer assets in and out of their wallet at any time.

⚠️  **No transaction reversals or refunds are possible.** As with all non-custodial blockchain wallet transactions, Greenruhm has no power to reverse payments, undo NFT transfers, etc. Please be careful to confirm transaction details with users.

🎉  **Friction-free onboarding.** Because Greenruhm does not sell cryptocurrencies or provide custody services, Greenruhm does not need users to go though complicated banking regulated-onboarding practices like Know Your Customer/Anti-Money Laundering identity verifications.

### Sign In

```typescript
connection.signIn(email: String) => Promise(User)
```

To sign in a user, you must first initialize the Greenruhm connect API:

```javascript
import { connect } from '@greenruhm/connect';

const connection = connect({ apiKey: '<your API key here>' });

const getSignedInUser = async (email) => {
  const user = await connection.signIn(email);
  // You can now use user.displayName, user.avatarImage, etc.
  return user;
};
```

\
Call the asynchronous `connection.signIn()` method with the user's email address. Greenruhm Connect will send the user an email containing a button to click.

If the user account exists, they'll be signed in and the promise returned by `connection.signIn()` will be resolved with user details such as their  `email`, `username`, `displayName`, `avatarImage`, and `walletAddress`.

```graphql
type User {
  email: String!
  walletAddress: String!
  # True if user is signed in
  isSignedIn: Boolean! 
  username: String
  displayName: String
  avatarImage: String
  # Used to uniquely identify you for credits and royalties in various systems.
  # Register for free here: https://sound.credit/account/login
  isni: String
  # Your IPI is assigned when you join a Performing Rights Organization (PRO).
  # e.g. BMI, ASCAP, or SESAC
  ipi: String
}
```

If the user does not exist, the `connection.signIn()` promise will reject with an `"Account not found"` error.

### New User Sign Up

```typescript
connection.signUp({
  email: String!,
  username: String!,
  displayName: String, // Optional. Defaults to username.
) => Promise(User) | Promise(Error)
```

If the account does not exist, the `connection.signUp()` method will resolve with the new user account details, including the user's `email` and `walletAddress`.\
\
If an account already exists for the given email, `connection.signUp()` will reject with an error: `"An account already exists for this email."`
