# Product and Features

## Embeddable widget

Want to display referral and reward data to your users on your app, but want to avoid having to invest the front-end work required to do so?

Add our embedded widget as quickly as our SDK to your website and capture referral links/codes, see what rewards they've used and how many folks have clicked their links, completed objectives, and etc.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FoTCn3vDRbaDMQPeZm9dd%2Fimage%20(14).png?alt=media&amp;token=18cfa0f1-11b2-4fcd-ad14-e455ac746fff" alt=""><figcaption></figcaption></figure>

## **Referral Links**

Want something with more sharing power that just a code? Generate referral links with us instead to make driving traffic to your site even more seamless for your users. Yes, we white-label links too!

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F5kpMRUBr037qJlQ3W5Xx%2Fimage%20(20).png?alt=media&amp;token=57104fd5-6c0c-4472-a4f4-70c56835272b" alt=""><figcaption></figcaption></figure>

## On/Off Chain Conversions

Want to payout users in a token of your choice for minting a token, transferring into a staking pool, use of a smart contract, or just simply drive signups on your website or dApp? We've got you covered with a wide variety of integration options via our SDK, Embeddable widget or no code program pages.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FvszeJJHGEPrNohl9JOAA%2Fimage%20(23).png?alt=media&amp;token=a1281b5f-6bc2-4447-ae52-d3849b3c9eea" alt=""><figcaption></figcaption></figure>

## ChainVine SDK

Want more control over your conversion events and metrics? Get integrated in minutes with our simple and intuitive SDK and scale that feature or upstart into mass adoption.&#x20;

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F94fhlkzR4VbF0zf1KN5G%2Fimage.png?alt=media&amp;token=8a03fda8-cdb9-4e07-be0a-b9aff5e20a3e" alt=""><figcaption></figcaption></figure>

Once integrated, we handle the tracking and reporting so you can focus on the fun parts:

* capturing and measuring ChainVine referral link traffic to your app with ease&#x20;
* sending conversion events from custom internal business logic
* generating referral links or codes wherever you want in your app or marketing campaigns
* objective or token gate user experiences
* incorporate referral programs into your third party provider logic

Did we mention we're open to new features and ideas too :point\_right: head over to [our feedback form](https://92dgagzx54m.typeform.com/to/nmMJ1EVj) if you'd like to brainstorm with us!

## Analytics

Monitor performance throughout the referral funnel from clicks all the way to revenue driven by affiliate. Track and export your data in any way you'd like.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FUlk7GDcBoFi0xctHvxnN%2Fimage%20(18).png?alt=media&amp;token=63faf823-38b9-4330-a44a-3e9124720788" alt=""><figcaption></figcaption></figure>

## **Automated rewards payouts**

ChainVine automates all your reward payouts. We spin up a Gnosis Safe (EVM only) on your behalf that we leverage to enable users to harvest their own rewards. Just remember to fill up your safe as your campaign takes off.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FNRLtxPZJqOxWNDh0JggR%2Fimage.png?alt=media&amp;token=c3bb78be-300d-40bf-9080-0295567414c0" alt=""><figcaption></figcaption></figure>

#### Payout in any tokens.

ChainVine lets you pay your community however you'd like. ChainVine lets you create multiple rewards in a single campaign and set token type, static amount or variable rewards! Payout rewards in YOUR token...or any other ERC-20/721 for that matter.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Frl8oxIJ35BX36K5PCo7q%2Fimage.png?alt=media&amp;token=8a9ce45a-e7fd-4c95-bff6-d13d184fe47b" alt=""><figcaption></figcaption></figure>

## **Leaderboard**

Incite friendly competition with ChainVine's leaderboard. You know it, we know it, [@daoex\_app](https://twitter.com/daoex_app) knows it. Everyone loves a leaderboard! Leaderboards ignite that competitive spark in people that get's them motivated to refer more people to your site.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fd2OTKeEZLukAuERVtrjn%2Fimage.png?alt=media&amp;token=06bf3f44-09a7-41d5-b041-45c0996475d2" alt=""><figcaption></figcaption></figure>

## Affiliate gating

Control who can gain access to a referral link by turning on referral gating! You can also whitelist addresses in advance for a friction-free referral flow! Our friends at [@LidoFinance](https://twitter.com/LidoFinance) know how annoying alpha hunters can be.&#x20;

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F5aW8qSsdhLQfTavQAphJ%2Fimage.png?alt=media&amp;token=ca21cdd5-8e5a-41e1-9fc2-0e0282a1e876" alt=""><figcaption></figcaption></figure>


# Technical Overview

The developer documentation is split into 5 separate sections

### [Use Cases](/developers/use-cases)

The best place to start if you're looking to integrate with ChainVine, this section outlines the most common integrations with examples for each.

If the examples don't cover your exact needs please feel free to reach out to us on [Telegram](https://t.me/chainvinehq) where the team will happily answer any questions and help you on your integration journey.

### [Embedded Widget](#embedded-widget)

This section outlines how to integrate the embeddable widget into your web application, allowing your users to engage in your referral program without leaving your site.

Our widget is available at: <https://www.npmjs.com/package/@chainvine/widget>

The widget is customizable to fit multiple form factors and supports light and dark modes - whatever your use case, we've got you covered!

### [SDK](/developers/sdk)

The bread and butter of your integration, the SDK serves as a useful client to simplify interacting with your referral program programmatically.

For ease of use, we've split the SDK into two types of client:

* [ChainvineClient](/developers/sdk/classes-and-functions/chainvineclient): used for program/community level operations, where the actions are not tied to any specific user
* [ChainvineUser](/developers/sdk/classes-and-functions/chainvineuser): used for user level operations, where the actions are directly tied to a specific user

The ChainvineUser class extends ChainvineClient so all general program operations are also available when operating in a user-specific context

Our SDK is available at: <https://www.npmjs.com/package/@chainvine/sdk>

### [Webhooks](#webhooks)

Expose an endpoint for ChainVine to send you updated on user events that occur within ChainVine, we currently support notifications for:

* When users join your program
* When users complete program actions
* When users earn a reward

### [Open API Specification](#open-api-specification)

Should you wish to interact with ChainVine without using the SDK, we do expose a RESTful API which you can interact with directly.


# Use Cases

We've put together a set of common use cases along with examples of each.

The examples leverage our [SDK](/developers/sdk), but all operations are possible using our RESTful API directly as well - see [Open API Specification](/developers/open-api-specification) for more details on this approach.

Note: these use cases don't encapsulate everything that's possible with the ChainVine, but rather highlight the most common customer needs - please refer to the technical documentation to see the full range of possibilities:

* [Embedded Widget](/developers/embedded-widget)
* [SDK](/developers/sdk)
* [Webhooks](/developers/webhooks)
* [Open API Specification](/developers/open-api-specification)


# Leverage cookies

In additional to the ChainvineClient operations, we offer a few global utility methods to assist in keeping track of referrals through the use of cookies.

> Note: these operations rely on browser functionality and will throw an error if used in a non-browser context

### Storing a Referrer

```typescript
import { storeReferrer } from '@chainvine/sdk';

// Fetches the "r" query parameter from the URL (if available)
// and stores it in a CV_REF cookie with an expiration of 120 days
storeReferrer();
```

Should you already have a reference to he referrer's ID or if you would like to adjust the cookies expiration you may do so by providing overrides as below:

```typescript
storeReferrer({
  durationDays: 30, //Override the default cookie duration (120 days)
  referrer: 'ABC123', //Should you already have access to the referrer, and if you do not want it fetched from the URL, you can provide it directly
}); 
```

### Fetching a stored Referrer

Once you've stored the referrer, you can access it at any point in your application like so:

```typescript
import { getReferrer } from '@chainvine/sdk';

const referrer = getReferrer();
```

### Clearing the stored Referrer

The referrer cookie can be cleared at any point using the following operation:

```typescript
import { clearReferrer } from '@chainvine/sdk';

clearReferrer();
```


# Link Claimer/Referrer

For claimers to be referred directly to your website rather than first connecting their wallet on ChainVine, you will need to ensure any valid referral is “linked” upon wallet connection.

### **Pre-requisites**

* Implement the SDK's recommended [Cookie Management](broken://pages/uYJ1fJuBmasYY0uEzdmV) approach

### **Best practices**

* In browser environments, fetch the referrer\_id using the getReferrer() method provided by the SDK
* In server environments, supply the referrer directly

### Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient, getReferrer } from '@chainvine/sdk';

const client = new ChainvineClient();

// referrer captured from url parameter and PREVIOUSLY saved with 
// the storeReferrerId() method

const referrer = getReferrer();

const referred_user_wallet = '0x1234567890';

const campaign = {
  id: 'aSlug123'
}

if (referrer) {
  const user = await client.syncUser(referred_user_wallet)
  const res = await user.referral({campaign}).linkReferrer(referrer);
}
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key <--- IMPORTANT
});

const referrer = 'a user referral code' // <--- provided by your system.

const referred_user_wallet = '0x1234567890';

const campaign = {
  id: 'aSlug123'
}

if (referrer) {
  const user = await client.syncUser(referred_user_wallet)
  const referral = await user.referral({campaign}).linkReferrer(referrer);
}

