# Decentralized (with Stripe Connect)

## Overview

This guide provides instructions on using Forge’s decentralized white label option to create and manage `ReferralCustomers` using Stripe Connect with
a Stripe Account. For a more detailed overview of the White Label product, please refer to the Forge Overview page.

---

## Prerequisites

1. Complete all prerequisites to Get Started with Forge.
2. Already manage a Stripe account and have flows for creating Stripe Customers and Stripe Payment Methods.

---

## ReferralCustomer API Onboarding

Use EasyPost’s `POST /referral_customers` endpoint to create a `ReferralCustomer`.
**Save the API keys securely for use in later steps.** If API keys are lost, they can be retrieved from the Sub Account Details page.

  **IMPORTANT:** When a `ReferralCustomer` is created with your API key, you are certifying that the `ReferralCustomer`
  agrees to the EasyPost Terms of Service.

**Production Only**

### Example: POST /referral_customers

#### cURL

```shell
curl -X POST https://api.easypost.com/v2/referral_customers \
  -u "$PARTNER_API_KEY": \
  -H "Content-Type: application/json" \
  -d '{
      "user": {
        "name": "Firstname Lastname",
        "email": "email@example.com",
        "phone_number": "8888888888"
      }
  }'
```

#### Go

```go
package example

import (
	"fmt"

	"github.com/EasyPost/easypost-go/v5"
)

func create() {
	client := easypost.New("EASYPOST_API_KEY")

	name := "Test Referral"
	email := "test@example.com"
	phone := "5555555555"

	referralUser, _ := client.CreateReferralCustomer(
		&easypost.UserOptions{
			Name:  &name,
			Email: &email,
			Phone: &phone,
		},
	)

	fmt.Println(referralUser)
}
```

#### Java

```java
package referral;

import com.easypost.exception.EasyPostException;
import com.easypost.model.ReferralCustomer;
import com.easypost.service.EasyPostClient;

import java.util.HashMap;

public class Create {
    public static void main(String[] args) throws EasyPostException {
        EasyPostClient client = new EasyPostClient("EASYPOST_API_KEY");

        HashMap<String, Object> params = new HashMap<>();

        params.put("name", "test test");
        params.put("email", "test@test.com");
        params.put("phone", "8888888888");

        ReferralCustomer referralUser = client.referralCustomer.create(params);

        System.out.println(referralUser);
    }
}
```

#### C#

```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyPost;
using Newtonsoft.Json;

namespace EasyPostExamples
{
    public class Examples
    {
        public static async Task Main()
        {
            var client = new EasyPost.Client(new EasyPost.ClientConfiguration("EASYPOST_API_KEY"));

            EasyPost.Parameters.ReferralCustomer.Create parameters = new()
            {
                Name = "test user",
                Email = "email@example.com",
                Phone = "8888888888"
            };

            EasyPost.Models.API.ReferralCustomer referralUser = await client.ReferralCustomer.CreateReferral(parameters);

            Console.WriteLine(JsonConvert.SerializeObject(referralUser, Formatting.Indented));
        }
    }
}
```

#### Node.js

```javascript
const EasyPostClient = require('@easypost/api');

const client = new EasyPostClient('EASYPOST_API_KEY');

(async () => {
  const referralCustomer = await client.ReferralCustomer.create({
    name: 'Test Referral',
    email: 'test@example.com',
    phone: '1111111111',
  });

  console.log(referralCustomer);
})();
```

#### PHP

```php
<?php

$client = new \EasyPost\EasyPostClient('EASYPOST_API_KEY');

$referralUser = $client->referralCustomer->create([
    'name' => 'Test Referral',
    'email' => 'test@test.com',
    'phone' => '8888888888'
]);

echo $referralUser;
```

#### Python

```python
import easypost

client = easypost.EasyPostClient("EASYPOST_API_KEY")

referral_user = client.referral_customer.create(
    name="test test",
    email="test@test.com",
    phone="8888888888",
)

print(referral_user)
```

#### Ruby

