# Luma

The Luma API enables shippers to buy labels, leveraging the rate shopping rules configured within the EasyPost Dashboard.
By using predefined rulesets, Luma automates the rate selection process based on criteria such as transit time, cost, carrier preferences, and delivery confidence levels.

Luma supports two methods for purchasing shipments:

- One-Call Buy: Use `POST /shipments/luma` to create and purchase a shipment in a
  single request. This method is ideal for shippers with established rulesets who want to reduce API calls.
- Standard Buy: Create a shipment using `POST /shipments`, then call `POST
  /shipments/:id/luma` to evaluate the rates against the Luma ruleset and purchase the label. This method is ideal for
  shippers that are doing rating (creating a shipment) first, and then want to rate shop with Luma and buy a label.

---

## Define Business Rulesets

Before using the Luma API, rate shopping rules must be defined in the EasyPost Dashboard. These rules determine how rates are
selected based on specific criteria. Work with an EasyPost Luma contact to configure rulesets that may include:

- **Days in Transit:** Maximum number of transit days desired.
- **Confidence:** Confidence level for delivery within the specified Days in Transit.
- **Maximum Cost:** Maximum dollar amount allowed for the shipment.
- **Included Carriers:** Array of carriers eligible for selection.

---

## Luma Promise

### Example: POST /luma/promise

#### cURL

```shell
curl -X POST 'https://api.easypost.com/v2/luma/promise' \
  -u "EASYPOST_API_KEY": \
  -H 'Content-Type: application/json' \
  -d '{
     "shipment": {
      "to_address": {
        "name": "Dr. Steve Brule",
        "street1": "5744 Silverton Ave",
        "city": "McKinney",
        "state": "TX",
        "zip": "75070",
        "country": "US",
        "phone": "8573875756",
        "email": "dr_steve_brule@gmail.com"
      },
      "from_address": {
        "name": "EasyPost",
        "street1": "417 Montgomery Street",
        "street2": "5th Floor",
        "city": "San Francisco",
        "state": "CA",
        "zip": "94104",
        "country": "US",
        "phone": "4153334445",
        "email": "support@easypost.com"
      },
      "parcel": {
        "length": "20.2",
        "width": "10.9",
        "height": "5",
        "weight": "65.9"
      },
      "ruleset_name": "ruleset_...",
      "planned_ship_date": "2025-07-03",
      "deliver_by_date": "2025-07-06"
    }
  }'
```

#### Go

```go
package example

import (
	"fmt"

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

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

	lumaRequest := &easypost.LumaRequest{
		Shipment: easypost.Shipment{
			Parcel: &easypost.Parcel{
				Length: 20.2,
				Width:  10.9,
				Height: 5,
				Weight: 65.9,
			},
			ToAddress: &easypost.Address{
				Name:    "Dr. Steve Brule",
				Street1: "179 N Harbor Dr",
				City:    "Redondo Beach",
				State:   "CA",
				Zip:     "90277",
				Country: "US",
				Phone:   "4155559999",
				Email:   "dr_steve_brule@gmail.com",
			},
			FromAddress: &easypost.Address{
				Name:    "EasyPost",
				Street1: "417 Montgomery Street",
				Street2: "5th Floor",
				City:    "San Francisco",
				State:   "CA",
				Zip:     "90277",
				Country: "US",
				Phone:   "4155559999",
				Email:   "support@easypost.com",
			},
		},
		RulesetName:     "ruleset_...",
		PlannedShipDate: "2025-07-21",
		DeliverByDate:   "2025-07-25",
		PersistLabel:    false,
	}

	lumaInfo, _ := client.GetLumaPromise(lumaRequest)

	fmt.Println(lumaInfo)
}
```

#### Java