```

{% endtab %}
{% endtabs %}

### **When you only have the referrer's wallet on hand**

* it is possible to fetch the referrer's ChainVine referreralCode if you only have the referrer's wallet address on hand
* simply call .syncUser with ChainvineClient to retrieve this Identifier from ChainVine

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key <--- IMPORTANT in server-side environments
});

const referred_user_wallet = '0x987654321';

const campaign = {
  id: 'aSlug123'
}

const referrer = await client.syncUser(referred_user_wallet);
const { referralCode } = referrer;

if (referralCode) {
  const user = await client.syncUser(referred_user_wallet)
  const referral = await user.referral({campaign}).linkReferrer(referralCode);
}

```


# Record Link Click

### **Pre-requisites**

* Implement the SDK's recommended [Cookie Management](broken://pages/uYJ1fJuBmasYY0uEzdmV) approach

### **Best practices**

* Fetch the referrer\_id using the [getReferrerId()](broken://pages/uYJ1fJuBmasYY0uEzdmV#fetching-a-stored-referrer-id) method
* be sure to only call this method when appropriate so as to avoid sending false events!

### Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient(); //Make sure to whitelist your domain

await client.recordClick(
    'ABC123', // the referrer from the referral link
    'aSlug123' // Optional, the campaign slug/id to record the click for (if you have multiple active campaigns)
); 
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key
});

await client.recordClick(
    'ABC123', // the referrer from the referral link
    'aSlug123' // Optional, the campaign slug/id to record the click for (if you have multiple active campaigns)
); 
```

{% endtab %}
{% endtabs %}


# Generate a Referrer Link

If you would like to bypass ChainVine and supply referrers with a referral URL directly on your webpage, you can generate a referral URL for a given wallet address using the "url" endpoint.

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

const campaign = {
   id: 'aSlug123'
}

const client = new ChainvineClient(); //Make sure to whitelist your domain

const userClient = await client.syncUser(userWalletAddress);
const userReferral = userClientReferrals.referral({campaign})

const res = await userReferral.url();

console.log(res.url); // > https://yourdomain.xyz/refer?r=99dj2ikmdo2
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

const campaign = {
   id: 'aSlug123'
}

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key
});

const userClient = await client.syncUser(userWalletAddress);

const userReferral = userClientReferrals.referral({campaign})

const res = await userReferral.url();

console.log(res.url); // > https://yourdomain.xyz/refer?r=99dj2ikmdo2
```

{% endtab %}
{% endtabs %}


# Record a Transfer Event

For when you intend to complete a requirement for a user programmatically.

#### Intended uses

When you are dealing with a requirement that can only be completed by your system, and not ChainVine's, some examples can include, but is not limited to:&#x20;

* a user interacts with a chain that ChainVine does not support
* a user replies to a message on your app
* a user signs up for an off-chain feature on your app

To better understand how a reward is issued to a user when calling this method, please refer to the [completeRequirement](/developers/sdk/classes-and-functions/chainvineuser/completerequirement-payload) method

