> ## Documentation Index
> Fetch the complete documentation index at: https://docs.credibill.tech/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Plans

> Define how you charge your customers

<Warning>
  We strongly advise managing all plan operations (create, read, update, delete)
  through the Credibill dashboard instead of using the API. The dashboard
  provides a user-friendly interface for defining pricing structures, managing
  trials, and configuring complex pricing models. Use the API only when you need
  programmatic plan operations in exceptional cases.
</Warning>

**Plans** define the pricing structure, billing interval, and feature set for a subscription.

## Plan Structure

A Plan consists of:

* **Name**: A human-readable name for the plan (e.g., `Pro Plan`, `Basic Plan`).
* **Description**: A brief description of what the plan offers.
* **Interval**: How often the customer is billed (e.g., `month`, `year`).
* **Currency**: The currency for the plan (e.g., `UGX`, `KES`).
* **Prices**: The amount to be charged.
* **Trial Period**: Optional free trial duration before billing starts.

### Pricing Models

Credibill supports flexible pricing models:

1. **Flat Rate**: A fixed amount per interval (e.g., UGX 10,000/month).
2. **Per Unit**: Charged based on the number of units (e.g., UGX 5,000 per seat).
3. **Tiered**: Different prices for different volume ranges (e.g., first 100 free, then UGX 100/unit).
4. **Usage-Based**: Metered billing based on reported usage (e.g., UGX 1 per API call).

Note: **Features** can be defined within your application and not
Credibill.

## How to create a plan

Create a new plan with pricing and billing configuration. This endpoint allows you to define how customers are charged when subscribed to this plan.

* Endpoint: `https://giant-goldfish-922.convex.site/api/v1/plans`
* Method: `POST`
* Authentication: Authorization: `Bearer <CREDIBILL_API_KEY>`

### Request Body Schema

| Field       | Type   | Required | Description                                                      |
| ----------- | ------ | -------- | ---------------------------------------------------------------- |
| name        | string | Yes      | The name of the plan (e.g., "Pro Plan").                         |
| description | string | No       | A brief description of what the plan includes.                   |
| interval    | string | Yes      | Billing interval - "month" or "year".                            |
| currency    | string | Yes      | The currency code (e.g., "UGX", "KES", "USD").                   |
| price       | number | Yes      | The amount to charge per billing interval.                       |
| trialDays   | number | No       | Number of free trial days before billing starts (defaults to 0). |
| metadata    | object | No       | Arbitrary JSON data for storing additional plan information.     |

### Examples

