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

# Quickstart: Validate Your First License with Avalex

> Learn how to validate your first software license with Avalex in under 5 minutes using the REST API or a ready-made integration example.

This guide walks you through the complete Avalex workflow from a fresh installation to your first successful license validation. By the end, you will have authenticated with the API, created a product and a customer, issued a license, and confirmed that the validation endpoint returns `{"valid": true}` — the signal your application will rely on at runtime. All examples use `curl` against the default base URL `http://localhost:8080`.

<Steps>
  <Step title="Log In and Obtain a JWT">
    Send your admin credentials to `POST /auth/login`. Avalex returns a JWT that is valid for **7 days**. Copy the `token` value — you will pass it as a `Bearer` token in every subsequent authenticated request.

    ```bash theme={null}
    curl -s -X POST http://localhost:8080/auth/login \
      -H "Content-Type: application/json" \
      -d '{"username": "ada", "password": "a-strong-password"}'
    ```

    **Response:**

    ```json theme={null}
    {
      "token": "eyJhbGci...",
      "user": {
        "username": "ada",
        "isMasterAdmin": false,
        "permissions": ["customers:read", "customers:write"],
        "role": "Support"
      }
    }
    ```

    Store the token in an environment variable so you can reuse it cleanly across the steps below:

    ```bash theme={null}
    TOKEN="eyJhbGci..."
    ```
  </Step>

  <Step title="Create a Product">
    Define the software product you want to license. Set `requiresLicense: true` to enforce validation, and choose slot limits for IP addresses and hardware identifiers. Use `null` for either limit to allow unlimited activations.

    ```bash theme={null}
    curl -s -X POST http://localhost:8080/products \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $TOKEN" \
      -d '{
        "name": "My Desktop App",
        "productType": "desktop",
        "description": "A desktop application requiring a valid license to run.",
        "price": 49.99,
        "requiresLicense": true,
        "isSubscription": false,
        "recurringPeriodDays": null,
        "maxIps": 3,
        "maxHwids": 2
      }'
    ```

    Note the `id` field in the response (e.g., `prod_67890`). You will use it when issuing and validating licenses.
  </Step>

  <Step title="Create a Customer">
    Add the customer who will receive the license. At minimum, provide a display name and an email address.

    ```bash theme={null}
    curl -s -X POST http://localhost:8080/customers \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $TOKEN" \
      -d '{
        "name": "Acme Corp",
        "email": "billing@acme.example"
      }'
    ```

    Note the `id` field in the response (e.g., `cust_11111`). You will link this customer to the license in the next step.
  </Step>

  <Step title="Issue a License">
    Create a license that ties a specific product to a specific customer. Provide the expiration date as a Unix epoch timestamp in milliseconds.

    ```bash theme={null}
    curl -s -X POST http://localhost:8080/licenses \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $TOKEN" \
      -d '{
        "productId": "prod_67890",
        "customerId": "cust_11111",
        "expiresAtEpochMillis": 1893456000000
      }'
    ```

    The response includes the new license's `id` (e.g., `lic_12345`). This is the value your end-user's application will present at validation time.
  </Step>

  <Step title="Validate the License">
    Call `POST /licenses/validate` with the license ID, the product ID, and the hardware identifier computed on the end-user's machine. This endpoint is **public and unauthenticated** — do not include credentials in your distributed application.

    ```bash theme={null}
    curl -s -X POST http://localhost:8080/licenses/validate \
      -H "Content-Type: application/json" \
      -d '{
        "licenseId": "lic_12345",
        "productId": "prod_67890",
        "hwid": "HWID-A1B2-C3D4"
      }'
    ```

    **Success response (license is valid):**

    ```json theme={null}
    { "valid": true }
    ```

    **Response when the license is not valid** (expired, wrong product, or slots exhausted):

    ```json theme={null}
    { "valid": false }
    ```

    If you exceed the rate limit (30 requests per minute per IP), the endpoint returns:

    ```json theme={null}
    { "error": "Too many validation attempts. Try again shortly." }
    ```

    A `valid: true` response means the license passed all checks: the product ID matched, the license has not expired, and the IP and HWID slots were either already bound to this client or had room for a new binding.
  </Step>
</Steps>

<Tip>
  Cache the last successful validation response locally on the end-user's machine and allow a **24–72 hour grace period** before blocking access. This keeps your application functional when the user is temporarily offline or your server is briefly unreachable, without meaningfully weakening license enforcement.
</Tip>

## Next Steps

<Card title="Integration Overview" icon="arrow-right" href="/integration/overview">
  Learn how to embed license validation into your application, handle edge cases like offline mode and HWID resets, and explore SDK examples for popular languages.
</Card>