{% tabs %}
{% tab title="Browser" %}
Before implementing this approach, be sure to have [whitelisted your domain](broken://pages/ydVDK8wbPPeSTZhAVgqw).

{% code overflow="wrap" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient();

const wallet_address = '0x1234567890' //<-- supplied by your systems

const transaction_hash = '0x1234567890'; //optional
const token_address = '0x1234567890'; //optional
const amount = 100; // this is the amount of token you want us to convert
const usd_value = 100; //optional, the USD value of the token at the time of the conversion
const external_identifier = 'ABC123'; //optional (e.g. a user ID in your system)
const fee = 390;

const campaign = {
  id: 'aSlug123'
}

const userClient = await client.syncUser(wallet_address);

const res = await userClient.transferEvent({
    campaign,
    transaction_hash,
    token_address,
    amount,
    usd_value,
    external_identifier,
    fee,
});
```

{% endcode %}
{% endtab %}

{% tab title="Server" %}
Before implementing this approach, be sure to have gotten a copy of [your API Key](/developers/sdk/classes-and-functions/authentication/getting-your-api-key).

{% code overflow="wrap" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key
});

const wallet_address = '0x1234567890' //<-- supplied by your systems

const transaction_hash = '0x1234567890'; //optional
const token_address = '0x1234567890'; //optional
const amount = 100; // this is the amount of token you want us to convert
const usd_value = 100; //optional, the USD value of the token at the time of the conversion
const external_identifier = 'ABC123'; //optional (e.g. a user ID in your system)

const campaign = {
  id: 'aSlug123'
}

const userClient = await client.syncUser(wallet_address);

const res = await userClient.completeRequirement({
    campaign,
    id: requirementId,
    referrer_id,
    transaction_hash,
    token_address,
    amount,
    usd_value,
    external_identifier,
});
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Complete a Requirement

For when you intend to complete a requirement for a user programmatically.

### Intended uses

When you are dealing with a requirement that can only be completed by your system, and not ChainVine's, some examples can include, but are not limited to:&#x20;

* a user interacts with a chain that ChainVine does not support
* a user replies to a message on your app
* a user signs up for an off-chain feature on your app

{% tabs %}
{% tab title="Browser" %}
Before implementing this approach, be sure to have [whitelisted your domain](broken://pages/ydVDK8wbPPeSTZhAVgqw).

{% code overflow="wrap" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug123';

const client = new ChainvineClient(); //Make sure to whitelist your domain
const requirementId = 'Hiodn2oD2dkmo2';
const userClient = await client.syncUser(userWalletAddress);

const completion = await userClient.completeRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId
});
```

{% endcode %}
{% endtab %}

{% tab title="Server" %}
Before implementing this approach, be sure to have gotten a copy of [your API Key](/developers/sdk/classes-and-functions/authentication/getting-your-api-key).

{% code overflow="wrap" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = '02jd020jkd-302jdi2d-02ij0dj';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const requirementId = 'Hiodn2oD2dkmo2';
const userClient = await client.syncUser(userWalletAddress);

const completion = await userClient.completeRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId
});

```

{% endcode %}
{% endtab %}
{% endtabs %}


# Embedded Widget

Add ChainVine's widget to display your referral program's information on your Web3 site for your logged in user!

Use the ChainVine Widget to display your referral program's information on your Web3 site for your logged in user!

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FoTCn3vDRbaDMQPeZm9dd%2Fimage%20(14).png?alt=media&amp;token=18cfa0f1-11b2-4fcd-ad14-e455ac746fff" alt=""><figcaption></figcaption></figure>

Use the ChainVine Widget if you :

* want a simple way to handle referral program signups with minimal Front-End code changes
* prefer to have users view their referral performance on your site
* want a quick way to provide your affiliates with a way to claim their rewards directly on your site


# Implementation

Note: the Widget requires React 18+

## Step 1 - Authorize your project

#### The Widget is a Browser-only SDK

#### For testing

Use a tool such as ngrok (<https://ngrok.com/docs/http/>) to get a unique URL for your web app running locally on your device and add it to your allowlist. \
\
See: [allowlisting via the admin dashboard](/developers/sdk/classes-and-functions/authentication/allow-listing-a-domain).

#### For production

Add your production domain by [allowlisting it via the admin dashboard](/developers/sdk/classes-and-functions/authentication/allow-listing-a-domain)

## Step 2 - Add the package

Install the package in your project

{% code overflow="wrap" %}

```bash
npm install @chainvine/widget
```

{% endcode %}

or

{% code overflow="wrap" %}

```bash
yarn add @chainvine/widget
```

{% endcode %}

## Step 3 - Add the Widget Component

Here is an example using a React component called "App".

### React

```typescript
import React from "react";
import "./App.css";
import { ChainvineWidget } from "@chainvine/widget";

const App = () => {
  const [isOpen, setIsOpen] = React.useState<boolean>(false);

  const openWidget = () => {
    setIsOpen(true);
  }
  const closeWidget = () => {
    setIsOpen(false);
  }

  return (
   <div>
     <button
        type={'submit'}
        onClick={() => {
          openWidget()
        }}>
        Open me
      </button>
      <ChainvineWidget
        isOpen={isOpen}
        userIdentifier={walletAddress}
        identifierType={'wallet'}
        campaignId={campaignId}
        onToggle={() => closeWidget()} 
      />
    </div>
  );
}
```

### NextJS/SSR

For server-side rendered projects, please ensure to wrap the widget component inside a client-side rendered component. For NextJS, a simple way to do this is by using the `'use-client'` tag at the top of your file:

```typescript
'use-client' //<--- IMPORTANT
import React from "react";
import "./App.css";
import { ChainvineWidget } from "@chainvine/widget";

export const MyClientSideWidgetComponent = () => {
  const [isOpen, setIsOpen] = React.useState<boolean>(false);

  const openWidget = () => {
    setIsOpen(true);
  }
  const closeWidget = () => {
    setIsOpen(false);
  }

  return (
    <div>
      <button
        type={'submit'}
        onClick={() => {
          openWidget()
        }}>
        Open me
      </button>
      <ChainvineWidget
        isOpen={isOpen}
        userIdentifier={walletAddress}
        identifierType={'wallet'}
        campaignId={campaignId}
        onToggle={() => closeWidget()} 
      />
    </div>
  );
}
```

Note: if your flow does not include a wallet connect step, we also support an identifier type of 'email' and 'externalId' where the externalId can be any unique user identifier within your system.

### Guidances

* When in desktop screen sizes: you must pass in the component around which the Widget will be positioned on the screen as a child component.&#x20;
  * In this example, we use a button, however, you can use any component that suits your needs, as long as it is able to update *isOpen* state hook in the example.
  * This example uses a useState hook, however you can very well use other state hooks such as Redux, or other  context providers.

## Step 4 - Testing&#x20;

### How to test

The ChainVine widget uses the ChainVine SDK under the hood. The *clientConfig* prop of the Widget is an extension of the ChainVine SDK's ***ClientConfig*** constructor options.

Refer to the [ChainVine SDK documentation](/developers/sdk/configuring-the-client) for how to setup testMode and ClientConfig options.&#x20;

## That's it!

If you have any questions, or run into any issues, please do not hesitate to reach out on [Telegram](https://t.me/chainvinehq)!

##


# FAQ

#### Does the Widget work with NextJS?

Of course! Please refer to our NextJS example in the [Implementation](/developers/embedded-widget/implementation#nextjs-ssr) section.

**What versions of React does the Widget support**

We support React 18+


# SDK

Welcome to the ChainVine SDK - your most flexible option when it comes to integrating with ChainVine. With our SDK, you can:

1. Capture referral events and referral traffic to your app on the browser or server, mobile apps support coming soon!
2. Create a full integrated referral system into your d(App)
3. Enable off-chain conversion events, or even on-chain conversion events that we haven't yet setup on-chain listeners for.
4. Gate portions of your app with referral program requirements
5. Design unique referral scenarios centered around activities or features on your apps


# Implementation

## Step 1 - Authorize your project

#### For testing

Use a tool such as ngrok (<https://ngrok.com/docs/http/>) to get a unique URL for your web app running locally on your device and add it to your allowlist. \
\
See: [allowlisting via the admin dashboard](/developers/sdk/classes-and-functions/authentication/allow-listing-a-domain).

#### For production

Add your production domain by [allowlisting it via the admin dashboard](/developers/sdk/classes-and-functions/authentication/allow-listing-a-domain)

## Step 2 - Packaging

The ChainVine SDK can be added to your project via the following package managers or methods

```bash
npm install @chainvine/sdk
```

Or

```bash
yarn add @chainvine/sdk
```

{% tabs %}
{% tab title="Script tag (coming soon)" %}
*Coming soon*
{% endtab %}

{% tab title="Feedback" %}
Not seeing your framework or language here? \
Let us know which one you'd like us to look into here:

{% embed url="<https://92dgagzx54m.typeform.com/to/nmMJ1EVj>" %}
{% endtab %}
{% endtabs %}

## Step 3 - Initializing the Client

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient();
```

You may provide optional configuration parameters in order to override the [default settings of the Client](broken://pages/4DdnEIPn6ZrnRUFs7uVC).

### Examples

**For your Testing environment**

{% tabs %}
{% tab title="Node.js/JavaScript" %}

```javascript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
   apiKey: 'S3CR37C0D3Z',
   testMode: true,
   logToConsole: true,
});
```

{% endtab %}
{% endtabs %}

#### For your Production environment

{% tabs %}
{% tab title="Node.js/JavaScript" %}

```javascript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
   apiKey: 'S3CR37C0D3Z',
   logToConsole: true, //can also be false or ommited depending on your needs
});
```

{% endtab %}
{% endtabs %}

## Examples

The extent to which a referral program is hosted on your d(App) is up to you.  Here are some of the functions you might like to use :&#x20;

1. [Generate unique referral links](/developers/use-cases/generate-a-referrer-link)
2. [Log the referrer from a URL link](/developers/use-cases/link-claimer-referrer)
3. [Send a custom amount-based referral conversion](/developers/use-cases/record-a-transfer-event)
4. [Send a custom once-off referral conversion](/developers/use-cases/complete-a-requirement)
5. [Record a link click](/developers/use-cases/record-link-click)
6. [Cookie management](/developers/use-cases/leverage-cookies)


# Configuring the Client

***ClientConfig***

Description: these are the options that can be specified in a [ChainvineClient](broken://pages/zHKakDgr7H1dOgGuFSfj) and [ChainvineUser](broken://pages/rxKTvA2EtbZW9K8cF0On) instance.

```typescript
import { ChainvineClient, ClientConfig } from '@chainvine/sdk/lib';

const config: ClientConfig = {
   apiKey: 'S3CR37C0D3Z',
   testMode: true,
   logToConsole: true,
}

const client = new ChainvineClient(config);
```

<table><thead><tr><th width="152">Parameter</th><th width="105">Type</th><th width="236">Description</th><th>Default</th></tr></thead><tbody><tr><td>apiKey</td><td>string</td><td>Your <a href="/developers/sdk/classes-and-functions/authentication/getting-your-api-key">ChainVine API Key</a>.<br><br>DO NOT expose this in the browser, only supply this if you are consuming the SDK on the server.</td><td>N/A<br><br>Note: If omitted, you must <a href="/developers/sdk/classes-and-functions/authentication/allow-listing-a-domain">allowlist the domain</a> you are sending requests from.</td></tr><tr><td>testMode</td><td>boolean</td><td>Setting this to true will send all traffic to ChainVine's staging environment - this should only be used for POCing and testing</td><td>false</td></tr><tr><td>logToConsole</td><td>boolean</td><td>When set to true, this will log responses and errors to console - this is useful for testing and debugging but should be set to false in production</td><td>false</td></tr><tr><td></td><td></td><td></td><td></td></tr></tbody></table>


# Classes and Functions

The SDK is split into two main classes

* [ChainvineClient](/developers/sdk/classes-and-functions/chainvineclient) handles generic requests to ChainVine not scoped to a single user
* [ChainvineUser](/developers/sdk/classes-and-functions/chainvineuser) handles requests that are scoped to a single user

Each class has its own set of functions, please refer to each classes' respective sections on each&#x20;


# Utility Methods

We expose a few useful utility methods to aid referrer ID storage when operating in a browser context.

## storeReferrer

<pre class="language-typescript"><code class="lang-typescript">import { storeReferrer } from '@chainvine/sdk';

storeReferrer(); //This will fetch the "r" query parameter from the current URL (if available) and store it in a CV_REF cookie

<strong>//You may customise the cookie settings as follows:
</strong>
storeReferrer({
  durationDays: 30, //Override the default cookie duration (120 days)
  referrer: 'ABC123', //Should you already have access to the referrer, and if you do not want it fetched from the URL, you can provide it directly
}); 
</code></pre>

## getReferrer

```typescript
import { getReferrer } from '@chainvine/sdk';

//Fetches a previously stored referrer from the CV_REF cookie if available, returns undefined if not
getReferrer(); 
```

## clearReferrer

```typescript
import { clearReferrer } from '@chainvine/sdk';

//Clear the CV_REF cookie:
clearReferrer();
```


# ChainvineClient

*ChainvineClient* instances provide functionality related to tracking referrals and triggering referral conversions in a browser or server environment.

The intended usage is:

* ChainvineClient: used for program/community level operations, where the actions are not tied to any specific user
* ChainvineUser: used for user level operations, where the actions are directly tied to a specific user


# getReferralUrl(walletAddress)

Retrieves the referral URL for a given wallet address.

<details>

<summary>To be deprecated</summary>

This method will be deprecated in upcoming versions of the SDK. Please use the [ChainvineUser.referral.url](/developers/sdk/classes-and-functions/chainvineuser/referral-campaignparams/url) method instead.

</details>

## Params

<table><thead><tr><th width="180">Param</th><th width="141">Required</th><th>Description</th></tr></thead><tbody><tr><td>walletAddress</td><td>required</td><td>the wallet of the user to general a referral link for</td></tr></tbody></table>

## **Response**

***ReferralUrlResponse***

<table><thead><tr><th width="180"></th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>url</td><td>String</td><td>the referral URL for the given wallet address</td></tr><tr><td>wallet_address</td><td>String</td><td>the wallet address linked to the referral URL</td></tr><tr><td>new_user</td><td>Boolean</td><td>indicates whether the supplied wallet address is a new user</td></tr></tbody></table>


# recordClick(referrer)

Logs a referral link click for stats tracking

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key - omit this if you're operating in the browser
});

await client.recordClick(
    'ABC123', // the referrer in the referral link
    'aSlug123' // Optional, the campaign slug/id to record the click for (if you have multiple active campaigns)
); 
```

## Params

<table><thead><tr><th width="180">Param</th><th width="141">Required</th><th>Description</th></tr></thead><tbody><tr><td>referrer</td><td>required</td><td>the referrer</td></tr><tr><td>slug</td><td>optional</td><td>An optional slug for the campaign to record the click for (if you have multiple active campaigns)</td></tr></tbody></table>

## **Response**

```typescript
void
```


# linkReferrer(\[payload,])

Links a referrer using the provided referral link payload.

### Warning - May 25, 2023

This method is deprecated, and will be sunset in upcoming versions of the SDK.

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key
});

const wallet_address = '0x1234567890';
const referrer = 'ABC2938';
const campaign_id = 'aSlug123';

const res = await client.linkToReferrer({
  campaign_id,
  wallet_address,
  referrer,
});
```

## Payload

<table><thead><tr><th width="180">Param</th><th width="141">Required</th><th>Description</th></tr></thead><tbody><tr><td>wallet_address</td><td>required</td><td>the wallet of the user being referred</td></tr><tr><td>referrer</td><td>required</td><td>the referrer's referral code</td></tr><tr><td>slug</td><td>optional</td><td>the campaign slug to create the link for</td></tr></tbody></table>

## Response

```typescript
void
```


# referralConversion(\[payload,])

Sends referral conversion event.

### Warning - May 25, 2023

This method is deprecated, and will be sunset in upcoming versions of the SDK.

{% tabs %}
{% tab title="Browser" %}
Before implementing this approach, be sure to have [whitelisted your domain](broken://pages/ydVDK8wbPPeSTZhAVgqw).

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key
});