```java
package shipments;

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

import java.util.HashMap;

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

        HashMap<String, Object> toAddress = new HashMap<String, Object>();
        toAddress.put("name", "Dr. Steve Brule");
        toAddress.put("street1", "5744 Silverton Ave");
        toAddress.put("city", "McKinney");
        toAddress.put("state", "TX");
        toAddress.put("zip", "75070");
        toAddress.put("country", "US");
        toAddress.put("phone", "8573875756");
        toAddress.put("email", "dr_steve_brule@gmail.com");

        HashMap<String, Object> fromAddress = new HashMap<String, Object>();
        fromAddress.put("name", "EasyPost");
        fromAddress.put("street1", "417 Montgomery Street");
        fromAddress.put("street2", "5th Floor");
        fromAddress.put("city", "San Francisco");
        fromAddress.put("state", "CA");
        fromAddress.put("zip", "94104");
        fromAddress.put("country", "US");
        fromAddress.put("phone", "4153334445");
        fromAddress.put("email", "support@easypost.com");

        HashMap<String, Object> parcel = new HashMap<String, Object>();
        parcel.put("length", 20.2);
        parcel.put("width", 10.9);
        parcel.put("height", 5.0);
        parcel.put("weight", 65.9);

        HashMap<String, Object> shipment = new HashMap<String, Object>();
        shipment.put("to_address", toAddress);
        shipment.put("from_address", fromAddress);
        shipment.put("parcel", parcel);
        shipment.put("ruleset_name", "ruleset_...");
        shipment.put("planned_ship_date", "2025-05-22");
        shipment.put("deliver_by_date", "2025-05-29");

        LumaInfo lumaInfo = client.luma.getPromise(shipment);

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

#### 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.Luma.GetPromise parameters = new()
            {
                ToAddress = new EasyPost.Parameters.Address.Create
                {
                    Name = "Dr. Steve Brule",
                    Street1 = "5744 Silverton Ave",
                    City = "McKinney",
                    State = "TX",
                    Zip = "75070",
                    Country = "US",
                    Phone = "8573875756",
                    Email = "dr_steve_brule@gmail.com"
                },
                FromAddress = new EasyPost.Parameters.Address.Create
                {
                    Name = "EasyPost",
                    Street1 = "417 Montgomery Street",
                    Street2 = "5th Floor",
                    City = "San Francisco",
                    State = "CA",
                    Zip = "94104",
                    Country = "US",
                    Phone = "4153334445",
                    Email = "support@easypost.com"
                },
                Parcel = new EasyPost.Parameters.Parcel.Create
                {
                    Length = 20.2,
                    Width = 10.9,
                    Height = 5,
                    Weight = 65.9
                },
                RulesetName = "ruleset_...",
                PlannedShipDate = "2025-07-18",
                DeliverByDate = "2025-07-20"
            };

            EasyPost.Models.API.LumaInfo lumaInfo = await client.Luma.GetPromise(parameters);

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

#### Node.js

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

const client = new EasyPost('EASYPOST_API_KEY');

(async () => {
  const toAddress = {
    name: 'Dr. Steve Brule',
    street1: '5744 Silverton Ave',
    city: 'McKinney',
    state: 'TX',
    zip: '75070',
    country: 'US',
    phone: '8573875756',
    email: 'dr_steve_brule@gmail.com',
  };
  const fromAddress = {
    name: 'EasyPost',
    street1: '417 Montgomery Street',
    street2: '5th Floor',
    city: 'San Francisco',
    state: 'CA',
    zip: '94104',
    country: 'US',
    phone: '4153334445',
    email: 'support@easypost.com',
  };
  const parcel = {
    length: 20.2,
    width: 10.9,
    height: 5,
    weight: 65.9,
  };
  const params = {
    to_address: toAddress,
    from_address: fromAddress,
    parcel,
    ruleset_name: 'ruleset_...',
    planned_ship_date: '2025-07-18',
    deliver_by_date: '2025-07-20',
  };

  const promise = await client.Luma.promise(params);

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

#### PHP

```php
<?php

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