<Tabs>
  <Tab title="React">
    ```typescript theme={null}
    // src/hooks/useCreatePlan.ts

    import { useMutation, UseMutationOptions } from "@tanstack/react-query";

    export type PlanData = {
      name: string,
      description?: string,
      interval: "month" | "year",
      currency: string,
      price: number,
      trialDays?: number,
      metadata?: Record<string, any>,
    };

    export type CreatePlanResponse = {
      success: boolean,
      planId: string,
    };

    const useApiKey = () => {
    // !! REPLACE THIS PLACEHOLDER !!
    const apiKey = 'YOUR_CREDIBILL_API_KEY';
    return apiKey;
    };

    const CREDIBILL_URL = 'https://giant-goldfish-922.convex.site';
    const ENDPOINT = '/api/v1/plans';

    type UseCreatePlanOptions = Omit<UseMutationOptions<
    CreatePlanResponse,
    Error,
    PlanData

    > , 'mutationFn'>;

    /\*\*

    - Custom React Query hook for creating a plan
    - @param options - Optional configuration options for useMutation
    - @returns The mutation object provided by TanStack Query
      \*/
      export const useCreatePlan = (
      options?: UseCreatePlanOptions
      ) => {
      const apiKey = useApiKey();

    return useMutation<CreatePlanResponse, Error, PlanData>({
    mutationFn: async (data: PlanData) => {
    if (!apiKey) {
    throw new Error("API Key is required for authentication.");
    }

          const response = await fetch(`${CREDIBILL_URL}${ENDPOINT}`, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${apiKey}`,
            },
            body: JSON.stringify(data),
          });

          if (!response.ok) {
            const errorBody = await response.json();
            throw new Error(errorBody.error || `HTTP error! Status: ${response.status}`);
          }

          return response.json();
        },
        ...options,

    });
    };

    ```

    #### Usage in a Component

    ```typescript theme={null}
    import React, { useState } from 'react';
    import { useCreatePlan } from './hooks/useCreatePlan';

    export const CreatePlanForm = () => {
      const [name, setName] = useState('');
      const [description, setDescription] = useState('');
      const [interval, setInterval] = useState<'month' | 'year'>('month');
      const [currency, setCurrency] = useState('UGX');
      const [price, setPrice] = useState('');
      const [trialDays, setTrialDays] = useState('');

      const { mutate, isPending, isError, isSuccess, data, error, reset } = useCreatePlan({
        onSuccess: (responseData) => {
          console.log(`Success! Plan ID: ${responseData.planId}`);
        },
      });

      const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        if (isPending) return;

        reset();

        mutate({
          name: name.trim(),
          description: description.trim() || undefined,
          interval,
          currency: currency.trim(),
          price: parseFloat(price),
          trialDays: trialDays ? parseInt(trialDays) : undefined,
        });
      };

      return (
        <div className="p-6 max-w-lg mx-auto bg-white rounded-xl shadow-lg space-y-4">
          <div className="p-3 bg-yellow-100 border border-yellow-400 text-yellow-700 rounded-lg text-sm">
            ⚠️ <strong>Recommendation:</strong> Consider creating plans through the dashboard for a better experience.
          </div>

          <h2 className="text-2xl font-bold text-gray-800">Create a Plan</h2>
          <form onSubmit={handleSubmit} className="space-y-4">
            <div>
              <label htmlFor="name" className="block text-sm font-medium text-gray-700">
                Plan Name (Required)
              </label>
              <input
                id="name"
                type="text"
                value={name}
                onChange={(e) => setName(e.target.value)}
                placeholder="Pro Plan"
                required
                disabled={isPending}
                className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
              />
            </div>

            <div>
              <label htmlFor="description" className="block text-sm font-medium text-gray-700">
                Description (Optional)
              </label>
              <textarea
                id="description"
                value={description}
                onChange={(e) => setDescription(e.target.value)}
                placeholder="Describe what's included in this plan"
                disabled={isPending}
                rows={3}
                className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
              />
            </div>

            <div className="grid grid-cols-2 gap-4">
              <div>
                <label htmlFor="interval" className="block text-sm font-medium text-gray-700">
                  Interval (Required)
                </label>
                <select
                  id="interval"
                  value={interval}
                  onChange={(e) => setInterval(e.target.value as 'month' | 'year')}
                  disabled={isPending}
                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                >
                  <option value="month">Monthly</option>
                  <option value="year">Yearly</option>
                </select>
              </div>

              <div>
                <label htmlFor="currency" className="block text-sm font-medium text-gray-700">
                  Currency (Required)
                </label>
                <input
                  id="currency"
                  type="text"
                  value={currency}
                  onChange={(e) => setCurrency(e.target.value.toUpperCase())}
                  placeholder="UGX"
                  required
                  disabled={isPending}
                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                />
              </div>
            </div>

            <div className="grid grid-cols-2 gap-4">
              <div>
                <label htmlFor="price" className="block text-sm font-medium text-gray-700">
                  Price (Required)
                </label>
                <input
                  id="price"
                  type="number"
                  value={price}
                  onChange={(e) => setPrice(e.target.value)}
                  placeholder="10000"
                  required
                  disabled={isPending}
                  step="0.01"
                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                />
              </div>

              <div>
                <label htmlFor="trialDays" className="block text-sm font-medium text-gray-700">
                  Trial Days (Optional)
                </label>
                <input
                  id="trialDays"
                  type="number"
                  value={trialDays}
                  onChange={(e) => setTrialDays(e.target.value)}
                  placeholder="0"
                  disabled={isPending}
                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                />
              </div>
            </div>

            <button
              type="submit"
              disabled={isPending}
              className="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 ease-in-out disabled:opacity-50"
            >
              {isPending ? 'Processing...' : 'Create Plan'}
            </button>
          </form>

          {isSuccess && (
            <div className="mt-4 p-3 bg-green-100 border border-green-400 text-green-700 rounded-lg">
              Success! Plan ID: <span className="font-mono">{data?.planId}</span>
            </div>
          )}
          {isError && (
            <div className="mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded-lg">
              Error: {error?.message}
            </div>
          )}
        </div>
      );
    };
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST 'https://giant-goldfish-922.convex.site/api/v1/plans' \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY' \
      -d '{
        "name": "Pro Plan",
        "description": "Advanced features for growing teams",
        "interval": "month",
        "currency": "UGX",
        "price": 50000,
        "trialDays": 14
      }'
    ```
  </Tab>
</Tabs>

### Response

When you create a plan, the API responds with the newly created plan's ID.

```json theme={null}
{
  "success": true,
  "planId": "k89cq3gkzhiys60bzuf53bh3hte8zx2d"
}
```

## Getting your app's plans

Retrieve all plans configured for your application. This endpoint returns a list of all available plans that customers can subscribe to.

* Endpoint: `https://giant-goldfish-922.convex.site/api/v1/plans`
* Method: `GET`
* Authentication: Authorization: `Bearer <CREDIBILL_API_KEY>`

