# Creating a Storefront App

Let's set up our Firmhouse project before we begin. You can find step-by-step instructions [here](https://help.firmhouse.com/en/collections/2489064-setting-up-your-project) to configure your project. Below is a list of things you should complete before we start:

* Create products. You can follow [this guide](https://help.firmhouse.com/en/articles/3577845-configuring-products).
* If your project type is Product-as-a-service, Create at least one Plan to use as your default plan. You can follow [this guide](https://help.firmhouse.com/en/articles/3278043-setting-up-plans).
* Set up a payment provider.
* Generate a Project Access Token by going to the ***Settings > Integrations*** page. For this tutorial a token with `Storefront` access type will be sufficient.

### Fetching products

To display the products, you need to use the [`products` ](https://developer.firmhouse.com/graphql-api/api-reference/queries/products)query. This query gives you all the information about the products you have set up in the Firmhouse Portal.

{% tabs %}
{% tab title="JavaScript" %}
{% code overflow="wrap" %}

```javascript
const projectAccessToken = '<Your-project-access-token>'
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': projectAccessToken
})
const graphql = JSON.stringify({
    query: `query products($after: String, $first: Int){
    products(after: $after, first: $first) {
        totalCount
        pageInfo {
            endCursor
            hasNextPage
            hasPreviousPage
            startCursor
        }
        nodes {
            available
            eligibleForDiscount
            graceCancellationEnabled
            graceCancellationPeriod
            graceCancellationUnit
            id
            imageUrl
            interval
            intervalUnitOfMeasure
            mandatory
            maximumCommitmentEnabled
            maximumCommitmentPeriod
            maximumCommitmentUnit
            metadata
            minimumCommitmentEnabled
            minimumCommitmentPeriod
            minimumCommitmentUnit
            nthProductFree
            priceCents
            priceExcludingTaxCents
            priceWithSymbol
            productType
            shopifyProductId
            shopifyVariantId
            sku
            slug
            supplier
            taxAmountCents
            taxPercentage
            title
        }
    }
}
`,
    variables: {
        after: null,
        first: 10
    }
})
const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const data = await response.json()
const {totalCount, nodes: products, pageInfo}  = data.data.products

```

{% endcode %}
{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
const response = await firmhouseClient.products.fetchAll({
    first: pageSize,
    after: endCursor,
});
const { total: totalCount, results: products, pageInfo} = response;
```

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

{% hint style="info" %}
You can use <mark style="color:blue;">`after`</mark> and <mark style="color:blue;">`first`</mark> parameters to implement pagination. `after` variable expects a cursor which you can get from <mark style="color:blue;">`pageInfo.endCursor`</mark> value from previous call.
{% endhint %}

### Fetching Plans

{% tabs %}
{% tab title="JavaScript" %}
If your project's subscription type is Product as Service, you can use the [plans ](https://developer.firmhouse.com/graphql-api/api-reference/queries/plans)query. This query gives you all the information about the plans you have set up in the Firmhouse Portal.

{% code overflow="wrap" %}

```
```

{% endcode %}

```javascript
const projectAccessToken = '<Your-project-access-token>'
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': projectAccessToken
})
const graphql = JSON.stringify({
    query: `query plans($after: String, $first: Int){
    plans(after: $after, first: $first) {
        totalCount
        nodes {
            available
            currency
            graceCancellationEnabled
            graceCancellationPeriod
            graceCancellationUnit
            id
            imageUrl
            initialAmountExcludingTaxCents
            initialAmountIncludingTaxCents
            instalmentIntervalPeriod
            instalmentIntervalUnit
            instalments
            maximumCommitmentEnabled
            maximumCommitmentPeriod
            maximumCommitmentUnit
            metadata
            minimumCommitmentEnabled
            minimumCommitmentPeriod
            minimumCommitmentUnit
            monthlyAmountCents
            monthlyAmountExcludingTaxCents
            monthlyAmountIncludingTaxCents
            name
            slug
            taxAmountCents
            taxPercentage
            planProducts {
                quantity
                product {
                    id
                }
            }
        }
        pageInfo {
            endCursor
            hasNextPage
            hasPreviousPage
            startCursor
        }
    }
}
`,
variables: {
  after: null,
 first: 10
}
})
const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const data = await response.json()
const {totalCount, nodes: plans, pageInfo}  = data.data.plans
```

{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
const response = await firmhouseClient.plans.fetchAll({
    first: pageSize,
    after: endCursor,
});
const { total: totalCount, results: plans, pageInfo} = response;
```

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

### Creating a cart

To start ordering products, you need to create a cart with [`createCart`](https://developer.firmhouse.com/graphql-api/api-reference/mutations/create-cart) mutation.

{% tabs %}
{% tab title="JavaScript" %}
{% code overflow="wrap" %}

```javascript
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': projectAccessToken
})
const graphql = JSON.stringify({
    query: `mutation {
    createCart(input: {}){
        subscription {
            token
        }
    }
}
`
})
const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const body = await response.json()
const subscriptionToken = body.data.createCart.subscription.token

```

{% endcode %}

{% hint style="info" %}
We will pass the value of <mark style="color:blue;">`subscriptionToken`</mark> in the `X-Subscription-Token` header for all subsequent calls. If you are creating a web app, you can store this value in a cookie or localStorage so that your customers can pick up where they left off when they return.
{% endhint %}
{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
const existingSubscriptionToken = localStorage.getItem('subscriptionToken') ?? undefined;
// const existingSubscriptionToken = cookies().get('subscriptionToken')?.value ?? undefined;
const response = await firmhouseClient.carts.getOrCreate(existingSubscriptionToken)
const { token: subscriptionToken } = response;
localStorage.setItem('subscriptionToken', subscriptionToken);
// cookies().set('subscriptionToken', subscriptionToken);
```

{% endcode %}

{% hint style="info" %}
We will pass the value of <mark style="color:blue;">`token`</mark> as a parameter for all subsequent calls. If you are creating a web app, you can store this value in a cookie or localStorage as shown in the example so that your customers can pick up where they left off when they return. `getOrCreate` method will return the existing cart if the token is provided and the cart has not been checked out yet, otherwise it will create a new cart.
{% endhint %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Note that, if the default plan of your project includes products, they will be automatically added to the cart when you create it.
{% endhint %}

### Adding products to the cart

Once the cart is created, you can start adding items to it with [`createOrderedProduct`](https://developer.firmhouse.com/graphql-api/api-reference/mutations/create-ordered-product) mutation. Note that we're using the <mark style="color:blue;">`subscriptionToken`</mark> value in `X-Subscription-Token` header.

{% tabs %}
{% tab title="JavaScript" %}
{% code overflow="wrap" %}

```javascript
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': token,
    'X-Subscription-Token': subscriptionToken
})
const graphql = JSON.stringify({
    query: `mutation CreateOrderedProduct($input: CreateOrderedProductInput!) {
        createOrderedProduct(input: $input) {
            errors
            orderedProduct {
                createdAt
                graceCancellationEndsAt
                id
                interval
                intervalUnitOfMeasure
                maximumCommitmentEndsAt
                metadata
                minimumCommitmentEndsAt
                priceExcludingTaxCents
                priceIncludingTaxCents
                productId
                quantity
                recurring
                shipmentDate
                status
                title
                totalAmountExcludingTaxCents
                totalAmountIncludingTaxCents
                totalOrdered
                updatedAt
            }
            subscription {
                amountForStartingSubscriptionCents
                currency
                metadata
                monthlyAmount
                monthlyAmountCents
                orderedProducts {
                    createdAt
                    graceCancellationEndsAt
                    id
                    interval
                    intervalUnitOfMeasure
                    maximumCommitmentEndsAt
                    metadata
                    minimumCommitmentEndsAt
                    priceExcludingTaxCents
                    priceIncludingTaxCents
                    productId
                    quantity
                    recurring
                    status
                    title
                    totalAmountExcludingTaxCents
                    totalAmountIncludingTaxCents
                    totalOrdered
                    updatedAt
                }
            }
        }
    }      
`,
    variables: {
        input: {
            productId: products[0].id, // You can use any product id here
            quantity: 1,
            // metadatata: {key:  "value"},
            // ensureNewRecord: true,
        }
    }
})
const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const body = await response.json()
const { orderedProduct, subscription, errors } = body.data.createOrderedProduct
 
```

{% endcode %}

{% hint style="info" %}
If you need to add metadata to the ordered product, you must use a project access token with `Write` permissions. You can add it using the <mark style="color:blue;">`metadata`</mark> input variable. If you need to use different metadata for multiple orders of the same product, you can set the <mark style="color:blue;">`ensureNewRecord`</mark> value to `true`. This will ensure that each time you use the endpoint, a new orderedProduct item is created with the specified metadata.
{% endhint %}

{% hint style="info" %}
There are additional options for querying the product to add apart from <mark style="color:blue;">`productId`</mark>. You can find all these options [here](https://developer.firmhouse.com/graphql-api/api-reference/objects/create-ordered-product-input).
{% endhint %}
{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
const = { orderedProduct, subscription } = await firmhouseClient.carts.addProduct(subscriptionToken, {
  productId,
  quantity,
});
```

{% endcode %}

{% hint style="info" %}
If you need to add metadata to the ordered product, you need to initialize firmhouse client with write permissions. You can add it using the <mark style="color:blue;">`metadata`</mark> input variable. If you need to use different metadata for multiple orders of the same product, you can set the <mark style="color:blue;">`ensureNewRecord`</mark> value to `true`. This will ensure that each time you use the endpoint, a new orderedProduct item is created with the specified metadata.
{% endhint %}
{% endtab %}
{% endtabs %}

You can use the <mark style="color:blue;">`orderedProduct`</mark> variable to display notifications about added products. To show cart information, such as all ordered products, total price, payment terms, etc., you can use the <mark style="color:blue;">`subscription`</mark> variable.

### Removing products from the cart

To let users remove products from their cart, you can use the `destroyOrderedProduct` mutation.

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

```javascript
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': token,
    'X-Subscription-Token': subscriptionToken
})
const graphql = JSON.stringify({
    query: `mutation DestroyOrderedProduct($input: DestroyOrderedProductInput!) {
        destroyOrderedProduct(input: $input) {
            orderedProduct {
                createdAt
                graceCancellationEndsAt
                id
                interval
                intervalUnitOfMeasure
                maximumCommitmentEndsAt
                metadata
                minimumCommitmentEndsAt
                priceExcludingTaxCents
                priceIncludingTaxCents
                productId
                quantity
                recurring
                shipmentDate
                status
                title
                totalAmountExcludingTaxCents
                totalAmountIncludingTaxCents
                totalOrdered
                updatedAt
            }
            subscription {
                amountForStartingSubscriptionCents
                currency
                metadata
                monthlyAmount
                monthlyAmountCents
                orderedProducts {
                    createdAt
                    graceCancellationEndsAt
                    id
                    interval
                    intervalUnitOfMeasure
                    maximumCommitmentEndsAt
                    metadata
                    minimumCommitmentEndsAt
                    priceExcludingTaxCents
                    priceIncludingTaxCents
                    productId
                    quantity
                    recurring
                    status
                    title
                    totalAmountExcludingTaxCents
                    totalAmountIncludingTaxCents
                    totalOrdered
                    updatedAt
                }
            }
        }
    }      
`,
    variables: {
        input: {
            id: orderedProduct.id, // You can use any ordered product id here
        }
    }
})

const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const { errors, data } = await response.json()
const { orderedProduct: removedProduct, subscription } = data?.destroyOrderedProduct ?? {}

```

The fields retrieved in this query are the same as those in [`createOrderedProduct`](#adding-products-to-the-cart). Therefore you can use the same logic to handle the response that updates the Cart UI or notifications.
{% endtab %}
{% endtabs %}

### Updating the quantities of products in the cart

To allow users to change the quantities of products in their shopping cart, you can use the [`updateOrderedProductQuantity`](https://developer.firmhouse.com/graphql-api/api-reference/mutations/update-ordered-product-quantity) mutation.

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

```javascript
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': token,
    'X-Subscription-Token': subscriptionToken
})
const graphql = JSON.stringify({
    query: `mutation UpdateOrderedProductQuantity($input: UpdateOrderedProductQuantityInput!) {
        updateOrderedProductQuantity(input: $input) {
            orderedProduct {
                createdAt
                graceCancellationEndsAt
                id
                interval
                intervalUnitOfMeasure
                maximumCommitmentEndsAt
                metadata
                minimumCommitmentEndsAt
                priceExcludingTaxCents
                priceIncludingTaxCents
                productId
                quantity
                recurring
                shipmentDate
                status
                title
                totalAmountExcludingTaxCents
                totalAmountIncludingTaxCents
                totalOrdered
                updatedAt
            }
            subscription {
                amountForStartingSubscriptionCents
                currency
                metadata
                monthlyAmount
                monthlyAmountCents
                orderedProducts {
                    createdAt
                    graceCancellationEndsAt
                    id
                    interval
                    intervalUnitOfMeasure
                    maximumCommitmentEndsAt
                    metadata
                    minimumCommitmentEndsAt
                    priceExcludingTaxCents
                    priceIncludingTaxCents
                    productId
                    quantity
                    recurring
                    status
                    title
                    totalAmountExcludingTaxCents
                    totalAmountIncludingTaxCents
                    totalOrdered
                    updatedAt
                }
            }
        }
    }      
`,
    variables: {
        input: {
            orderedProduct: {
                id: orderedProduct.id, // You can use any ordered product id here
                quantity: 2
            } 
        }
    }
})

const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const body = await response.json()
const { orderedProduct: updatedProduct, subscription, errors } = body.data.updateOrderedProductQuantity
```

The fields retrieved in this query are the same as those in [`createOrderedProduct`](#adding-products-to-the-cart). Therefore you can use the same logic to handle the response that updates the Cart UI or notifications.
{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
const = { orderedProduct: updatedProduct, subscription } = await firmhouseClient.carts.updateOrderedProductQuantity(
  subscriptionToken,
  orderedProduct.id,
  2 // quantity
);
```

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

### Updating the subscription plan

You can change the active subscription plan with [`updatePlan`](https://developer.firmhouse.com/graphql-api/api-reference/mutations/update-plan) mutation.

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

```javascript
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': token,
    'X-Subscription-Token': subscriptionToken
})
const graphql = JSON.stringify({
    query: `mutation UpdatePlan($planSlug: String!) {
    updatePlan(input: { planSlug: $planSlug }) {
        subscription {
            activePlan {
                available
                currency
                graceCancellationEnabled
                graceCancellationPeriod
                graceCancellationUnit
                id
                imageUrl
                initialAmountExcludingTaxCents
                initialAmountIncludingTaxCents
                instalmentIntervalPeriod
                instalmentIntervalUnit
                instalments
                maximumCommitmentEnabled
                maximumCommitmentPeriod
                maximumCommitmentUnit
                metadata
                minimumCommitmentEnabled
                minimumCommitmentPeriod
                minimumCommitmentUnit
                monthlyAmountCents
                monthlyAmountExcludingTaxCents
                monthlyAmountIncludingTaxCents
                name
                slug
                taxAmountCents
                taxPercentage
            }
            subscribedPlan {
                activatedAt
                allowedToCancel
                billingCycleInterval
                billingCycleIntervalUnit
                customInitialAmountCents
                customRecurringAmountCents
                graceCancellationEndsAt
                graceCancellationPeriod
                graceCancellationUnit
                id
                inGraceCancellation
                inMinimumCommitment
                maximumCommitmentEndsAt
                maximumCommitmentPeriod
                maximumCommitmentUnit
                minimumCommitmentEndsAt
                minimumCommitmentPeriod
                minimumCommitmentUnit
                name
                nextBillingDate
                showInPriceBreakDown
                trialPeriodPeriod
                trialPeriodUnit
                unconsumedContractTermEventCount
            }
        }
    }
}   
`,
    variables: {
        planSlug: plans[0].slug //
    }
})

const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const body = await response.json()
const { subscription } = body.data.updatePlan

```

{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
const planSlug = plans[0].slug;
const cart = await firmhouseClient.carts.updatePlan(
  subscriptionToken,
  planSlug
);
```

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

### Fetching current cart information

You can use [`getSubscription` ](https://developer.firmhouse.com/graphql-api/api-reference/queries/get-subscription)query to get the current state of the cart. It's helpful when customers return to the application after leaving. You can use this query to retrieve cart information using the subscription token that you saved in a cookie or local storage. It's also useful for fetching details when they navigate to checkout page.

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

```javascript
const headers = new Headers({
    'Content-Type': 'application/json',
    'X-Project-Access-Token': token,
    'X-Subscription-Token': subscriptionToken
})
const graphql = JSON.stringify({
    query: `query GetSubscription($token: ID!) {
        getSubscription(token: $token) {
            amountForStartingSubscriptionCents
            monthlyAmountCents
            checkoutUrl
            currency
            metadata
            name
            lastName
            email
            address
            city
            country
            orderedProducts {
                createdAt
                graceCancellationEndsAt
                id
                interval
                intervalUnitOfMeasure
                maximumCommitmentEndsAt
                metadata
                minimumCommitmentEndsAt
                priceExcludingTaxCents
                priceIncludingTaxCents
                productId
                quantity
                recurring
                status
                title
                totalAmountExcludingTaxCents
                totalAmountIncludingTaxCents
                totalOrdered
                updatedAt
            }
        }
    }
    
`,
    variables: {
        token: subscriptionToken
    }
})

const requestOptions = {
    method: 'POST',
    headers,
    body: graphql,
};

const response = await fetch("https://portal.firmhouse.com/graphql", requestOptions)
const body = await response.json()
const subscription  = body.data.getSubscription

```

{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
const planSlug = plans[0].slug;
const cart = await firmhouseClient.carts.get(subscriptionToken);
```

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

You can see the list of available fields for a subscription [here](https://developer.firmhouse.com/graphql/objects/Subscription).

{% hint style="info" %}
If you want to use the default checkout page, you can redirect your customers to<mark style="color:blue;">`subscription.checkoutUrl`</mark>
{% endhint %}

### Updating address details

To update the subscription details, you can use the [`updateAddressDetails` ](https://developer.firmhouse.com/graphql-api/api-reference/mutations/update-address-details)mutation. This is helpful for checkout pages where users can enter their payment, invoice, and shipping information.

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

```javascript
const headers = new Headers({
  "Content-Type": "application/json",
  "X-Project-Access-Token": token,
  "X-Subscription-Token": subscriptionToken,
});
const graphql = JSON.stringify({
  query: `mutation UpdateAddressDetails($input: UpdateAddressDetailsInput!) {
        updateAddressDetails(input: $input) {
            subscription {
                amountForStartingSubscriptionCents
                monthlyAmountCents
                currency
                metadata
                name
                lastName
                email
                address
                city
                country
                orderedProducts {
                    createdAt
                    graceCancellationEndsAt
                    id
                    interval
                    intervalUnitOfMeasure
                    maximumCommitmentEndsAt
                    metadata
                    minimumCommitmentEndsAt
                    priceExcludingTaxCents
                    priceIncludingTaxCents
                    productId
                    quantity
                    recurring
                    status
                    title
                    totalAmountExcludingTaxCents
                    totalAmountIncludingTaxCents
                    totalOrdered
                    updatedAt
                }
            }
            errors {
                attribute
                message
                path
            }
        }
    }
    
`,
  variables: {
    input: {
        name: "John",
        lastName: "Doe",
        email: "johndoe@example.com",
        address: "X street",
        city: "Rotterdam",
        country: "NL", // ISO3661
        termsAccepted: true,
    },
  },
});

const requestOptions = {
  method: "POST",
  headers,
  body: graphql,
};

const response = await fetch(
  "https://portal.firmhouse.com/graphql",
  requestOptions
);

const { data = {}, errors: requestErrors } = await response.json();
const { subscription, errors } = data.updateAddressDetails ?? {};

```

{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
try {
  const cart = await firmhouseClient.carts.updateAddressDetails(
    subscriptionToken,
    {
      name: "John",
      lastName: "Doe",
      email: "johndoe@example",
      address: "X street",
      city: "Rotterdam",
      country: "NL", // ISO3661
      termsAccepted: true,
    }    
  );
} catch(error) {
  if (error instanceof ValidationError) {
    const { details } = error;
    //details: { email: "Email is invalid" }
  }
}

```

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

If there are any validation errors, you can find them in <mark style="color:blue;">`errors`</mark> variable. If there is an error in request, you can find them in <mark style="color:blue;">`requestErrors`</mark>.

{% hint style="info" %}
By default, only the following fields are required to proceed to the payment stage: <mark style="color:blue;">`name`</mark>, <mark style="color:blue;">`email`</mark>, <mark style="color:blue;">`address`</mark>, <mark style="color:blue;">`city`</mark>, <mark style="color:blue;">`country`</mark>. You can find the complete list of available input variables [here](https://developer.firmhouse.com/graphql/objects/UpdateAddressDetailsInput).

If you want to change the required fields, you can do so on the ***Checkout > Preferences > Customer fields*** page in your Firmhouse project.
{% endhint %}

### Generating payment links

After you have added the products to your cart and filled in the required information using the [`updateAddressDetails` ](#updating-address-details)mutation, you can use the [`createSubscriptionFromCart` ](https://developer.firmhouse.com/graphql-api/api-reference/mutations/create-subscription-from-cart)mutation to create a payment link (<mark style="color:blue;">`paymentUrl`</mark>). You can then direct the user to the payment provider with that link to complete the payment process. If the payment is successful, the user will be redirected to the <mark style="color:blue;">`returnUrl`</mark> that you provided as parameter for the mutation.

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

```javascript
const headers = new Headers({
  "Content-Type": "application/json",
  "X-Project-Access-Token": token,
  "X-Subscription-Token": subscriptionToken,
});
const graphql = JSON.stringify({
  query: `mutation CreateSubscriptionFromCart($input: CreateSubscriptionFromCartInput!) {
    createSubscriptionFromCart(input: $input){
        paymentUrl
        returnUrl
        errors {
            attribute
            message
            path 
        }
    }
}      
`,
  variables: {
    input: {
      returnUrl: "https://yourdomain.com/return", // The URL to redirect to after a successful payment
      paymentPageUrl: "https://yourdomain.com/checkout", // The URL where the user can sign up for a new subscription
    },
  },
});

const requestOptions = {
  method: "POST",
  headers,
  body: graphql,
};

const response = await fetch(
  "https://portal.firmhouse.com/graphql",
  requestOptions
);

const body = await response.json();
const { paymentUrl, returnUrl, errors } = body.data.createSubscriptionFromCart;
```

{% endtab %}

{% tab title="Firmhouse SDK" %}
{% code overflow="wrap" %}

```typescript
try {
  const paymentResponse = await firmhouseClient.carts.createSubscription(
    subscriptionToken,
    "https://yourdomain.com/checkout",
    "https://yourdomain.com/return"
  );
  const { paymentUrl, returnUrl } = paymentResponse;
} catch(error) {
  if (error instanceof ValidationError) {
    const { details } = error;
    //details: { email: "Email is invalid" }
  }
}

```

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

If any required fields are missing, the <mark style="color:blue;">`paymentUrl`</mark> will be null and you can check which fields are missing in the <mark style="color:blue;">`errors`</mark> variable.

{% hint style="warning" %}
If you haven't added a payment method to your Firmhouse project, this request will fail with a 500 error.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.firmhouse.com/guides/creating-a-storefront-app.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