$lumaPromise = $client->shipment->lumaPromise([
    'shipment' => [
        'to_address' => [
            'name' => 'Dr. Steve Brule',
            'street1' => '5744 Silverton Ave',
            'city' => 'McKinney',
            'state' => 'TX',
            'zip' => '75070',
            'country' => 'US',
            'phone' => '8573875756',
            'email' => 'dr_steve_brule@gmail.com'
        ],
        'from_address' => [
            'name' => 'EasyPost',
            'street1' => '417 Montgomery Street',
            'street2' => '5th Floor',
            'city' => 'San Francisco',
            'state' => 'CA',
            'zip' => '94104',
            'country' => 'US',
            'phone' => '4153334445',
            'email' => 'support@easypost.com'
        ],
        'parcel' => [
            'length' => 20.2,
            'width' => 10.9,
            'height' => 5,
            'weight' => 65.9
        ],
        'ruleset_name' => 'ruleset_...',
        'planned_ship_date' => '2025-07-18',
        'deliver_by_date' => '2025-07-20'
    ]
]);

echo $lumaPromise;
```

#### Python

```python
import easypost

client = easypost.EasyPostClient("EASYPOST_API_KEY")

shipment = client.luma.get_promise(
    to_address={
        "name": "Dr. Steve Brule",
        "street1": "5744 Silverton Ave",
        "city": "McKinney",
        "state": "TX",
        "zip": "75070",
        "country": "US",
        "phone": "8573875756",
        "email": "dr_steve_brule@gmail.com",
    },
    from_address={
        "name": "EasyPost",
        "street1": "417 Montgomery Street",
        "street2": "5th Floor",
        "city": "San Francisco",
        "state": "CA",
        "zip": "94104",
        "country": "US",
        "phone": "4153334445",
        "email": "support@easypost.com",
    },
    parcel={
        "length": 20.2,
        "width": 10.9,
        "height": 5,
        "weight": 65.9,
    },
    ruleset_name="ruleset_...",
    planned_ship_date="2025-07-24",
    deliver_by_date="2025-07-26",
)

print(shipment)
```

#### Ruby

```ruby
# frozen_string_literal: true

require 'easypost'

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

shipment = client.luma.get_promise(
  to_address: {
    name: 'Dr. Steve Brule',
    street1: '5744 Silverton Ave',
    city: 'McKinney',
    state: 'TX',
    zip: '75070',
    country: 'US',
    phone: '8573875756',
    email: 'dr_steve_brule@gmail.com',
  },
  from_address: {
    name: 'EasyPost',
    street1: '417 Montgomery Street',
    street2: '5th Floor',
    city: 'San Francisco',
    state: 'CA',
    zip: '94104',
    country: 'US',
    phone: '4153334445',
    email: 'support@easypost.com',
  },
  parcel: {
    length: 20.2,
    width: 10.9,
    height: 5,
    weight: 65.9,
  },
  ruleset_name: 'ruleset_...',
  planned_ship_date: '2025-07-16',
  deliver_by_date: '2025-07-18',
)

puts shipment
```

The Luma Promise endpoint evaluates rate options and returns a `predicted_deliver_by_date` and the selected rate without requiring a label purchase.
This endpoint is designed for rating-only scenarios, such as displaying estimated delivery windows for customers. It supports predefined rulesets
and enables evaluation without incurring label charges.

---

## One-Call Buy

### Example: POST /shipments/luma

#### cURL

```shell
curl -X POST https://api.easypost.com/v2/shipments/luma \
  -u "EASYPOST_API_KEY": \
  -H 'Content-Type: application/json' \
  -d '{
    "shipment": {
      "to_address": {
        "name": "Dr. Steve Brule",
        "street1": "5744 Silverton Ave",
        "city": "McKinney",
        "state": "TX",
        "zip": "75070",
        "country": "US",
        "phone": "8573875756",
        "email": "dr_steve_brule@gmail.com"
      },
      "from_address": {
        "name": "EasyPost",
        "street1": "417 Montgomery Street",
        "street2": "5th Floor",
        "city": "San Francisco",
        "state": "CA",
        "zip": "94104",
        "country": "US",
        "phone": "4153334445",
        "email": "support@easypost.com"
      },
      "parcel": {
        "length": "20.2",
        "width": "10.9",
        "height": "5",
        "weight": "65.9"
      },
      "carrier_accounts": ["ca_..."],
      "ruleset_name": "ruleset_...",
      "planned_ship_date": "2025-05-14",
      "deliver_by_date": "2025-05-16"
    }
  }'