const wallet_address = '0x1234567890' //<-- supplied by your systems
const transaction_hash = '0x1234567890'; //optional
const token_address = '0x1234567890'; //optional
const amount = 100; // this is the amount of token you want us to convert
const usd_value = 100; //optional, the USD value of the token at the time of the conversion
const external_identifier = 'ABC123'; //optional (e.g. a user ID in your system)

const campaign = {
  id: 'aSlug123'
}

const result = await client.referralConversion({
  campaign,
  wallet_address,
  amount,
  transaction_hash,
  token_address,
  usd_value,
  external_identifier,
});
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key
});

const wallet_address = '0x1234567890' //<-- supplied by your systems
const transaction_hash = '0x1234567890'; //optional
const token_address = '0x1234567890'; //optional
const amount = 100; // this is the amount of token you want us to convert
const usd_value = 100; //optional, the USD value of the token at the time of the conversion
const external_identifier = 'ABC123'; //optional (e.g. a user ID in your system)

const campaign = {
  id: 'aSlug123'
}

const result = await client.referralConversion({
  campaign,
  wallet_address,
  amount,
  transaction_hash,
  token_address,
  usd_value,
  external_identifier,
});
```

{% endtab %}
{% endtabs %}

#### Payload

<table data-full-width="true"><thead><tr><th width="188">Param</th><th width="141">Required</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>wallet_address</td><td>required</td><td>String</td><td>the wallet of the user being referred</td></tr><tr><td>chain_prefix</td><td>optional</td><td>String</td><td>a wallet address prefix - provide this if you are passing in a wallet address </td></tr><tr><td>amount</td><td>required</td><td>Number</td><td>an amount to pass in</td></tr><tr><td>campaign_id</td><td>required</td><td>String</td><td>the <a href="broken://pages/662saYlawwXwhdwSI4rC">campaign or program id</a></td></tr><tr><td>usd_value</td><td>optional</td><td>number</td><td>The USD Value of the token(s) or value being transferred, please supply this if available</td></tr><tr><td>transaction_hash</td><td>optional</td><td>String</td><td>a transaction hash to associate with the conversion</td></tr><tr><td>token_address</td><td>optional (defaults to Ethereum if not provided)</td><td>String</td><td>the token address of the token that was transfered</td></tr><tr><td>fee</td><td>optional</td><td>String</td><td>the usd value of the fee earned from the transaction</td></tr><tr><td>external_identifier</td><td>optional</td><td>String</td><td>An external identifier associated to the <code>wallet_address</code>  in your system</td></tr></tbody></table>

#### Response

```typescript
void
```


# syncUser(walletAddress)

Allows you to clone ChainvineClient instance scoped to a single wallet address without having to fetch your ClientConfig.

In addition to creating a [ChaivineUser](/developers/sdk/classes-and-functions/chainvineuser) instance from your [ChainvineClient](/developers/sdk/classes-and-functions/chainvineclient), this method will sync the wallet to the database and return the wallet's ChainVine User Id.

## EVM Wallet Addresses

<pre class="language-typescript"><code class="lang-typescript">import { ChainvineClient } from '@chainvine/sdk';

const client = new ChainvineClient({
    apiKey: '9dj022didj', //your api key
});

<strong>//Get a user's wallet address by id
</strong>const userClient = await client.syncUser(
    '0x0384093304u83', // your user's wallet address
);

</code></pre>

### Params

<table><thead><tr><th width="180">Param</th><th width="141">Required</th><th>Description</th></tr></thead><tbody><tr><td>walletAddress</td><td>required</td><td>the wallet of the user to general a referral link for</td></tr></tbody></table>

### **Response**

A ChainvineUser client instance


# getCampaignReferralStats(\[payload,])

We expose some useful campaign information via the SDK, this is accessible via the getCampaignReferralStats method

```typescript
const campaignId = 'aSlug3293';

const stats = await client.getCampaignReferralStats({
    campaign: {
        id: campaignId
    },
});
```

## Params

| Param       | Required | Type   | Description                                       |
| ----------- | -------- | ------ | ------------------------------------------------- |
| campaign.id | required | string | the id of the program/campaign to fetch stats for |

## Response

| Field         | Type                                                                                                                                                                                                                                                                                       | Description                                                              |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |
| generated\_at | Date                                                                                                                                                                                                                                                                                       | the timestamp the stats were generated at (we cache stats for 5 minutes) |
| referrers     | <p>{ <br>  user\_id: string;<br>  external\_id?: string;<br>  wallet\_address?: string;<br>  email?: string;<br>  referral\_count: number;<br>  links\_claimed: number;<br>  join\_date: Date;<br>  rewards: {<br>    amount: number;<br>    denomination: string;<br>  }\[];<br>}\[];</p> | A list of stats per active referrer on the program                       |

## Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug3293';

const client = new ChainvineClient(); //Make sure to whitelist your domain

const stats = await client.getCampaignReferralStats({
    campaign: {
        id: campaignId
    },
});
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug3293';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const stats = await client.getCampaignReferralStats({
    campaign: {
        id: campaignId
    },
});
```

{% endtab %}
{% endtabs %}


# ChainvineUser

*ChainvineUser* instances provide functionality related to managing a user in a referral program or campaign in a browser or server environment.

This is an extension of the [ChainvineClient](/developers/sdk/classes-and-functions/chainvineclient) scoped to a user, in order to perform user-specific actions.

Creating the *ChainvineUser* instance can be done via the [*ChainvineClient.syncUser*](/developers/sdk/classes-and-functions/chainvineclient/syncuser-walletaddress) method - see [Initializing the client](/developers/sdk/classes-and-functions/chainvineuser/initializing-the-client) for details.


# Initializing the client

```typescript
import { ChainvineUser } from '@chainvine/sdk';

const config = {
   apiKey: 'S3CR37C0D3Z',
   testMode: true,
   logToConsole: true,
}

const client = new ChainvineClient(config)

// By default we assume you are dealing with an ethereum wallet address 
const userClient = await client.syncUser('0x393849393430')

// If your users are uniquely identified by an email address or you would like to
// use your own internal unique identifier you may instead use either of the following
const userClient = await client.syncUserWithEmail('user@test.xyz')
const userClient = await client.syncUserWithExternalId('myOwnInternalId123')
```