### Examples

<Tabs>
  <Tab title="React">
    ```typescript theme={null}
    // src/hooks/useGetPlans.ts

    import { useQuery, UseQueryOptions } from "@tanstack/react-query";

    export type Plan = {
      _id: string,
      name: string,
      description?: string,
      interval: "month" | "year",
      currency: string,
      price: number,
      trialDays?: number,
      metadata?: Record<string, any>,
      [key: string]: any,
    };

    export type GetPlansResponse = {
      plans: Plan[],
    };

    const useApiKey = () => {
    // !! REPLACE THIS PLACEHOLDER !!
    const apiKey = 'YOUR_CREDIBILL_API_KEY';
    return apiKey;
    };

    const CREDIBILL_URL = 'https://giant-goldfish-922.convex.site';
    const ENDPOINT = '/api/v1/plans';

    type UseGetPlansOptions = Omit<UseQueryOptions<
    GetPlansResponse,
    Error

    > , 'queryFn' | 'queryKey'>;

    /\*\*

    - Custom React Query hook for fetching all plans for your app
    - @param options - Optional configuration options for useQuery
    - @returns The query object provided by TanStack Query
      \*/
      export const useGetPlans = (
      options?: UseGetPlansOptions
      ) => {
      const apiKey = useApiKey();

    return useQuery<GetPlansResponse, Error>({
    queryKey: ['plans'],
    queryFn: async () => {
    if (!apiKey) {
    throw new Error("API Key is required for authentication.");
    }

          const response = await fetch(`${CREDIBILL_URL}${ENDPOINT}`, {
            method: 'GET',
            headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${apiKey}`,
            },
          });

          if (!response.ok) {
            const errorBody = await response.json();
            throw new Error(errorBody.error || `HTTP error! Status: ${response.status}`);
          }

          return response.json();
        },
        ...options,

    });
    };

    ```

    #### Usage in a Component

    ```typescript theme={null}
    import React from 'react';
    import { useGetPlans } from './hooks/useGetPlans';

    export const PlansShowcase = () => {
      const { data, isLoading, isError, error } = useGetPlans();

      if (isLoading) {
        return <div className="text-center py-8">Loading plans...</div>;
      }

      if (isError) {
        return (
          <div className="p-3 bg-red-100 border border-red-400 text-red-700 rounded-lg">
            Error: {error?.message}
          </div>
        );
      }

      return (
        <div className="p-6 max-w-4xl mx-auto">
          <h2 className="text-3xl font-bold text-gray-800 mb-8">Choose Your Plan</h2>

          {data?.plans && data.plans.length > 0 ? (
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
              {data.plans.map((plan) => (
                <div
                  key={plan._id}
                  className="p-6 border border-gray-200 rounded-lg shadow-md hover:shadow-lg transition-shadow"
                >
                  <h3 className="text-xl font-bold text-gray-800 mb-2">{plan.name}</h3>
                  {plan.description && (
                    <p className="text-sm text-gray-600 mb-4">{plan.description}</p>
                  )}

                  <div className="mb-4">
                    <span className="text-3xl font-bold text-gray-900">{plan.price}</span>
                    <span className="text-sm text-gray-600 ml-2">{plan.currency}</span>
                    <span className="text-sm text-gray-600">/{plan.interval}</span>
                  </div>

                  {plan.trialDays && plan.trialDays > 0 && (
                    <div className="mb-4 p-2 bg-green-100 rounded">
                      <p className="text-sm text-green-800">
                        🎉 {plan.trialDays}-day free trial
                      </p>
                    </div>
                  )}

                  <button className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
                    Subscribe Now
                  </button>
                </div>
              ))}
            </div>
          ) : (
            <div className="p-4 bg-gray-100 rounded-lg text-center">
              <p className="text-gray-600">No plans available yet.</p>
            </div>
          )}
        </div>
      );
    };
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET 'https://giant-goldfish-922.convex.site/api/v1/plans' \
      -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY'
    ```
  </Tab>
</Tabs>

### Response

When you fetch your app's plans, the API responds with a list of all configured plans.

```json theme={null}
{
  "plans": [
    {
      "_id": "k89cq3gkzhiys60bzuf53bh3hte8zx2d",
      "name": "Basic Plan",
      "description": "Perfect for getting started",
      "interval": "month",
      "currency": "UGX",
      "price": 10000,
      "trialDays": 7
    },
    {
      "_id": "l98dro4hlizjt71cvwg64cj4juf9ze3e",
      "name": "Pro Plan",
      "description": "Advanced features for growing teams",
      "interval": "month",
      "currency": "UGX",
      "price": 50000,
      "trialDays": 14
    },
    {
      "_id": "m01eso5imjzku82dwxh75dk5kug0af4f",
      "name": "Enterprise Plan",
      "description": "Custom solutions for large organizations",
      "interval": "year",
      "currency": "UGX",
      "price": 500000,
      "trialDays": null
    }
  ]
}
```

## How to update a plan

Update an existing plan's configuration. You can modify the name, description, price, trial period, and other plan attributes.

* Endpoint: `https://giant-goldfish-922.convex.site/api/v1/plans`
* Method: `PATCH`
* Authentication: Authorization: `Bearer <CREDIBILL_API_KEY>`