```

#### Go

```go
package example

import (
	"fmt"

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

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

	lumaRequest := &easypost.LumaRequest{
		Shipment: easypost.Shipment{
			CarrierAccountIDs: []string{"ca_..."},
			Parcel: &easypost.Parcel{
				Length: 20.2,
				Width:  10.9,
				Height: 5,
				Weight: 65.9,
			},
			ToAddress: &easypost.Address{
				Name:    "Dr. Steve Brule",
				Street1: "179 N Harbor Dr",
				City:    "Redondo Beach",
				State:   "CA",
				Zip:     "90277",
				Country: "US",
				Phone:   "4155559999",
				Email:   "dr_steve_brule@gmail.com",
			},
			FromAddress: &easypost.Address{
				Name:    "EasyPost",
				Street1: "417 Montgomery Street",
				Street2: "5th Floor",
				City:    "San Francisco",
				State:   "CA",
				Zip:     "90277",
				Country: "US",
				Phone:   "4155559999",
				Email:   "support@easypost.com",
			},
		},
		RulesetName:     "ruleset_...",
		PlannedShipDate: "2025-07-21",
		DeliverByDate:   "2025-07-25",
	}

	shipment, _ := client.CreateAndBuyLumaShipment(lumaRequest)

	fmt.Println(shipment)
}
```

#### Java

```java
package shipments;

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

import java.util.HashMap;

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

        HashMap<String, Object> toAddressMap = new HashMap<String, Object>();
        toAddressMap.put("name", "Dr. Steve Brule");
        toAddressMap.put("street1", "5744 Silverton Ave");
        toAddressMap.put("city", "McKinney");
        toAddressMap.put("state", "TX");
        toAddressMap.put("zip", "75070");
        toAddressMap.put("country", "US");
        toAddressMap.put("phone", "8573875756");
        toAddressMap.put("email", "dr_steve_brule@gmail.com");

        HashMap<String, Object> fromAddressMap = new HashMap<String, Object>();
        fromAddressMap.put("name", "EasyPost");
        fromAddressMap.put("street1", "417 Montgomery Street");
        fromAddressMap.put("street2", "5th Floor");
        fromAddressMap.put("city", "San Francisco");
        fromAddressMap.put("state", "CA");
        fromAddressMap.put("zip", "94104");
        fromAddressMap.put("country", "US");
        fromAddressMap.put("phone", "4153334445");
        fromAddressMap.put("email", "support@easypost.com");

        HashMap<String, Object> parcelMap = new HashMap<String, Object>();
        parcelMap.put("length", 20.2);
        parcelMap.put("width", 10.9);
        parcelMap.put("height", 5);
        parcelMap.put("weight", 65.9);

        HashMap<String, Object> params = new HashMap<String, Object>();
        params.put("to_address", toAddressMap);
        params.put("from_address", fromAddressMap);
        params.put("parcel", parcelMap);
        params.put("carrier_accounts", "ca_...");
        params.put("ruleset_name", "ruleset_...");
        params.put("planned_ship_date", "2025-07-18");
        params.put("deliver_by_date", "2025-07-20");

        Shipment shipment = client.shipment.createLuma(params);

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