You may provide an optional configuration parameters in order to override the [default settings of the Client](broken://pages/4DdnEIPn6ZrnRUFs7uVC).

You may then use the userClient to perform actions specific to the user it was synced with

## Examples

### **For your Testing environment**

{% tabs %}
{% tab title="Node.js/JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript">import { ChainvineClient } from '@chainvine/sdk';

const config = {
   apiKey: 'S3CR37C0D3Z',
   testMode: true,
   logToConsole: true,
}

const userWalletAddress = '0x393849393430'

const client = new ChainvineUser(config);

// Create your ChainvineUser client
const userClient = new ChainvineUser(
   userWalletAddress, 
   config
);

// or by using the syncUser method (note this will create or fetch the user
// on ChainVine
const userClientFromClient = await client.<a data-footnote-ref href="#user-content-fn-1">syncUser</a>(userWalletAddress);
<strong>
</strong><strong>// sync does not need to be called again as long as this instance exists
</strong><strong>console.log(userClientFromClient.id); // > ABC123
</strong></code></pre>

{% endtab %}
{% endtabs %}

### For your Production environment

{% tabs %}
{% tab title="Node.js/JavaScript" %}

```javascript
import { ChainvineClient } from '@chainvine/sdk';

const config = {
   apiKey: 'S3CR37C0D3Z',
   logToConsole: true, //can also be false or ommited depending on your needs
}

const userWalletAddress = '0x393849393430'

const client = new ChainvineClient(config);

// Create your ChainvineUser client
const userClient = await client.syncUser(userWalletAddress);
```

{% endtab %}
{% endtabs %}

[^1]:


# joinCampaign(\[campaignParams,])

Send a request to join a user to a referral program/campaign.

<pre class="language-typescript"><code class="lang-typescript">const campaignId = '02jd020jkd-302jdi2d-02ij0dj';

await userClient.joinCampaign(
   {
      campaign: {
         id: campaignId
      },
      referrer: 'ABC1245' //optional
   }
<strong>)
</strong></code></pre>

## Params

<table><thead><tr><th width="180">Param</th><th width="110">Required</th><th width="80">Type</th><th>Description</th></tr></thead><tbody><tr><td>campaign.id</td><td>required</td><td>String</td><td>the  <a href="broken://pages/662saYlawwXwhdwSI4rC">id of the program/campaign</a> the user should be added to.<br>Note: this campaign/program must belong to your account.</td></tr><tr><td>referrer</td><td>optional</td><td>String</td><td>the referrer's referral code - if passed in, a referral linking will be attempted. No referral will be made if the user was already referred.</td></tr></tbody></table>

## **Response**

```typescript
void
```

### Examples

**Joining a referred user in a gated referral program so a user can become a referrer** &#x20;

In both browser and Server-side examples, we're able to provide an optional referrerId to link the referrer to the joining user if they were referred.

{% tabs %}
{% tab title="Browser" %}
In this example we use the getReferrerId utility to fetch a referrerId from the browser session. If a referrer Id was saved before .joinCampaign is called, it&#x20;

```typescript
import { ChainvineClient, getReferrer } from '@chainvine/sdk';

const referrer = getReferrer();
const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug23';
const wallet = 'Hiodn2oD2dkmo2';

const client = new ChainvineClient(); //Make sure to whitelist your domain
const userClient = await client.syncUser(userWalletAddress);

await userClient.joinCampaign(
   {
      campaign: {
         id: campaignId
      },
      referrer, //Optional
   }
)
```

{% endtab %}

{% tab title="Server Side" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const referrer = 'aReferralCode';
const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug23';
const wallet = 'Hiodn2oD2dkmo2';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});
const userClient = await client.syncUser(userWalletAddress);

await userClient.joinCampaign(
   {
      campaign: {
         id: campaignId
      },
      referrer, //Optional
   }
)
```

{% endtab %}
{% endtabs %}


# getRequirement(\[payload,])

Fetches the completion status of a program requirement for the user

```typescript
const campaignId = 'aSlug123';
const requirementId = 'Hiodn2oD2dkmo2';

const verify = await userClient.getRequirement(
   {
      id: requirementId,
      campaign: {
         id: campaignId
      }
   }
)
```

## Params

<table><thead><tr><th width="180">Param</th><th width="106">Required</th><th width="96">Type</th><th>Description</th></tr></thead><tbody><tr><td>campaign.id</td><td>required</td><td>String</td><td><p>the id of the program/campaign the requirement belongs to.</p><p><br>Note: this campaign/program must belong to your account.</p></td></tr><tr><td>id</td><td>required</td><td>String</td><td>the referral program/campaign requirement id.</td></tr></tbody></table>

## **Response**

***UserRequirementResponse***

<table><thead><tr><th width="180">Field</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>String</td><td>the requirement id processed by the request.</td></tr><tr><td>completed</td><td>Boolean</td><td>a boolean representing if the user has completed the requirement or not.</td></tr></tbody></table>

## Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug123';

const client = new ChainvineClient(); //Make sure to whitelist your domain
const requirementId = 'Hiodn2oD2dkmo2';
const userClient = await client.syncUser(userWalletAddress);

const requirement = await userClient.getRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId
});
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug123';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const requirementId = 'Hiodn2oD2dkmo2';
const userClient = await client.syncUser(userWalletAddress);

const requirement = await userClient.getRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId
});
```

{% endtab %}
{% endtabs %}


# getUserStats(\[payload,])

Fetches the completion status of a program requirement for the user

```typescript
const campaignId = 'aSlug123';

const stats = await userClient.getUserStats(
   {
      campaign: {
         id: campaignId
      }
   }
)
```

## Params

<table><thead><tr><th width="180">Param</th><th width="106">Required</th><th width="96">Type</th><th>Description</th></tr></thead><tbody><tr><td>campaign.id</td><td>required</td><td>String</td><td><p>the id of the program/campaign the requirement belongs to.</p><p><br>Note: this campaign/program must belong to your account.</p></td></tr></tbody></table>

## **Response**

***UserStatsResponse***

<table><thead><tr><th width="180">Field</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>links_clicked.total</td><td>number</td><td>Total links clicked for the user and campaign</td></tr><tr><td>rewards_earnings.unclaimed_earnings_sum</td><td>string</td><td>Total unclaimed earnings amount formatted to two decimal points.</td></tr><tr><td>rewards_earnings.display_amount</td><td>string</td><td>Total unclaimed earnings amount formatted to two decimal points with the currency</td></tr></tbody></table>

## Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug123';

const client = new ChainvineClient(); //Make sure to whitelist your domain
const userClient = await client.syncUser(userWalletAddress);

const stats = await userClient.getUserStats({
    campaign: {
        id: campaignId
    },
});
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug123';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const userClient = await client.syncUser(userWalletAddress);

const stats = await userClient.getUserStats({
    campaign: {
        id: campaignId
    },
});
```

{% endtab %}
{% endtabs %}


# verifyRequirement(\[payload,])

Attempts to verify a requirement for the user

On success, if the requirement belongs to a program/campaign objective, ChainVine will asynchronously check whether the user has completed enough requirements to mark an objective as completed.

```typescript
const campaignId = '02jd020jkd-302jdi2d-02ij0dj';

const requirementId = 'Hiodn2oD2dkmo2';

const verify = await userClient.verifyRequirement(
   {
      id: requirementId,
      campaign: {
         id: campaignId
      }
   }
)
```

## Params

<table><thead><tr><th width="180">Field</th><th width="141">Required</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>campaign.id</td><td>required</td><td>String</td><td>the id of the program/campaign the requirement belongs to<br>Note: this campaign/program must belong to your account</td></tr><tr><td>id</td><td>required</td><td>String</td><td>the referral program/campaign requirement id</td></tr></tbody></table>

## **Response**

***UserRequirementResponse***

<table><thead><tr><th width="180">Field</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>String</td><td>the referral program/campaign requirement id</td></tr><tr><td>completed</td><td>Boolean</td><td>a boolean representing if the user has completed the requirement or not</td></tr></tbody></table>

## Examples

{% tabs %}
{% tab title="Browser" %}
In this approach, we complete a requirement ad-hoc for a user, by passing in a referrer\_id if one has been captured by a referral link beforehand.

If the referrer id is passed into the request, and no referral has ever been made between this user and any referrer, then a Referral will be created.

```typescript
import { ChainvineClient, getReferrerId } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

const campaignId = 'aSlug123';

// Generate your ChainvineClient instance
const client = new ChainvineClient(); //Make sure to whitelist your domain

const requirementId = 'Hiodn2oD2dkmo2';

const userClient = await client.syncUser(userWalletAddress);

const completion = await userClient.verifyRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId,
});

```

{% endtab %}

{% tab title="Server" %}
In this approach, we complete a requirement ad-hoc for a user, by passing in a referrer\_id if one has been captured by a referral link beforehand.

If the referrer id is passed into the request, and no referral has ever been made between this user and any referrer, then a Referral will be created.

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

const campaignId = '02jd020jkd-302jdi2d-02ij0dj';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const requirementId = 'Hiodn2oD2dkmo2';

const userClient = await client.syncUser(userWalletAddress);

const completion = await userClient.verifyRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId,
});

```

{% endtab %}
{% endtabs %}


# completeRequirement(\[payload,])

Mark a program/campaign requirement as completed for the user

This method allows you to mark a user's program requirement as completed.

#### How this methods issues rewards

On success, if the requirement belongs to a program/campaign objective, ChainVine will asynchronously check whether the user has completed enough requirements to mark an objective as completed.

```typescript
const campaignId = '02jd020jkd-302jdi2d-02ij0dj';

const requirementId = 'Hiodn2oD2dkmo2';

const completion = await userClient.completeRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId,
});
```

## Params

<table><thead><tr><th width="190">Param</th><th width="102">Required</th><th width="111">Type</th><th>Description</th></tr></thead><tbody><tr><td>campaign.id</td><td>required</td><td>string</td><td>the  <a href="broken://pages/662saYlawwXwhdwSI4rC">id of the program/campaign</a> requirement belongs to<br>Note: this campaign/program must belong to your account</td></tr><tr><td>id</td><td>required</td><td>string</td><td>the requirement id to complete</td></tr></tbody></table>

## Optional Params

These parameters can be passed in if you are sending custom data to ChainVine when completing a requirement programatically

<table><thead><tr><th width="190">Param</th><th width="102">Required</th><th width="111">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount</td><td>optional</td><td>number</td><td>an amount to associate with the completion</td></tr><tr><td>fee</td><td>optional</td><td>number</td><td>an optional fee to pass into the SDK</td></tr><tr><td>transaction_hash</td><td>optional</td><td>string</td><td>The hash of the transaction that this completion should be linked to</td></tr><tr><td>token_address</td><td>optional</td><td>string</td><td>a token address (token, NFT, smart contract) that should be associated with this completion</td></tr><tr><td>external_identifier</td><td>optional</td><td>string</td><td>a user identifier known to your system, if passed in, ChainVine will associate this with the wallet address if none has been associated yet, this value will be returned to you if present</td></tr></tbody></table>

## **Response**