```ruby
require 'easypost'

client = EasyPost::Client.new(api_key: 'EASYPOST_API_KEY')

referral_user = client.referral_customer.create(
  name: 'test user',
  email: 'email@example.com',
  phone: '8888888888',
)

puts referral_user
```

---

## ReferralCustomer Billing Management

Platforms and marketplaces must build an interface that allows customers to:

- Set up Payment Methods
- Manage Wallet Settings within their application.

---

## Step 1: Create and Attach Payment Methods

Forge **Decentralized with Stripe Connect** allows platforms and marketplaces to collect payment methods with their own custom Stripe integration.
Use EasyPost’s POST /beta/referral_customers` endpoint to create a referral customer payment method. Each referral customer can have one primary
and one secondary payment method.

  **IMPORTANT:** Ensure all payment methods are fully verified, including any necessary verification steps, such as ACH
  micro-deposit verification for bank accounts or 3D Secure authentication for credit cards.

### Example: POST /beta/referral_customers/payment_method

#### cURL

```shell
curl -X POST https://api.easypost.com/beta/referral_customers/payment_method \
  -u "$REFERRAL_USER_API_KEY": \
  -H "Content-Type: application/json" \
  -d '{
      "payment_method": {
        "stripe_customer_id": "cus_...",
        "payment_method_reference": "card_...",
        "priority": "primary"
      }
  }'
```

#### Go

```go
package example

import (
	"fmt"

	"github.com/EasyPost/easypost-go/v5"
)

func addPaymentMethodWithCreditCard() {
	client := easypost.New("EASYPOST_API_KEY")

	paymentMethod, _ := client.BetaAddPaymentMethod("cus_...", "card_...", easypost.PrimaryPaymentMethodPriority)

	fmt.Println(paymentMethod)
}
```

#### Java

```java
package referral;

import com.easypost.exception.EasyPostException;
import com.easypost.model.PaymentMethodObject;
import com.easypost.service.EasyPostClient;

public class Create {
    public static void main(String[] args) throws EasyPostException {
        EasyPostClient client = new EasyPostClient("EASYPOST_API_KEY");

        PaymentMethodObject paymentMethod = client.betaReferralCustomer.addPaymentMethod("cus_...", "card_...");

        System.out.println(paymentMethod);
    }
}
```

#### C#

```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyPost;
using Newtonsoft.Json;

namespace EasyPostExamples
{
    public class Examples
    {
        public static async Task Main()
        {
            var client = new EasyPost.Client(new EasyPost.ClientConfiguration("EASYPOST_API_KEY"));

            EasyPost.Models.API.PaymentMethod paymentMethod = await client.Beta.ReferralCustomer.AddPaymentMethod("cus_...", "card_...", PaymentMethod.Priority.Primary);

            Console.WriteLine(JsonConvert.SerializeObject(paymentMethod, Formatting.Indented));
        }
    }
}
```

#### Node.js

```javascript
const EasyPostClient = require('@easypost/api');

const client = new EasyPostClient('EASYPOST_API_KEY');

(async () => {
  const paymentMethod = await client.BetaReferralCustomer.addPaymentMethod('cus_...', 'card_...');

  console.log(paymentMethod);
})();
```

#### PHP

```php
<?php

$client = new \EasyPost\EasyPostClient('EASYPOST_API_KEY');

$paymentMethod = $client->betaReferralCustomer->addPaymentMethod([
    'cus_...',
    'card_...',
    'primary'
]);

echo $paymentMethod;
```

#### Python

```python
import easypost

client = easypost.EasyPostClient("EASYPOST_API_KEY")

payment_method = client.beta_referral_customer.add_payment_method(
    stripe_customer_id="cus_...",
    payment_method_reference="card_...",
    primary_or_secondary="primary",
)

print(payment_method)
```

#### Ruby

```ruby
require 'easypost'

client = EasyPost::Client.new(api_key: 'EASYPOST_API_KEY')

payment_method = client.beta_referral_customer.add_payment_method(
  'cus_...',
  'card_...',
  'primary',
)