#### 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.Shipment.Create parameters = new()
            {
                ToAddress = new EasyPost.Parameters.Address.Create
                {
                    Name = "Dr. Steve Brule",
                    Street1 = "5744 Silverton Ave",
                    City = "McKinney",
                    State = "TX",
                    Zip = "75070",
                    Country = "US",
                    Phone = "8573875756",
                    Email = "dr_steve_brule@gmail.com"
                },
                FromAddress = new EasyPost.Parameters.Address.Create
                {
                    Name = "EasyPost",
                    Street1 = "417 Montgomery Street",
                    Street2 = "5th Floor",
                    City = "San Francisco",
                    State = "CA",
                    Zip = "94104",
                    Country = "US",
                    Phone = "4153334445",
                    Email = "support@easypost.com"
                },
                Parcel = new EasyPost.Parameters.Parcel.Create
                {
                    Length = 20.2,
                    Width = 10.9,
                    Height = 5,
                    Weight = 65.9
                },
                CarrierAccountIds = new List<string> { "ca_..." },
                RulesetName = "ruleset_...",
                PlannedShipDate = "2025-07-18",
                DeliverByDate = "2025-07-20"
            };

            EasyPost.Models.API.Shipment shipment = await client.Shipment.CreateAndBuyLuma(parameters);

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

#### Node.js

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

const client = new EasyPost('EASYPOST_API_KEY');