<table><thead><tr><th width="180">Field</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>message</td><td>String</td><td>Ok status message on success</td></tr></tbody></table>

## Examples

{% tabs %}
{% tab title="Browser" %}
In this approach, we complete a requirement ad-hoc for a user, by passing in a referrer\_id if one has been captured by a referral link beforehand.

If the referrer id is passed into the request, and no referral has ever been made between this user and any referrer, then a Referral will be created.

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug123';

const client = new ChainvineClient(); //Make sure to whitelist your domain
const requirementId = 'Hiodn2oD2dkmo2';
const userClient = await client.syncUser(userWalletAddress);

const completion = await userClient.completeRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId
});

```

{% endtab %}

{% tab title="Server" %}
In this approach, we complete a requirement ad-hoc for a user, by passing in a referrer\_id if one has been captured by a referral link beforehand.

If the referrer id is passed into the request, and no referral has ever been made between this user and any referrer, then a Referral will be created.

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = '02jd020jkd-302jdi2d-02ij0dj';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const requirementId = 'Hiodn2oD2dkmo2';
const userClient = await client.syncUser(userWalletAddress);

const completion = await userClient.completeRequirement({
    campaign: {
        id: campaignId
    },
    id: requirementId
});

```

{% endtab %}
{% endtabs %}


# claimEligibleEarnings(\[payload,])

Claim eligible cryptocurrency earnings for a user of your campaign

This method allows you request a user's earnings to be paid out from your Gnosis Safe.

**Note** - this endpoint is asynchronous of the actual payouts from your Gnosis Safe, which occur on-chain. ChainVine handles reconciling earnings owed with those that are transferred successfully on-chain via this SDK method.

```typescript
const campaignId = 'aSlug123';

const campaign = {
  id: campaignId
}

const claim = await userClient.claimEligibleEarnings({campaign});
```

## Params

<table><thead><tr><th width="190">Param</th><th width="102">Required</th><th width="111">Type</th><th>Description</th></tr></thead><tbody><tr><td>campaign.id</td><td>required</td><td>string</td><td>the  <a href="broken://pages/662saYlawwXwhdwSI4rC">id of the program/campaign</a> requirement belongs to<br>Note: this campaign/program must belong to your account</td></tr></tbody></table>

## **Response**

<table><thead><tr><th width="180">Field</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>message</td><td>String</td><td>Ok status message on success</td></tr></tbody></table>

## How this method claims earnings for your user

* All unpaid earnings are flagged for pay-out
* Pay-outs are reflected on ChainVine asynchronously of the request&#x20;
* Earnings that are ***paid out*** successfully on chain are marked as paid out ChainVine side
* Earnings that ***fail*** on-chain are not marked as failed on ChainVine and can be re-attempted
* Earnings that are ***being*** paid out will not be retried while on-chain transfer confirmation is pending

## Examples

{% tabs %}
{% tab title="Browser" %}
In this approach, we claim a user's earnings on their behalf.

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'aSlug123';

// Generate your ChainvineClient instance
const client = new ChainvineClient(); //Make sure to whitelist your domain

const userClient = await client.syncUser(userWalletAddress);

const campaign = {
  id: campaignId
}

const claim = await userClient.claimEligibleEarnings({campaign});

```

{% endtab %}

{% tab title="Server" %}
In this approach, we claim a user's earnings on their behalf. Since we are in a server-side environment, we pass in the API Key to the ChainvineClient instance.

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

const campaignId = 'aSlug123';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const userClient = await client.syncUser(userWalletAddress);

const campaign = {
  id: campaignId
}

const claim = await userClient.claimEligibleEarnings({campaign});

```

{% endtab %}
{% endtabs %}


# transferEvent(\[payload,])

{% code overflow="wrap" %}

```typescript
const campaignId = 'aSlud3293';

const amount = 100; // required, this is the amount of token you want us to convert
const usd_value = 100; //required, the USD value of the token at the time of the conversion
const external_identifier = 'ABC123'; //optional (e.g. a user ID in your system)
const chain_id = '1'; // optional
const fee = 20; // optional
const transaction_hash = '0x1234567890'; //optional
const token_address = '0x1234567890'; //optional
const requirement_id = 'abc123def'; //optional

const completion = await userClient.transferEvent({
    requirement_id,
    campaign: {
        id: campaignId
    },
    transaction_hash,
    chain_id,
    network,
    token_address,
    amount,
    usd_value
    external_identifier
    fee,
});
```

{% endcode %}

## Params

<table><thead><tr><th width="190">Param</th><th width="102">Required</th><th width="111">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount</td><td>required</td><td>number</td><td>an amount to associate with the completion</td></tr><tr><td>campaign.id</td><td>required</td><td>string</td><td>the id of the program/campaign requirement belongs to</td></tr><tr><td>usd_value</td><td>optional</td><td>string</td><td>the value of the amount field in USD</td></tr><tr><td>fee</td><td>optional</td><td>number</td><td>an optional fee to pass into the SDK</td></tr><tr><td>transaction_hash</td><td>optional</td><td>string</td><td>The hash of the transaction that this completion should be linked to</td></tr><tr><td>token_address</td><td>optional</td><td>string</td><td>a token address (token, NFT, smart contract) that should be associated with this completion</td></tr><tr><td>external_identifier</td><td>optional</td><td>string</td><td>a user identifier known to your system, if passed in, ChainVine will associate this with the wallet address if none has been associated yet, this value will be returned to you if present</td></tr><tr><td>requirement_id</td><td>optional</td><td>string</td><td>The requirement to track the transfer against, this is only required if you have a program with multiple transfer objectives</td></tr></tbody></table>

## **Response**

<table><thead><tr><th width="180">Field</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>message</td><td>String</td><td>Ok status message on success</td></tr></tbody></table>

## Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

const campaignId = 'aSlug123';

// Generate your ChainvineClient instance
const client = new ChainvineClient(); //Make sure to whitelist your domain
const userClient = await client.syncUser(userWalletAddress);

const amount = 100; // required, this is the amount of token you want us to convert
const usd_value = 100; //required, the USD value of the token at the time of the conversion
const external_identifier = 'ABC123'; //optional (e.g. a user ID in your system)
const chain_id = '1'; // optional
const fee = 20; // optional
const transaction_hash = '0x1234567890'; //optional
const token_address = '0x1234567890'; //optional
const requirement_id = 'abc123def'; //optional

const completion = await userClient.transferEvent({
    requirement_id,
    campaign: {
        id: campaignId
    },
    transaction_hash,
    chain_id,
    network,
    token_address,
    amount,
    usd_value
    external_identifier
    fee,
});

```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

const campaignId = 'aSlug123';

// Generate your ChainvineClient instance
const client = new ChainvineClient({ apiKey: 'your-api-key'});
const userClient = await client.syncUser(userWalletAddress);

const amount = 100; // required, this is the amount of token you want us to convert
const usd_value = 100; //required, the USD value of the token at the time of the conversion
const external_identifier = 'ABC123'; //optional (e.g. a user ID in your system)
const chain_id = '1'; // optional
const fee = 20; // optional
const transaction_hash = '0x1234567890'; //optional
const token_address = '0x1234567890'; //optional
const requirement_id = 'abc123def'; //optional

const completion = await userClient.transferEvent({
    requirement_id,
    campaign: {
        id: campaignId
    },
    transaction_hash,
    chain_id,
    network,
    token_address,
    amount,
    usd_value
    external_identifier
    fee,
});

```

{% endtab %}
{% endtabs %}


# referral(\[campaignParams,])

Access the user's referral methods for a given referral program.

```typescript
import { ChainvineUser } from '@chainvine/sdk';

const userClient = new ChainvineUser(
   '0x393849393430', 
   {
      apiKey: 'S3CR37C0D3Z',
   }
);

const campaignId = 'siojdp2no';

const campaignParams = {
  campaign: {
     id: campaignId
  }
};

const userReferral = userClient.referral(campaignParams);
```

## Params

<table><thead><tr><th width="180">Param</th><th width="141">Required</th><th>Description</th></tr></thead><tbody><tr><td>campaign.id</td><td>yes</td><td>the id of the program/campaign the user should be added to.<br>Note: this campaign/program must belong to your account.</td></tr></tbody></table>

## **Response**

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td></td><td><strong>url()</strong></td><td></td><td><a href="/developers/sdk/classes-and-functions/chainvineuser/referral-campaignparams/url">url()</a></td></tr><tr><td><p></p><p><strong>linkToReferrer(referrerId)</strong></p></td><td></td><td></td><td><a href="/developers/sdk/classes-and-functions/chainvineuser/referral-campaignparams/linktoreferrer-referrer">linkToReferrer(referrer)</a></td></tr></tbody></table>


# linkToReferrer(referrer)

Link a user to a given referrer - this creates a relationship between the two on ChainVine, allowing us to attribute rewards to the referrer based on the user's activity

```typescript
const campaign = { id:'your-campaign-id',}
const referrer = getReferrer();//Or manually fetch from URL if not using cookies

if (referrer) {
  await userClient
    .referral({ campaign })
    .linkToReferrer(referrer);
}
```

## Params