### Request Body Schema

| Field       | Type   | Required | Description                             |
| ----------- | ------ | -------- | --------------------------------------- |
| planId      | string | Yes      | The unique ID of the plan to update.    |
| name        | string | No       | Update the plan name.                   |
| description | string | No       | Update the plan description.            |
| price       | number | No       | Update the plan price.                  |
| trialDays   | number | No       | Update the trial period in days.        |
| metadata    | object | No       | Update or add additional plan metadata. |

### Examples

<Tabs>
  <Tab title="React">
    ```typescript theme={null}
    // src/hooks/useUpdatePlan.ts

    import { useMutation, UseMutationOptions } from "@tanstack/react-query";

    export type UpdatePlanData = {
      planId: string,
      name?: string,
      description?: string,
      price?: number,
      trialDays?: number,
      metadata?: Record<string, any>,
    };

    export type UpdatePlanResponse = {
      success: boolean,
      message: string,
    };

    const useApiKey = () => {
    // !! REPLACE THIS PLACEHOLDER !!
    const apiKey = 'YOUR_CREDIBILL_API_KEY';
    return apiKey;
    };

    const CREDIBILL_URL = 'https://giant-goldfish-922.convex.site';
    const ENDPOINT = '/api/v1/plans';

    type UseUpdatePlanOptions = Omit<UseMutationOptions<
    UpdatePlanResponse,
    Error,
    UpdatePlanData

    > , 'mutationFn'>;

    /\*\*

    - Custom React Query hook for updating a plan
    - @param options - Optional configuration options for useMutation
    - @returns The mutation object provided by TanStack Query
      \*/
      export const useUpdatePlan = (
      options?: UseUpdatePlanOptions
      ) => {
      const apiKey = useApiKey();

    return useMutation<UpdatePlanResponse, Error, UpdatePlanData>({
    mutationFn: async (data: UpdatePlanData) => {
    if (!apiKey) {
    throw new Error("API Key is required for authentication.");
    }

          const response = await fetch(`${CREDIBILL_URL}${ENDPOINT}`, {
            method: 'PATCH',
            headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${apiKey}`,
            },
            body: JSON.stringify(data),
          });

          if (!response.ok) {
            const errorBody = await response.json();
            throw new Error(errorBody.error || `HTTP error! Status: ${response.status}`);
          }

          return response.json();
        },
        ...options,

    });
    };

    ```

    #### Usage in a Component

    ```typescript theme={null}
    import React, { useState } from 'react';
    import { useUpdatePlan } from './hooks/useUpdatePlan';

    export const UpdatePlanForm = ({ planId, currentPlan }: {
      planId: string;
      currentPlan?: { name: string; description?: string; price: number; trialDays?: number };
    }) => {
      const [name, setName] = useState(currentPlan?.name || '');
      const [description, setDescription] = useState(currentPlan?.description || '');
      const [price, setPrice] = useState(String(currentPlan?.price) || '');
      const [trialDays, setTrialDays] = useState(String(currentPlan?.trialDays || ''));

      const { mutate, isPending, isError, isSuccess, error, reset } = useUpdatePlan({
        onSuccess: () => {
          console.log('Plan updated successfully');
        },
      });

      const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        if (isPending) return;

        reset();

        const updates: Record<string, any> = { planId };
        if (name.trim()) updates.name = name.trim();
        if (description.trim()) updates.description = description.trim();
        if (price) updates.price = parseFloat(price);
        if (trialDays) updates.trialDays = parseInt(trialDays);

        mutate(updates as UpdatePlanData);
      };

      return (
        <div className="p-6 max-w-lg mx-auto bg-white rounded-xl shadow-lg space-y-4">
          <h2 className="text-2xl font-bold text-gray-800">Update Plan</h2>
          <form onSubmit={handleSubmit} className="space-y-4">
            <div>
              <label htmlFor="planId" className="block text-sm font-medium text-gray-700">
                Plan ID
              </label>
              <input
                id="planId"
                type="text"
                value={planId}
                disabled
                className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm bg-gray-100 text-gray-600"
              />
            </div>

            <div>
              <label htmlFor="name" className="block text-sm font-medium text-gray-700">
                Plan Name (Optional)
              </label>
              <input
                id="name"
                type="text"
                value={name}
                onChange={(e) => setName(e.target.value)}
                placeholder="Leave blank to keep current"
                disabled={isPending}
                className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
              />
            </div>

            <div>
              <label htmlFor="description" className="block text-sm font-medium text-gray-700">
                Description (Optional)
              </label>
              <textarea
                id="description"
                value={description}
                onChange={(e) => setDescription(e.target.value)}
                placeholder="Leave blank to keep current"
                disabled={isPending}
                rows={3}
                className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
              />
            </div>

            <div className="grid grid-cols-2 gap-4">
              <div>
                <label htmlFor="price" className="block text-sm font-medium text-gray-700">
                  Price (Optional)
                </label>
                <input
                  id="price"
                  type="number"
                  value={price}
                  onChange={(e) => setPrice(e.target.value)}
                  placeholder="Leave blank to keep current"
                  disabled={isPending}
                  step="0.01"
                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                />
              </div>

              <div>
                <label htmlFor="trialDays" className="block text-sm font-medium text-gray-700">
                  Trial Days (Optional)
                </label>
                <input
                  id="trialDays"
                  type="number"
                  value={trialDays}
                  onChange={(e) => setTrialDays(e.target.value)}
                  placeholder="Leave blank to keep current"
                  disabled={isPending}
                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                />
              </div>
            </div>

            <button
              type="submit"
              disabled={isPending}
              className="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 ease-in-out disabled:opacity-50"
            >
              {isPending ? 'Processing...' : 'Update Plan'}
            </button>
          </form>

          {isSuccess && (
            <div className="mt-4 p-3 bg-green-100 border border-green-400 text-green-700 rounded-lg">
              Success! Plan has been updated.
            </div>
          )}
          {isError && (
            <div className="mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded-lg">
              Error: {error?.message}
            </div>
          )}
        </div>
      );
    };
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # Update plan name and description
    curl -X PATCH 'https://giant-goldfish-922.convex.site/api/v1/plans' \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY' \
      -d '{
        "planId": "k89cq3gkzhiys60bzuf53bh3hte8zx2d",
        "name": "Premium Plan",
        "description": "Updated premium tier with more features"
      }'

    # Update plan price

    curl -X PATCH 'https://giant-goldfish-922.convex.site/api/v1/plans' \
     -H 'Content-Type: application/json' \
     -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY' \
     -d '{
    "planId": "k89cq3gkzhiys60bzuf53bh3hte8zx2d",
    "price": 75000
    }'

    # Update multiple fields at once

    curl -X PATCH 'https://giant-goldfish-922.convex.site/api/v1/plans' \
     -H 'Content-Type: application/json' \
     -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY' \
     -d '{
    "planId": "k89cq3gkzhiys60bzuf53bh3hte8zx2d",
    "name": "Pro Plan",
    "price": 60000,
    "trialDays": 30
    }'

    ```
  </Tab>
</Tabs>

### Response

When you update a plan, the API responds with a success message.

```json theme={null}
{
  "success": true,
  "message": "Plan updated"
}
```

## How to delete a plan

Delete a plan from your application. This action removes the plan and prevents new subscriptions from being created with this plan. Existing subscriptions are not affected.

* Endpoint: `https://giant-goldfish-922.convex.site/api/v1/plans/delete`
* Method: `DELETE`
* Authentication: Authorization: `Bearer <CREDIBILL_API_KEY>`