(async () => {
  const shipment = await client.Luma.createAndBuyLuma({
    carrier_accounts: ['ca_...'],
    to_address: {
      name: 'Dr. Steve Brule',
      street1: '5744 Silverton Ave',
      city: 'McKinney',
      state: 'TX',
      zip: '75070',
      country: 'US',
      phone: '8573875756',
      email: 'dr_steve_brule@gmail.com',
    },
    from_address: {
      name: 'EasyPost',
      street1: '417 Montgomery Street',
      street2: '5th Floor',
      city: 'San Francisco',
      state: 'CA',
      zip: '94104',
      country: 'US',
      phone: '4153334445',
      email: 'support@easypost.com',
    },
    parcel: {
      length: 20.2,
      width: 10.9,
      height: 5,
      weight: 65.9,
    },

    ruleset_name: 'ruleset_...',
    planned_ship_date: '2025-07-24',
    deliver_by_date: '2025-07-26',
  });

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

#### PHP

```php
<?php

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

$shipment = $client->shipment->create([
    'carrier_accounts' => ['ca_...'],
    'to_address' => [
        'name' => 'Dr. Steve Brule',
        'street1' => '5744 Silverton Ave',
        'city' => 'McKinney',
        'state' => 'TX',
        'zip' => '75070',
        'country' => 'US',
        'phone' => '8573875756',
        'email' => 'dr_steve_brule@gmail.com'
    ],
    'from_address' => [
        'name' => 'EasyPost',
        'street1' => '417 Montgomery Street',
        'street2' => '5th Floor',
        'city' => 'San Francisco',
        'state' => 'CA',
        'zip' => '94104',
        'country' => 'US',
        'phone' => '4153334445',
        'email' => 'support@easypost.com'
    ],
    'parcel' => [
        'length' => 20.2,
        'width' => 10.9,
        'height' => 5,
        'weight' => 65.9
    ],
    'ruleset_name' => 'ruleset_...',
    'planned_ship_date' => '2025-07-18',
    'deliver_by_date' => '2025-07-20'
]);

echo $shipment;
```

#### Python

```python
import easypost

client = easypost.EasyPostClient("EASYPOST_API_KEY")

shipment = client.shipment.create_and_buy_luma(
    carrier_accounts=["ca_..."],
    to_address={
        "name": "Dr. Steve Brule",
        "street1": "5744 Silverton Ave",
        "city": "McKinney",
        "state": "TX",
        "zip": "75070",
        "country": "US",
        "phone": "8573875756",
        "email": "dr_steve_brule@gmail.com",
    },
    from_address={
        "name": "EasyPost",
        "street1": "417 Montgomery Street",
        "street2": "5th Floor",
        "city": "San Francisco",
        "state": "CA",
        "zip": "94104",
        "country": "US",
        "phone": "4153334445",
        "email": "support@easypost.com",
    },
    parcel={
        "length": 20.2,
        "width": 10.9,
        "height": 5,
        "weight": 65.9,
    },
    ruleset_name="ruleset_...",
    planned_ship_date="2025-07-24",
    deliver_by_date="2025-07-26",
)

print(shipment)
```

#### Ruby

```ruby
# frozen_string_literal: true

require 'easypost'

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

shipment = client.shipment.create_and_buy_luma(
  to_address: {
    name: 'Dr. Steve Brule',
    street1: '5744 Silverton Ave',
    city: 'McKinney',
    state: 'TX',
    zip: '75070',
    country: 'US',
    phone: '8573875756',
    email: 'dr_steve_brule@gmail.com',
  },
  from_address: {
    name: 'EasyPost',
    street1: '417 Montgomery Street',
    street2: '5th Floor',
    city: 'San Francisco',
    state: 'CA',
    zip: '94104',
    country: 'US',
    phone: '4153334445',
    email: 'support@easypost.com',
  },
  parcel: {
    length: 20.2,
    width: 10.9,
    height: 5,
    weight: 65.9,
  },
  carrier_accounts: ['ca_...'],
  ruleset_name: 'ruleset_...',
  planned_ship_date: '2025-07-16',
  deliver_by_date: '2025-07-18',
)

puts shipment
```

The Luma One-Call Buy endpoint enables live rating, time in transit predictions, rate shopping, and label purchase in a single API call using a predefined Luma ruleset.

The response is similar to the standard `/shipments` buy response, with the addition of a `luma_info` object that provides a detailed breakdown of the ruleset evaluation results.

See Luma Info Object for a breakdown of the response structure.

Insurance may be added at the time of purchase by including the `insurance` attribute within the `shipment` object as a string. All insurance
values must be in U.S. dollars (USD).

---

## Standard Buy

### Example: POST /shipments/:id/luma

#### cURL

```shell
curl -X POST https://api.easypost.com/v2/shipments/shp_.../luma \
  -u "EASYPOST_API_KEY": \
  -H 'Content-Type: application/json' \
  -d '{
    "ruleset_name": ""ruleset_..."",
    "planned_ship_date": "YYYY-MM-DD",
    "deliver_by_date": "YYYY-MM-DD"
  }'
```

#### Go

```go
package example

import (
	"fmt"

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

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

	shipment, _ := client.GetShipment("shp_...")
	lumaRequest := &easypost.LumaRequest{
		Shipment:        easypost.Shipment{ID: shipment.ID},
		RulesetName:     "ruleset_...",
		PlannedShipDate: "2025-07-21",
		DeliverByDate:   "2025-07-25",
		PersistLabel:    false,
	}

	shipment, _ = client.BuyLumaShipment(shipment.ID, lumaRequest)

	fmt.Println(shipment)
}
```

#### Java

```java
package luma;

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

import java.util.HashMap;

public class BuyLuma {
    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("ruleset_name", "ruleset_...");
        params.put("planned_ship_date", "2025-07-18");
        params.put("deliver_by_date", "2025-07-20");

        Shipment shipment = client.shipment.luma("shp_...", params);

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

#### 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.Shipment shipment = await client.Shipment.Retrieve("shp_...");

            shipment = await client.Shipment.BuyLuma(
                "shp_...",
                rulesetName: "ruleset_...",
                plannedShipDate: "2025-07-18",
                deliverByDate: "2025-07-20"
            );

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

#### Node.js

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

const client = new EasyPost('EASYPOST_API_KEY');

(async () => {
  const params = {
    ruleset_name: 'ruleset_...',
    planned_ship_date: '2025-07-18',
    deliver_by_date: '2025-07-20',
  };

  const shipment = await client.Luma.buyLuma('shp_...', params);

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

#### PHP

```php
<?php

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

$shipment = $client->shipment->luma('shp_...', [
    'ruleset_name' => 'ruleset_...',
    'planned_ship_date' => '2025-07-18',
    'deliver_by_date' => '2025-07-20'
]);

echo $shipment;
```

#### Python

```python
import easypost

client = easypost.EasyPostClient("EASYPOST_API_KEY")

shipment = client.shipment.buy_luma(
    "shp_...",
    ruleset_name="ruleset_...",
    planned_ship_date="2025-07-24",
    deliver_by_date="2025-07-26",
)

print(shipment)
```

#### Ruby

```ruby
# frozen_string_literal: true

require 'easypost'

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

retrieved_shipment = client.shipment.retrieve('shp_...')

shipment = client.shipment.buy_luma(
  retrieved_shipment.id,
  ruleset_name: 'ruleset_...',
  planned_ship_date: '2025-07-16',
  deliver_by_date: '2025-07-18',
)

puts shipment
```

A shipment object must be created with the following details before calling the Luma Standard Buy API:

- `from_address`: The origin address.
- `to_address`: The destination address.
- `parcel`: Package weight, dimensions, and other relevant information.

This step returns all available carrier rates associated with the EasyPost account.

After creating the shipment, pass the `shipment_id` into the Luma API to purchase a label based on the predefined ruleset.

---

## LumaInfo Object

The response includes standard shipment purchase details and a `luma_info` object that outlines the ruleset logic used to select the final rate.

| Property | Type | Description |
|----------|------|-------------|
| ruleset_description | string | Describes the logic used to select the rate. |
| matching_rule_idx | integer | The index position of the applied rule within the ruleset (starting from 0). |
| ai_results | array | List of all fetched rates and their evaluation against the ruleset |
| ai_results[].carrier | string | Carrier associated with the rate (e.g., USPS, FedEx). |
| ai_results[].service | string | Carrier service level used for the rate (e.g., Express, Ground). |
| ai_results[].rate_id | string | The ID of the specific rate. |
| ai_results[].rate_usd | string | Total cost of the rate in USD |
| ai_results[].predicted_deliver_by_date | string | Date the SmartRate AI predicts the package will be delivered. |
| ai_results[].predicted_deliver_days | integer | Number of calendar days SmartRate AI predicts for delivery, factoring in weekends and carrier operations |
| ai_results[].meets_ruleset_requirements | boolean | Indicates whether the rate meets the ruleset's transit time, cost, and carrier conditions. |

Example Object:

```json
{
  "luma_info": {
    "ai_results": [
      {
        "carrier": "USPS",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-11",
        "predicted_deliver_days": 5,
        "rate_id": "rate_878246b64dfc4acdaae144632071ebbf",
        "rate_usd": "135.45",
        "service": "Express"
      },
      {
        "carrier": "USPS",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-12",
        "predicted_deliver_days": 6,
        "rate_id": "rate_c5ea42853ee34db5a3b739a30c1d1e7d",
        "rate_usd": "41.44",
        "service": "Priority"
      },
      {
        "carrier": "USPS",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-13",
        "predicted_deliver_days": 7,
        "rate_id": "rate_3041c849fcfb4eca8e7140ce8ac68ac2",
        "rate_usd": "23.85",
        "service": "GroundAdvantage"
      },
      {
        "carrier": "UPSDAP",
        "meets_ruleset_requirements": true,
        "predicted_deliver_by_date": "2025-02-07",
        "predicted_deliver_days": 1,
        "rate_id": "rate_ecc1a08e97e349dc83645663e02e8ce6",
        "rate_usd": "94.45",
        "service": "NextDayAir"
      },
      {
        "carrier": "UPSDAP",
        "meets_ruleset_requirements": true,
        "predicted_deliver_by_date": "2025-02-10",
        "predicted_deliver_days": 4,
        "rate_id": "rate_9de47a58578943f692779ba1ef649db0",
        "rate_usd": "124.45",
        "service": "NextDayAirEarlyAM"
      },
      {
        "carrier": "UPSDAP",
        "meets_ruleset_requirements": true,
        "predicted_deliver_by_date": "2025-02-10",
        "predicted_deliver_days": 4,
        "rate_id": "rate_3a017a1f045a44088baba60cacaacae4",
        "rate_usd": "87.91",
        "service": "NextDayAirSaver"
      },
      {
        "carrier": "UPSDAP",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-11",
        "predicted_deliver_days": 5,
        "rate_id": "rate_5c552ee17b764ebe8b3e040e23acc161",
        "rate_usd": "52.98",
        "service": "2ndDayAir"
      },
      {
        "carrier": "UPSDAP",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-11",
        "predicted_deliver_days": 5,
        "rate_id": "rate_00697bb80a6a4690a4adc1fa821d0549",
        "rate_usd": "60.79",
        "service": "2ndDayAirAM"
      },
      {
        "carrier": "UPSDAP",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-12",
        "predicted_deliver_days": 6,
        "rate_id": "rate_8d6d3b28b62d43e8bf137f7f63588807",
        "rate_usd": "38.19",
        "service": "3DaySelect"
      },
      {
        "carrier": "UPSDAP",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-14",
        "predicted_deliver_days": 8,
        "rate_id": "rate_ec4000010aa74083bcf7af34d77cd69f",
        "rate_usd": "24.02",
        "service": "Ground"
      },
      {
        "carrier": "FedExDefault",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-15",
        "predicted_deliver_days": 9,
        "rate_id": "rate_81be930fa6824faa9f75ce474db8c329",
        "rate_usd": "47.99",
        "service": "SMART_POST"
      },
      {
        "carrier": "FedExDefault",
        "meets_ruleset_requirements": true,
        "predicted_deliver_by_date": "2025-02-10",
        "predicted_deliver_days": 4,
        "rate_id": "rate_8c590b2c9f9f42fa8986b19e0180d5bd",
        "rate_usd": "289.00",
        "service": "PRIORITY_OVERNIGHT"
      },
      {
        "carrier": "FedExDefault",
        "meets_ruleset_requirements": true,
        "predicted_deliver_by_date": "2025-02-10",
        "predicted_deliver_days": 4,
        "rate_id": "rate_f6cba61f30714f7fb779b7b157c0c619",
        "rate_usd": "264.87",
        "service": "STANDARD_OVERNIGHT"
      },
      {
        "carrier": "FedExDefault",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-11",
        "predicted_deliver_days": 5,
        "rate_id": "rate_9a64fd048d644d8daaece83c92b49ae8",
        "rate_usd": "202.16",
        "service": "FEDEX_2_DAY_AM"
      },
      {
        "carrier": "FedExDefault",
        "meets_ruleset_requirements": false,
        "predicted_deliver_by_date": "2025-02-13",
        "predicted_deliver_days": 7,
        "rate_id": "rate_4fb6b986d5e242b39dcfd47bff29b74d",
        "rate_usd": "36.75",
        "service": "FEDEX_GROUND"
      }
    ],
    "matching_rule_idx": 0,
    "ruleset_description": "Buy the cheapest rate that satisfies all of the following:\nRule 0\n        - Deliver by user input day of deliver_by_date    - Transit day confidence >= 90\nOtherwise buy the cheapest rate"
  }
}
```

---

## Testing the Luma API

To test the Luma API without incurring charges:

- Use the **Test API Key** to execute the same buying logic on test shipments.
- This test environment mirrors production logic, returning the rate that would be selected based on the chosen ruleset.

For more details on Luma, refer to the Luma section of the EasyPost Help Center.