puts payment_method
```

---

## Step 2: Fund the EasyPost Wallet

`ReferralCustomer` users can deposit an initial amount into the EasyPost Wallet using EasyPost’s `POST /bank_accounts/:id/charges` or `POST /credit_cards/:id/charges`
to start using services immediately.

### Example: Add Funds

#### cURL

```shell
curl -X POST https://api.easypost.com/v2/credit_cards/card_.../charges \
  -u "EASYPOST_API_KEY": \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": "2000"
  }'
```

#### Go

```go
package example

import (
	"github.com/EasyPost/easypost-go/v5"
)

func fund() {
	client := easypost.New("EASYPOST_API_KEY")

	_ = client.FundWallet("2000", easypost.PrimaryPaymentMethodPriority)
}
```

#### Java

```java
package billing;

import com.easypost.exception.EasyPostException;
import com.easypost.model.PaymentMethod;
import com.easypost.service.EasyPostClient;

public class Fund {
    public static void main(String[] args) throws EasyPostException {
        EasyPostClient client = new EasyPostClient("EASYPOST_API_KEY");

        client.billing.fundWallet("2000", PaymentMethod.Priority.PRIMARY);
    }
}
```

#### C#

```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyPost;
using Newtonsoft.Json;

namespace EasyPostExamples
{
    public class Examples
    {
        public static async Task Main()
        {
            var client = new EasyPost.Client(new EasyPost.ClientConfiguration("EASYPOST_API_KEY"));

            await client.Billing.FundWallet("2000", PaymentMethod.Priority.Primary);
        }
    }
}
```

#### Node.js

```javascript
const EasyPostClient = require('@easypost/api');

const client = new EasyPostClient('EASYPOST_API_KEY');

(async () => {
  await client.Billing.fundWallet('2000', 'primary');
})();
```

#### PHP

```php
<?php

$client = new \EasyPost\EasyPostClient('EASYPOST_API_KEY');

$client->billing->fundWallet(2000, 'primary');
```

#### Python

```python
import easypost

client = easypost.EasyPostClient("EASYPOST_API_KEY")

client.billing.fund_wallet(
    amount="2000",
    primary_or_secondary="primary",
)
```

#### Ruby

```ruby
require 'easypost'

client = EasyPost::Client.new(api_key: 'EASYPOST_API_KEY')

client.billing.fund_wallet('2000', 'primary')
```

---

## Step 3: Configure Recharge Threshold and Recharge Amount

Once a payment method is established, EasyPost can automatically charge a `recharge_amount` if a wallet balance falls below a `recharge_threshold`. To ensure
uninterrupted service, platforms using the Decentralized white-label option should provide clear guidance on the recharge threshold and recharge amount system.

### Default Recharge Settings

- `recharge_amount` is set to $100
- `recharge_threshold` is set to zero

This means that the wallet will not automatically recharge unless the balance falls below zero. A negative balance can occur if shipment adjustments are
applied due to inaccurately specified weights, dimensions, or other shipment details.

### Handling Failed Payments

If a charge to the primary payment method fails, EasyPost will automatically attempt to charge the `ReferralCustomer`’s secondary payment method, if one
is available. To avoid service interruptions, It is recommended that `ReferralCustomers` have both a primary and secondary payment method configured.

### Customizing Recharge Settings

Forge customers can configure the `recharge_threshold`, `recharge_amount` and `secondary_recharge_amount` for a `ReferralCustomer` using EasyPost’s `PATCH /users` API.
These settings allow automatic maintenance of the wallet balance and prevent disruptions in service.

### Example: PATCH /users/:id

#### cURL

```shell
# Update the authenticated user
curl -X PATCH https://api.easypost.com/v2/users \
  -u "EASYPOST_API_KEY": \
  -H 'Content-Type: application/json' \
  -d '{
    "user": {
      "recharge_threshold": "50.00"
    }
  }'

# Update a child user
curl -X PATCH https://api.easypost.com/v2/users/user_... \
  -u "EASYPOST_API_KEY": \
  -H 'Content-Type: application/json' \
  -d '{
    "user": {
      "name": "Test Child"
    }
  }'