### Query Parameters

| Parameter | Type   | Required | Description                          |
| --------- | ------ | -------- | ------------------------------------ |
| planId    | string | Yes      | The unique ID of the plan to delete. |

### Examples

<Tabs>
  <Tab title="React">
    ```typescript theme={null}
    // src/hooks/useDeletePlan.ts

    import { useMutation, UseMutationOptions } from "@tanstack/react-query";

    export type DeletePlanData = {
      planId: string,
    };

    export type DeletePlanResponse = {
      success: boolean,
      message: string,
    };

    const useApiKey = () => {
    // !! REPLACE THIS PLACEHOLDER !!
    const apiKey = 'YOUR_CREDIBILL_API_KEY';
    return apiKey;
    };

    const CREDIBILL_URL = 'https://giant-goldfish-922.convex.site';
    const ENDPOINT = '/api/v1/plans/delete';

    type UseDeletePlanOptions = Omit<UseMutationOptions<
    DeletePlanResponse,
    Error,
    DeletePlanData

    > , 'mutationFn'>;

    /\*\*

    - Custom React Query hook for deleting a plan
    - @param options - Optional configuration options for useMutation
    - @returns The mutation object provided by TanStack Query
      \*/
      export const useDeletePlan = (
      options?: UseDeletePlanOptions
      ) => {
      const apiKey = useApiKey();

    return useMutation<DeletePlanResponse, Error, DeletePlanData>({
    mutationFn: async (data: DeletePlanData) => {
    if (!apiKey) {
    throw new Error("API Key is required for authentication.");
    }

          const url = new URL(`${CREDIBILL_URL}${ENDPOINT}`);
          url.searchParams.append('planId', data.planId);

          const response = await fetch(url.toString(), {
            method: 'DELETE',
            headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${apiKey}`,
            },
          });

          if (!response.ok) {
            const errorBody = await response.json();
            throw new Error(errorBody.error || `HTTP error! Status: ${response.status}`);
          }

          return response.json();
        },
        ...options,

    });
    };

    ```

    #### Usage in a Component

    ```typescript theme={null}
    import React, { useState } from 'react';
    import { useDeletePlan } from './hooks/useDeletePlan';

    export const DeletePlanForm = () => {
      const [planId, setPlanId] = useState('');
      const [showConfirm, setShowConfirm] = useState(false);

      const { mutate, isPending, isError, isSuccess, error, reset } = useDeletePlan({
        onSuccess: () => {
          console.log('Plan deleted successfully');
          setPlanId('');
          setShowConfirm(false);
        },
      });

      const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        if (isPending) return;

        reset();
        mutate({ planId: planId.trim() });
      };

      return (
        <div className="p-6 max-w-lg mx-auto bg-white rounded-xl shadow-lg space-y-4">
          <h2 className="text-2xl font-bold text-gray-800">Delete Plan</h2>
          <form onSubmit={handleSubmit} className="space-y-4">
            <div>
              <label htmlFor="planId" className="block text-sm font-medium text-gray-700">
                Plan ID (Required)
              </label>
              <input
                id="planId"
                type="text"
                value={planId}
                onChange={(e) => setPlanId(e.target.value)}
                placeholder="Enter the plan ID to delete"
                required
                disabled={isPending}
                className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
              />
            </div>

            {planId && !showConfirm && (
              <button
                type="button"
                onClick={() => setShowConfirm(true)}
                disabled={isPending}
                className="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-yellow-600 hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 transition duration-150 ease-in-out disabled:opacity-50"
              >
                Next: Confirm Deletion
              </button>
            )}

            {showConfirm && (
              <div className="p-4 bg-red-50 border border-red-200 rounded-lg">
                <p className="text-sm font-semibold text-red-800 mb-3">
                  ⚠️ Are you sure you want to delete this plan?
                </p>
                <p className="text-sm text-red-700 mb-4">
                  This action cannot be undone. Existing subscriptions to this plan will not be affected, but new subscriptions cannot be created.
                </p>
                <div className="flex gap-2">
                  <button
                    type="submit"
                    disabled={isPending}
                    className="flex-1 py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition duration-150 ease-in-out disabled:opacity-50"
                  >
                    {isPending ? 'Deleting...' : 'Delete Plan'}
                  </button>
                  <button
                    type="button"
                    onClick={() => setShowConfirm(false)}
                    disabled={isPending}
                    className="flex-1 py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 ease-in-out disabled:opacity-50"
                  >
                    Cancel
                  </button>
                </div>
              </div>
            )}
          </form>

          {isSuccess && (
            <div className="mt-4 p-3 bg-green-100 border border-green-400 text-green-700 rounded-lg">
              Success! Plan has been deleted.
            </div>
          )}
          {isError && (
            <div className="mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded-lg">
              Error: {error?.message}
            </div>
          )}
        </div>
      );
    };
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X DELETE 'https://giant-goldfish-922.convex.site/api/v1/plans/delete?planId=k89cq3gkzhiys60bzuf53bh3hte8zx2d' \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY'
    ```
  </Tab>
</Tabs>

### Response

When you delete a plan, the API responds with a success message.

```json theme={null}
{
  "success": true,
  "message": "Plan deleted"
}
```
