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

# Quickstart

> Enroll a customer and award their first stamp - five minutes, three requests.

This walkthrough wires the smallest real integration: create a customer on your stamp card, award a stamp when they buy, and watch the event arrive. Use your API key from **Settings → Developer → API keys**, or a sandbox key (`vxn_test_sk_...`) if you would rather run it away from real customers first (see [Testing and environments](https://vexioncards.mintlify.site/api-reference/test-mode.md)).

## Anatomy of your first call

Every step below is the same four-beat pattern: grab your key once, put it on every request, call an endpoint, read what comes back. Once this loop feels automatic, the rest of the API is just new endpoints inside it.

```mermaid theme={null}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E5F6FF','primaryBorderColor':'#36C6FA','primaryTextColor':'#0B3A4A','lineColor':'#2BA8D9','secondaryColor':'#F4FCFF','tertiaryColor':'#FFFFFF','fontFamily':'Manrope, ui-sans-serif, system-ui, sans-serif'}}}%%
sequenceDiagram
    participant You
    participant Dashboard
    participant API as api.vexioncards.one

    You->>Dashboard: Settings → Developer → API keys
    Dashboard-->>You: vxn_sk_... (vxn_test_sk_... in sandbox)
    You->>API: Authorization: Bearer $VXN_API_KEY
    Note right of You: e.g. GET /v1/cards
    API-->>You: 200 OK · JSON body · Vexion-Request-Id
    Note over You: Read the response - grab the id<br/>the next call needs (card_id, customer_id, ...)
```

> [!TIP]
>
> Set `VXN_API_KEY` once as an environment variable and every `curl` below just works: `export VXN_API_KEY=vxn_test_sk_...`

**1. Find your card id**

```bash theme={null}
curl https://api.vexioncards.one/v1/cards \
  -H "Authorization: Bearer $VXN_API_KEY"
```

Grab the `id` of your stamp card (`crd_...`) from the response.

**2. Enroll a customer**

`POST /v1/customers` is an **upsert** - the same call from your checkout can run on every order, and the dedupe key (external\_id → email → phone, scoped to the card) makes it idempotent:

```bash theme={null}
curl -X POST https://api.vexioncards.one/v1/customers \
  -H "Authorization: Bearer $VXN_API_KEY" \
  -H "Idempotency-Key: order-1001-enroll" \
  -H "Content-Type: application/json" \
  -d '{
    "card_id": "crd_YOUR_STAMP_CARD",
    "email": "jana@example.com",
    "first_name": "Jana"
  }'
```

The response includes `claim_url`. Send it to the customer yourself, or add `"deliver": { "channel": "email" }` to the request and we email it. When the customer opens the link, the pass lands in their Apple or Google Wallet.

> [!NOTE]
>
> **Good to know:** if the business has Dotykačka connected and customer sync is on, a customer created through `POST /v1/customers` (or the MCP `create_customer` tool) appears in Dotykačka within about 5 minutes, the same way as a customer who signs up through the card. Only the card types that the Dotykačka integration syncs are sent. VEXiON matches by its own customer id, so a person that staff already created directly in Dotykačka gets a second record there. A later change of the name, email, phone or birthday through the API goes to Dotykačka the same way. If the business has Papaya connected, the customer is also added to Papaya, and a change of name or email reaches Papaya too. A new customer with an email or phone that is not valid gets that field left empty in Dotykačka. For a customer Dotykačka already has, a valid value goes to Dotykačka; an email or phone that is not valid is not sent, and Dotykačka keeps the value it has.

**3. Award a stamp**

```bash theme={null}
curl -X POST https://api.vexioncards.one/v1/transactions \
  -H "Authorization: Bearer $VXN_API_KEY" \
  -H "Idempotency-Key: order-1001-stamp" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "cus_FROM_STEP_2",
    "action": "award",
    "value": 1
  }'
```

The server computes everything else - the response carries `type: "stamp.add"` and `balance_after.stamps_collected`. Once the customer has added the pass, it updates and their lock screen shows the banner.

**4. Hear about it (optional)**

Register a webhook receiver and prove it in one call:

```bash theme={null}
curl -X POST https://api.vexioncards.one/v1/webhook_endpoints \
  -H "Authorization: Bearer $VXN_API_KEY" \
  -H "Idempotency-Key: wh-setup-1" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://yourapp.example/webhooks", "enabled_events": ["transaction.created"] }'
# → store the whsec_ secret from the response, then:
curl -X POST https://api.vexioncards.one/v1/webhook_endpoints/{id}/test \
  -H "Authorization: Bearer $VXN_API_KEY" -H "Idempotency-Key: wh-test-1"
```

## Where next

> [card] [Transactions](https://vexioncards.mintlify.site/api-reference/transactions/create-a-transaction.md)
>
> Every loyalty event, one endpoint.

> [card] [Webhooks](https://vexioncards.mintlify.site/api-reference/webhooks.md)
>
> Signatures, retries, the 22-event catalog.

> [card] [Testing and environments](https://vexioncards.mintlify.site/api-reference/test-mode.md)
>
> The sandbox, and how to go live.

> [card] [Idempotency](https://vexioncards.mintlify.site/api-reference/idempotency.md)
>
> Why every POST carries the key.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.