```

#### Go

```go
package example

import (
	"fmt"

	"github.com/EasyPost/easypost-go/v5"
)

func update() {
	client := easypost.New("EASYPOST_API_KEY")

	rechargeAmount := "50.00"

	user, _ := client.UpdateUser(
		&easypost.UserOptions{
			ID:             "user_...",
			RechargeAmount: &rechargeAmount,
		},
	)

	fmt.Println(user)
}
```

#### Java

```java
package users;

import com.easypost.exception.EasyPostException;
import com.easypost.model.User;
import com.easypost.service.EasyPostClient;

import java.util.HashMap;

public class Update {
    public static void main(String[] args) throws EasyPostException {
        EasyPostClient client = new EasyPostClient("EASYPOST_API_KEY");

        HashMap<String, Object> params = new HashMap<String, Object>();
        params.put("recharge_threshold", "50.00");

        User user = client.user.update("user_...", params);

        System.out.println(user);
    }
}
```

#### C#

```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyPost;
using Newtonsoft.Json;

namespace EasyPostExamples
{
    public class Examples
    {
        public static async Task Main()
        {
            var client = new EasyPost.Client(new EasyPost.ClientConfiguration("EASYPOST_API_KEY"));

            EasyPost.Parameters.User.Update parameters = new()
            {
                RechargeThreshold = "50.00"
            };

            EasyPost.Models.API.User user = await client.User.Update("user_...", parameters);

            Console.WriteLine(JsonConvert.SerializeObject(user, Formatting.Indented));
        }
    }
}
```

#### Node.js

```javascript
const EasyPostClient = require('@easypost/api');

const client = new EasyPostClient('EASYPOST_API_KEY');

(async () => {
  const user = await client.User.update('user_...', { recharge_threshold: '50.00' });

  console.log(user);
})();
```

#### PHP

```php
<?php

$client = new \EasyPost\EasyPostClient('EASYPOST_API_KEY');

$user = $client->user->update(
    'user_...',
    ['recharge_threshold' => '50.00']
);

echo $user;
```

#### Python

```python
import easypost

client = easypost.EasyPostClient("EASYPOST_API_KEY")

user = client.user.retrieve_me()

updated_user = client.user.update(user.id, recharge_threshold="50.00")

print(updated_user)
```

#### Ruby

```ruby
require 'easypost'

client = EasyPost::Client.new(api_key: 'EASYPOST_API_KEY')

retrieved_user = client.user.retrieve_me

user = client.user.update(retrieved_user.id, recharge_amount: '50.00')

puts user
```

---

## ReferralCustomer Carrier Account Management

Upon creation, the `ReferralCustomer` user automatically receives access to several EasyPost-Powered Carrier Accounts, which are billed through the platforms’ wallet.

To add additional carrier accounts for a `ReferralCustomer` user, one of the following options can be used:

- **API Integration:** Use the Carrier Account API with the `ReferralCustomer` user’s Production API Key of the sub account to integrate additional carriers.
- **Forge Dashboard:** Manually add carriers through the Carriers section of the Forge Dashboard.

Related:

- [Carrier Management](https://support.easypost.com/hc/en-us/sections/34550349817869-Carrier-Management)

---

## ReferralCustomer Shipment Creation

Creating shipments for `ReferralCustomer` users follows the same process as Parent Users, with key differences being the requirement to use the `ReferralCustomer` user’s API Keys.

A `Shipment Object` consists of:

- A valid `to_address` and `from_address`
- A `parcel` with shipping details
- Any required `forms` for international deliveries

Once a `shipment` is created, a `Shipment Object` is used to retrieve shipping rates and purchase a label.

### Advanced Shipping

Platforms may optionally enable Advanced Shipping, a white-labeled shipping interface that allows sub-accounts to purchase labels and manage
shipments through a hosted experience.

When Advanced Shipping is used with the Decentralized (EasyPost-Managed Billing) option, shipments and billing continue to be processed through the
ReferralCustomer's wallet and carrier configuration.

---

## Additional Resources

Please visit the Help Center for more information.