| Param       | Required | Type   | Description                                            |
| ----------- | -------- | ------ | ------------------------------------------------------ |
| campaign.id | required | string | the  id of the program/campaign requirement belongs to |
| referrer    | required | string | the referrer to link the user to                       |

## Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient, getReferrerId } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'siojdp2no';
const referrer = getReferrer();//Or manually fetch from URL if not using cookies

const client = new ChainvineClient(); //Make sure to whitelist your domain

const userClient = await client.syncUser(userWalletAddress);
const referralUrlResponse = await userClient
  .referral({ campaign })
  .linkToReferrer(referrer);
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'siojdp2no';
const referrer = 'abc123';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const userClient = await client.syncUser(userWalletAddress);
const referralUrlResponse = await userClient
  .referral({ campaign })
  .linkToReferrer(referrer);
```

{% endtab %}
{% endtabs %}


# url()

Generate the referral url for the user in a given campaign or program via ChainVine.

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const config = {
   apiKey: 'S3CR37C0D3Z',
   testMode: true,
   logToConsole: true,
}

const userWalletAddress = '0x393849393430'

const client = new ChainvineClient(config);
const userClient = await client.syncUser(userWalletAddress);

const campaign = {
   id: 'siojdp2no'
}

const referralUrlResponse = await userClient.referral({ campaign }).url();
console.log(referralUrlResponse.url); //<-- https://app.chainvine.xyz/community/siojdp2no?r=ABC123
```

## **Params**

| Param       | Required | Type   | Description                                            |
| ----------- | -------- | ------ | ------------------------------------------------------ |
| campaign.id | required | string | the  id of the program/campaign requirement belongs to |

## **Response**

***ReferralUrlResponse***

<table><thead><tr><th width="180">Field</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>url</td><td>String</td><td>the referral URL for the given wallet address</td></tr><tr><td>wallet_address</td><td>String</td><td>the wallet address linked to the referral URL</td></tr></tbody></table>

## Examples

