> ## 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.

# Customers

> The people that purchase your products or services

A **Customer** represents a business or individual that purchases your products or services. It allows you to track subscriptions, payments, invoices, and usage for a specific entity.

## 👤 Creating a Customer

You should create a Customer in Credibill when a user signs up for your application.
This endpoint is used to register a new customer in the system. It is authenticated via an API Key passed as a Bearer Token in the Authorization header.

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

Request Body Schema:

| Field              | Type   | Required | Description                                            |
| ------------------ | ------ | -------- | ------------------------------------------------------ |
| email              | string | Yes      | The customer's primary email address (must be unique). |
| first\_name        | string | No       | The customer's first name.                             |
| last\_name         | string | No       | The customer's last name.                              |
| phone              | string | No       | The customer's phone number.                           |
| externalCustomerId | string | No       | An ID from your internal system.                       |
| metadata           | object | No       | Arbitrary JSON data.                                   |

## Example (React + TS)

<Tabs>
  <Tab title="customers.ts">
    ```typescript theme={null}
    // src/api/customers.ts

    // --- Data Types for Customer Creation ---
    export type CustomerData = {
    email: string;
    first_name?: string;
    last_name?: string;
    phone?: string;
    externalCustomerId?: string;
    metadata?: Record<string, any>;
    type?: string;
    status?: string;
    };

    export type CustomerCreationResponse = {
      success: boolean,
      customerId: string,
    };

    // Replace with your actual Convex URL
    const CONVEX_URL = 'https://YOUR_CONVEX_URL.convex.site';
    const ENDPOINT = '/api/v1/customers/create';

    /\*\*

    - Handles the HTTP POST request to create a new customer.
    - @param data - The customer payload.
    - @param apiKey - The Credibill API Key for Bearer authentication.
    - @returns A promise resolving to the API response data.
      \*/
      export async function createCustomer(
      data: CustomerData,
      apiKey: string
      ): Promise<CustomerCreationResponse> {
      // 1. Validate API Key presence
      if (!apiKey) {
      throw new Error("API Key is required for authentication.");
      }

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

    // 3. Handle API Response Errors
    if (!response.ok) {
    const errorBody = await response.json();
    // Throw error to be caught by React Query's useMutation onError
    throw new Error(errorBody.error || `HTTP error! Status: ${response.status}`);
    }

    // 4. Return successful response body
    return response.json();
    }

    ```
  </Tab>

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

    import { useMutation, UseMutationOptions } from '@tanstack/react-query';
    import { createCustomer, CustomerData, CustomerCreationResponse } from '../api/customers';

    // NOTE: In a real application, the API key should be retrieved securely,
    // e.g., from an authentication context or securely fetched environment variable.
    const useApiKey = () => {
        // !! REPLACE THIS PLACEHOLDER !!
        const apiKey = 'YOUR_CREDIBILL_API_KEY';
        return apiKey;
    };

    // Define the arguments and return type for the useMutation hook
    type CreateCustomerOptions = Omit<UseMutationOptions<
      CustomerCreationResponse,
      Error,
      CustomerData
    >, 'mutationFn'>;

    /**
     * Custom React Query hook for creating a customer.
     * Uses the useMutation hook to manage the POST request state.
     * @param options - Optional configuration options for useMutation (e.g., onSuccess, onError).
     * @returns The mutation object provided by TanStack Query.
     */
    export const useCreateCustomer = (
      options?: CreateCustomerOptions
    ) => {
      const apiKey = useApiKey();

      return useMutation<CustomerCreationResponse, Error, CustomerData>({
        // mutationFn takes the customer data and calls the authenticated API function
        mutationFn: (data: CustomerData) => createCustomer(data, apiKey),
        // Pass through any custom options (like onSuccess/onError)
        ...options,
      });
    };
    ```
  </Tab>

  <Tab title="React Component">
    ```typescript theme={null}
    import React, { useState } from 'react';
    import { useMutation, UseMutationOptions } from '@tanstack/react-query';

    // --- 1. API Data Types ---

    type CustomerData = {
    email: string;
    first_name?: string;
    last_name?: string;
    phone?: string;
    externalCustomerId?: string;
    metadata?: Record<string, any>;
    type?: string;
    status?: string;
    };

    type CustomerCreationResponse = {
    success: boolean;
    customerId: string;
    };

    // --- 2. API Fetch Function ---

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

    async function createCustomer(
    data: CustomerData,
    apiKey: string
    ): Promise<CustomerCreationResponse> {
    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();
    }

    // --- 3. Custom React Query Hook ---

    const useApiKey = () => {
    const apiKey = 'YOUR_CREDIBILL_API_KEY';
    return apiKey;
    };

    type CreateCustomerOptions = Omit<UseMutationOptions<
    CustomerCreationResponse,
    Error,
    CustomerData

    > , 'mutationFn'>;

    const useCreateCustomer = (
    options?: CreateCustomerOptions
    ) => {
    const apiKey = useApiKey();

    return useMutation<CustomerCreationResponse, Error, CustomerData>({
    mutationFn: (data: CustomerData) => createCustomer(data, apiKey),
    ...options,
    });
    };

    // --- 4. Component Definition ---

    const CreateCustomerForm = () => {
    const [email, setEmail] = useState('');
    const [firstName, setFirstName] = useState('');
    const [externalId, setExternalId] = useState('');

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

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

        reset();

        mutate({
          email: email.trim(),
          first_name: firstName.trim(),
          externalCustomerId: externalId.trim() || undefined,
        });

    };

    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">New Customer Registration</h2>
    <form onSubmit={handleSubmit} className="space-y-4">
    <div>
    <label htmlFor="email" className="block text-sm font-medium text-gray-700">Email (Required)</label>
    <input
    id="email"
    type="email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    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="firstName" className="block text-sm font-medium text-gray-700">First Name</label>
    <input
    id="firstName"
    type="text"
    value={firstName}
    onChange={(e) => setFirstName(e.target.value)}
    disabled={isPending}
    className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
    />
    </div>
    <div>
    <label htmlFor="externalId" className="block text-sm font-medium text-gray-700">External ID (Optional)</label>
    <input
    id="externalId"
    type="text"
    value={externalId}
    onChange={(e) => setExternalId(e.target.value)}
    disabled={isPending}
    className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
    />
    </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 Customer'}
            </button>
          </form>

          {isSuccess && (
            <div className="mt-4 p-3 bg-green-100 border border-green-400 text-green-700 rounded-lg">
              Success! New Customer ID: <span className="font-mono">{data?.customerId}</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>

    );
    };

    export default CreateCustomerForm;
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST 'https://giant-goldfish-922.convex.site/api/v1/customers/create' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY' \
    -d '{
        "email": "jane.doe@example.com",
        "first_name": "Jane",
        "externalCustomerId": "app-user-12345"
    }'
    ```
  </Tab>
</Tabs>

## Response

When you create a customer, the API responds with a JSON object containing the success status and the unique customer ID.

```json theme={null}
{
  "success": true,
  "customerId": "j97bp2fjzhbx59ayye52ag2gsd7ydw1c"
}
```

## Getting Customer Details

Retrieve customer information by listing all customers for your app or fetching a specific customer by ID.

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

### Query Parameters

| Parameter  | Type   | Required | Description                                                     |
| ---------- | ------ | -------- | --------------------------------------------------------------- |
| customerId | string | No       | The unique ID of the customer. If omitted, lists all customers. |

### Examples

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

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

    export type Customer = {
      _id: string,
      email: string,
      first_name?: string,
      last_name?: string,
      phone?: string,
      externalCustomerId?: string,
      metadata?: Record<string, any>,
      [key: string]: any,
    };

    export type GetCustomersResponse = {
      customers?: Customer[],
      customer?: Customer,
    };

    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/customers';

    type UseGetCustomersOptions = Omit<UseQueryOptions<
    GetCustomersResponse,
    Error

    > , 'queryFn' | 'queryKey'>;

    /\*\*

    - Custom React Query hook for fetching customer(s)
    - @param customerId - (Optional) Fetch a specific customer by ID. If omitted, fetches all customers
    - @param options - Optional configuration options for useQuery
    - @returns The query object provided by TanStack Query
      \*/
      export const useGetCustomers = (
      customerId?: string,
      options?: UseGetCustomersOptions
      ) => {
      const apiKey = useApiKey();

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

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

          const response = await fetch(url.toString(), {
            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,

    });
    };

    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # Get a single customer by ID
    curl -X GET 'https://giant-goldfish-922.convex.site/api/customers?customerId=j97bp2fjzhbx59ayye52ag2gsd7ydw1c' \
      -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY'

    # List all customers in the app
    curl -X GET 'https://giant-goldfish-922.convex.site/api/customers' \
      -H 'Authorization: Bearer $YOUR_CREDIBILL_API_KEY'
    ```
  </Tab>
</Tabs>

### Response Examples

**Get Single Customer:**

```json theme={null}
{
  "customer": {
    "_id": "j97bp2fjzhbx59ayye52ag2gsd7ydw1c",
    "email": "jane.doe@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "phone": "+1234567890",
    "externalCustomerId": "app-user-12345",
    "metadata": {
      "plan": "premium",
      "signup_date": "2024-01-01"
    }
  }
}
```

**List All Customers:**

```json theme={null}
{
  "customers": [
    {
      "_id": "j97bp2fjzhbx59ayye52ag2gsd7ydw1c",
      "email": "jane.doe@example.com",
      "first_name": "Jane",
      "last_name": "Doe",
      "metadata": {}
    },
    {
      "_id": "k89cq3gkzhiys60bzuf53bh3hte8zx2d",
      "email": "john.smith@example.com",
      "first_name": "John",
      "last_name": "Smith",
      "metadata": {}
    }
  ]
}
```