{% tabs %}
{% tab title="Browser" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'siojdp2no';

const client = new ChainvineClient(); //Make sure to whitelist your domain

const userClient = await client.syncUser(userWalletAddress);
const referralUrlResponse = await userClient.referral({ campaign }).url();
```

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';
const campaignId = 'siojdp2no';

// Generate your ChainvineClient instance
const client = new ChainvineClient({
    apiKey: '0dj03j000d'  // Your API Key
});

const userClient = await client.syncUser(userWalletAddress);
const referralUrlResponse = await userClient.referral({ campaign }).url();
```

{% endtab %}
{% endtabs %}


# setRewardTiersOverride(\[payload,])

We allow tier percentage overriding should you wish to specify a custom percentage reward for specific users

```typescript
const rewardId = 1; //Your reward ID to override

await userClient.setRewardTiersOverride({
   rewardId,
   percentage: 25 //the custom reward % for the given user
});

```

| Param      | Required | Type   | Description                                                  |
| ---------- | -------- | ------ | ------------------------------------------------------------ |
| rewardId   | required | number | the rewardId you are setting a custom percentage for         |
| percentage | required | number | the custom percentage to apply for the given user and reward |

{% tabs %}
{% tab title="Browser" %}

<pre class="language-typescript"><code class="lang-typescript">import { ChainvineClient } from '@chainvine/sdk';

<strong>const userWalletAddress = '0x293kdo0ij0';
</strong>
// Generate your ChainvineClient instance
const client = new ChainvineClient(); //Make sure to whitelist your domain
const userClient = await client.syncUser(userWalletAddress);

const rewardId = 1; //Your reward ID to override

await userClient.setRewardTiersOverride({
   rewardId,
   percentage: 25 //the custom reward % for the given user
});
</code></pre>

{% endtab %}

{% tab title="Server" %}

```typescript
import { ChainvineClient } from '@chainvine/sdk';

const userWalletAddress = '0x293kdo0ij0';

// Generate your ChainvineClient instance
const client = new ChainvineClient({ apiKey: 'your-api-key'});
const userClient = await client.syncUser(userWalletAddress);

const rewardId = 1; //Your reward ID to override

await userClient.setRewardTiersOverride({
   rewardId,
   percentage: 25 //the custom reward % for the given user
});
```

{% endtab %}
{% endtabs %}


# Errors

ChainVine uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success, whereas codes in the 4xx range indicate an error caused by invalid request information, and codes in the 5xx range indicate an error with ChainVine’s servers.


# Authentication

The ChainVine API uses API keys and domain allowlisting to authenticate requests depending on where you want to use it.

## For the Browser

**Recommendation**

Setup [domain allowlisting](/developers/sdk/classes-and-functions/authentication/allow-listing-a-domain) for your dApp to authenticate SDK requests.

## For the Server

Use [API Keys](/developers/sdk/classes-and-functions/authentication/getting-your-api-key) to authenticate and authorize requests from your servers.


# Getting your API Key

Go to <https://app.chainvine.xyz> and connect your wallet.

#### 1. Navigate to your Admin Dashboard

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FX54JpnxuyAEoDz6wyUaM%2FScreen%20Shot%202023-05-20%20at%202.22.33%20PM.png?alt=media&amp;token=e8e8cabb-2457-49ac-b0db-b4e6c60280f4" alt=""><figcaption><p><em>The Admin Dashboard can be found on clicking your Avatar icon at the top-right of the screen, in the dropdown menu that appears.</em></p></figcaption></figure>

#### 2. Select your Community

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fy3bD11mXrWrig0WJnY3G%2Fselect-community.png?alt=media&amp;token=b6c0002c-25c2-4db9-9e58-712f5d6ba533" alt=""><figcaption></figcaption></figure>

#### 3. Select the "Settings" tab

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F7Qru1tHNkyAoI6eIO7fw%2Fselect-settings.png?alt=media&amp;token=b95e3954-a8c9-4eaa-990c-686d468a5010" alt=""><figcaption></figcaption></figure>

#### 4. Scroll down to the "Integration" section and copy your API Key

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FlY2f9uhMgc60aW88l8xS%2Fcopy-api-key.png?alt=media&amp;token=ee780101-9600-4bbf-a6db-e00b5de90b3b" alt=""><figcaption></figcaption></figure>


# Allow-listing a domain

Go to <https://app.chainvine.xyz> (for production) or <https://staging.chainvine.xyz> (for testing) and connect your wallet.

#### 1. Navigate to your Admin Dashboard

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FX54JpnxuyAEoDz6wyUaM%2FScreen%20Shot%202023-05-20%20at%202.22.33%20PM.png?alt=media&amp;token=e8e8cabb-2457-49ac-b0db-b4e6c60280f4" alt=""><figcaption><p><em>The Admin Dashboard can be found on clicking your Avatar icon at the top-right of the screen, in the dropdown menu that appears.</em></p></figcaption></figure>

#### 2. Select your Community

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fy3bD11mXrWrig0WJnY3G%2Fselect-community.png?alt=media&amp;token=b6c0002c-25c2-4db9-9e58-712f5d6ba533" alt=""><figcaption></figcaption></figure>

#### 3. Select the "Settings" tab

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F7Qru1tHNkyAoI6eIO7fw%2Fselect-settings.png?alt=media&amp;token=b95e3954-a8c9-4eaa-990c-686d468a5010" alt=""><figcaption></figcaption></figure>

#### 4. Scroll down to the "Integration" section and enter your domain in the text field (you can add many domains), click "Add a domain"&#x20;

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F8d2wOnXT3x2rWkIzLdHt%2Fadd-a-domain.png?alt=media&amp;token=216e3a51-b70d-4fcf-b6e1-174fd49a79ef" alt=""><figcaption></figcaption></figure>

#### 5. Click "Save" to update your new domain(s) to your list of allow-listed domains&#x20;

You should see a "Changes Saved" popup at the top of the screen if the save was successful.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FZOl9AYA9aycQ3Dp53t4l%2Fsave-domain-confirmation.png?alt=media&amp;token=a7d9edfa-d571-4a90-bcf7-b6ebbc1b49f0" alt=""><figcaption></figcaption></figure>

Note, if testing from localhost, you can use a tool like ngrok: <https://ngrok.com/docs/http/> to get a unique endpoint that you can whitelist.


# FAQ

## Does the SDK handle any browser cookies?

Yes, the SDK is designed to set referral sessions cookies for you if it detects it is being used in a browser environment.

## Does ChainVine support other programming languages?

We currently only provide our SDK in TypeScript/JavaScript. We are working towards publishing our OpenAPI specification, and aiming to release other programming language versions of our SDK in the coming quarters.&#x20;

Head over to our SDK feedback form to [suggest a programming language](https://92dgagzx54m.typeform.com/to/nmMJ1EVj)!


# Webhooks

Got a use case where Webhooks make the most sense? Drop us a line and we'll get you set up!

## Payload

All requests sent by ChainVine have the following structure. Each event may or may not provide a unique nested event.data payload:

```typescript
type WebHookRequestData = {
  source: {
    campaign: {
      name: string;
      created_on: string;
      id: string;
    };
    community: {
      name: string;
      id: string;
    };
  };
  event: {
    name: string;
    data: object;
  };
  version: string;
  secure_request: boolean;
  request_id: string;
  event_id: string;
  sent_at: string;
};
```

## Events

### Join Campaign Event

<details>

<summary>Payload</summary>

```typescript
{
  event: {
    name: "USER_JOINED_CAMPAIGN";
    data: {
      user_id: string;
      user: {
        id: string;
        email?: string;
        first_name?: string;
        last_name?: string;
        wallet_address?: string;
        external_identifier?: string;
      };
      referrer?: string;
      external_identifier?: string;
    }
  }
}
```

</details>

#### When we send this event

ChainVine sends this event when a user has joined a referral program.

This can occur when:

* a user clicks "Join Campaign" in a program page
* your systems call [ChainVineUser.joinCampaign](/developers/sdk/classes-and-functions/chainvineuser/joincampaign-campaignparams) and the request is successful&#x20;

### Referral Conversion Event

<details>

<summary>Payload</summary>

```typescript
{
  event: {
    name: "REFERRAL_CONVERSION",
    data: {
      claimer: string;
      referrer?: string;
      external_identifier?: string;
    };
  };
}
```

</details>

#### When we send this event

This event is sent whenever a ***referred*** user has completed an action:&#x20;

* you call either [ChainVineUser.verifyRequirement ](/developers/sdk/classes-and-functions/chainvineuser/verifyrequirement-payload)or [ChainVineUser.completeRequirement](/developers/sdk/classes-and-functions/chainvineuser/completerequirement-payload) methods, and this results in a claimer completing an objective or requirement
* you call [ChainVineUser.transferEvent](/developers/sdk/classes-and-functions/chainvineuser/transferevent-payload) where the amount transferred meets the minimum threshold (if any)
* a user completes an objective via an on-chain requirement

### Earning Creation Event

<details>

<summary>Payload</summary>

```typescript
{
  event: {
    name: "EARNING_CREATED",
    data: {
      userId: string;
      dateCreatedUtc: string;
      user: {
        id: string;
        email?: string;
        firstName?: string;
        lastName?: string;
        walletAddress?: string;
        externalIdentifier?: string;
      };
      reward: {
        name: string;
      };
      amount: string;
    };
  };
}
```

</details>

#### When we send this event

This event is fired off whenever a user reward has been attributed a reward from a program or campaign you manage.

**Schema**

| Name        | Type   | Description                                                                                                                                                              |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| user\_id    | string | The Chainvine user id of your user                                                                                                                                       |
| reward.name | string | <p>The name of the reward issued<br>If </p>                                                                                                                              |
| amount      | string | <p>The amount of the reward issued.<br>Cryptocurrencies: 18 decimal places, value in unitary currency (ie, in ETH, not GWEI)<br>Non Crypto Rewards: 4 decimal places</p> |

**Examples of reward amounts**

* "15.000" Points for fifteen points
* "0.00398888889000003983" ETH for 0.0039 ETH
* "1.000" NFT for 1 NFT of a Collection
* "1.000" Boxes for 1 Loot Box from your platform

### Payment Request

ChainVine supports using your system as a payout-provider if you should so choose.

Example scenarios where this could be a useful scenario for you:

* if you have compliance requirements to track, record or action all user payouts
* if you have a payout currency not supported by ChainVine

#### When we send this event

This event is sent in one of the following scenarios if you have configured a reward payout to be managed by your systems:

* a user clicks "Claim Rewards" on ChainVine or on the ChainVine Widget hosted on your site
* if you have configured payouts to be automatically executed as soon as they are awarded to users.

#### Handling responses

ChainVine will expect a 200-type status to mark a payment as completed.

If an error response is received, ChainVine will mark the payout as failed, and the payout will need to be attempted again.&#x20;

There is currently no limit on how many times a Webhook Payout can be attempted.

## Testing

If you would like to test the webhook flow before implementing on your end, simply visit <https://webhook.site/> and send us your unique URL.\
\
We will then configure your community's webhooks to target your unique endpoint and you can inspect them as they come through.


# Open API Specification

## Context

Here you will find our OpenAPI specification for the Chainvine API.

### All endpoints below require you to provide your api key in the headers

```typescript
{
    'X-API-KEY': 'your-api-key'
}
```

## SyncUser

Always call this method early on in your flows to fetch a user's Chainvine ID.

Note: the SDK handles calling this endpoint for your when using the SDK to call the methods in the ChainvineUser section.

{% openapi src="/files/0aOfdewALY13Iux9G7JK" path="/api/v2/users" method="post" %}
[openapi.yaml](https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fk7bfAvA1lkm2rdPIuBLw%2Fopenapi.yaml?alt=media\&token=c66c35b3-828c-433d-ab72-adf49d757a91)
{% endopenapi %}

This endpoint can also be used to update the user's information.

### ChainvineUser

These endpoints can also be covered via the SDK. Please see methods outlined there as needed or examples of how to use these endpoints to suit your needs.

{% openapi src="/files/px5gwdrDz7OrwYDhFiv7" path="/api/v2/user/{user\_id}/campaign/{campaign\_id}/link/referral" method="post" %}
[openapi.yaml](https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FgVVxoD02bb9t5fdNTop4%2Fopenapi.yaml?alt=media\&token=a540cdf3-d6c9-4e08-bb34-c19e5c91130f)
{% endopenapi %}

{% openapi src="/files/0aOfdewALY13Iux9G7JK" path="/api/v2/user/{user\_id}/campaign/{campaign\_id}/referral/url" method="get" %}
[openapi.yaml](https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fk7bfAvA1lkm2rdPIuBLw%2Fopenapi.yaml?alt=media\&token=c66c35b3-828c-433d-ab72-adf49d757a91)
{% endopenapi %}

{% openapi src="/files/0aOfdewALY13Iux9G7JK" path="/api/v2/user/{user\_id}/campaign/{campaign\_id}/events/transfer" method="post" %}
[openapi.yaml](https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fk7bfAvA1lkm2rdPIuBLw%2Fopenapi.yaml?alt=media\&token=c66c35b3-828c-433d-ab72-adf49d757a91)
{% endopenapi %}

{% openapi src="/files/0aOfdewALY13Iux9G7JK" path="/api/v2/user/{user\_id}/requirements/complete" method="post" %}
[openapi.yaml](https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fk7bfAvA1lkm2rdPIuBLw%2Fopenapi.yaml?alt=media\&token=c66c35b3-828c-433d-ab72-adf49d757a91)
{% endopenapi %}

### V1 Endpoints

{% openapi src="/files/px5gwdrDz7OrwYDhFiv7" path="/v1/chainvine/community/{community\_id}/campaign/{campaign\_id}/record-click" method="post" %}
[openapi.yaml](https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FgVVxoD02bb9t5fdNTop4%2Fopenapi.yaml?alt=media\&token=a540cdf3-d6c9-4e08-bb34-c19e5c91130f)
{% endopenapi %}

### CodeGeneration

If you would like to generate custom code for the endpoints above, please visit our [swaggerhub page ](https://app.swaggerhub.com/apis/ChainVine/ChainVine/1.5.40)and select the "Export" drop down at the top right of the page.


# Claiming For Users

All users can come to our ChainVine dApp in order to claim rewards.


# On ChainVine

This guide outlines how a user can claim rewards themselves on <https://app.chainvine.xyz>.

### 1. Log in to ChainVine with your wallet

a. Visit <https://app.chainvine.xyz>

b. Connect your wallet

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2Fgb5TbOoyay8XxR7FiIGx%2FScreenshot%202024-01-25%20at%2015.59.55.png?alt=media&amp;token=bc7fe802-9716-40b2-bc2f-fcbd11951f9c" alt=""><figcaption></figcaption></figure>

### 2. Sign up as a Partner

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FqenSGETmUYr02uqgO4GQ%2Fimage.png?alt=media&amp;token=b9c4fe8d-8aff-4bf2-abca-46c7434e3a05" alt=""><figcaption></figcaption></figure>

a. Link your Twitter account

b. Fill out the form and apply

c. Wait for the ChainVine team to approve your request

### 3. Open the Earning Drawer

You can open the earning drawer by clicking on the Pill Button next to your DAvatar a the top right of the screen.

<figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F30nodquCunKshwIe20y7%2FScreenshot%202024-01-25%20at%2015.59.17.png?alt=media&amp;token=2bae7bf9-3c89-4e63-89d4-21154ca2f30b" alt=""><figcaption></figcaption></figure>

### 4. Claim Eligible Rewards in the Rewards Tab

If a user has eligible rewards that can be paid out, their "Claim Rewards" button in the Claimable Rewards section of the drawer will be enabled.

Once a user clicks Claim Rewards, ChainVine will handle paying out the user.

<div align="left"><figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2FS8GHc8qnJY1Qy339MFv3%2Fimage.png?alt=media&amp;token=ff3e8e37-bde3-4b6d-9db9-0911f3bd489b" alt="" width="326"><figcaption></figcaption></figure></div>

### 5. View your own user and referrer activity in the Activity Tab

<div align="left"><figure><img src="https://1752503732-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl2v529xMI8AzUlzqr4xx%2Fuploads%2F8W8EgSgw72DBdV3hborN%2Fimage.png?alt=media&amp;token=74694d84-dc57-45c3-8615-d9318ddfef9d" alt="" width="354"><figcaption></figcaption></figure></div>


