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

# Upload Cards CSV

> Bulk upload NFC cards via CSV file

<Info>
  Admin endpoint for bulk importing NFC cards into the system. Cards are created with status "Unassigned".
</Info>

## Request

<ParamField header="Authorization" type="string" required>
  `Bearer olive_live_xxx` or `Bearer eyJ...` (JWT)
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `multipart/form-data`
</ParamField>

### Form Data

<ParamField body="file" type="file" required>
  CSV file with card data
</ParamField>

***

## CSV Format

```csv theme={null}
Serial No.,MAC Address
OLIV0001,AA:BB:CC:DD:EE:01
OLIV0002,AA:BB:CC:DD:EE:02
OLIV0003,AA:BB:CC:DD:EE:03
```

### Column Requirements

| Column      | Format                                   | Required |
| ----------- | ---------------------------------------- | -------- |
| Serial No.  | Alphanumeric (e.g., `OLIV0001`)          | Yes      |
| MAC Address | 6-octet (`AA:BB:CC:DD:EE:FF`) or 7-octet | Yes      |

<Info>
  MAC addresses can use colons (`:`) or hyphens (`-`) as separators.
</Info>

***

## Response

<ResponseField name="success" type="boolean">
  Whether upload succeeded
</ResponseField>

<ResponseField name="message" type="string">
  Summary message
</ResponseField>

<ResponseField name="total" type="integer">
  Total rows in CSV
</ResponseField>

<ResponseField name="created" type="integer">
  Successfully created cards
</ResponseField>

<ResponseField name="errors" type="array">
  List of rows with errors
</ResponseField>

***

## Examples

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://demo.api.vultlocal.com/api/v1/cards/upload-csv" \
    -H "Authorization: Bearer olive_live_xxx" \
    -F "file=@cards.csv"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "success": true,
    "message": "Cards uploaded successfully",
    "total": 100,
    "created": 98,
    "errors": [
      {
        "row": 15,
        "serial": "OLIV0015",
        "error": "Duplicate serial number"
      },
      {
        "row": 42,
        "serial": "OLIV0042",
        "error": "Invalid MAC address format"
      }
    ]
  }
  ```

  ```json 400 Invalid File theme={null}
  {
    "error": "Invalid CSV format",
    "code": "INVALID_CSV",
    "details": "Missing required column: MAC Address"
  }
  ```
</ResponseExample>

***

## Validation Rules

<CardGroup cols={2}>
  <Card title="Serial Number" icon="hash">
    * Must be unique in system
    * Alphanumeric characters
    * No special characters
  </Card>

  <Card title="MAC Address" icon="wifi">
    * Valid hex octets
    * 6 or 7 octets supported
    * Colons or hyphens allowed
  </Card>
</CardGroup>

***

## Best Practices

<AccordionGroup>
  <Accordion title="File Size" icon="file">
    * Keep files under 10,000 rows for best performance
    * Split larger imports into batches
  </Accordion>

  <Accordion title="Error Handling" icon="alert-triangle">
    * Review errors array after upload
    * Fix invalid rows and re-upload
    * Valid rows are still created even if some fail
  </Accordion>

  <Accordion title="Duplicate Detection" icon="copy">
    * Serial numbers must be unique
    * Duplicates in CSV are rejected
    * Existing cards in system are skipped
  </Accordion>
</AccordionGroup>

***

## Permissions

<Warning>
  Only users with `system_admin` role can upload cards.
</Warning>

***

## Errors

| Status | Code             | Description                   |
| ------ | ---------------- | ----------------------------- |
| 400    | `INVALID_CSV`    | CSV format or structure error |
| 400    | `MISSING_FILE`   | No file uploaded              |
| 401    | `UNAUTHORIZED`   | Invalid API key               |
| 403    | `FORBIDDEN`      | Not authorized to upload      |
| 413    | `FILE_TOO_LARGE` | File exceeds size limit       |
| 500    | `INTERNAL_ERROR` | Server error                  |


## OpenAPI

````yaml olive-openapi.json POST /cards/upload-csv
openapi: 3.0.0
info:
  description: >-
    API Gateway for OLIVE NFC Card Payment System - Comprehensive payment, card
    management, agent operations, and admin authentication. All /api/v1 routes
    require authentication using either API Key or JWT token.
  title: OLIVE NFC Card Payment API
  termsOfService: http://swagger.io/terms/
  contact:
    name: API Support
    email: support@olive.sl
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 1.0.0
servers:
  - url: https://olive-gateway-a6ba.onrender.com/api/v1
security: []
paths:
  /cards/upload-csv:
    post:
      tags:
        - Cards
      summary: Upload NFC cards via CSV file
      description: >-
        Admin uploads CSV file containing Serial No. and MAC Address (supports
        both 6-octet and 7-octet formats). Valid records are inserted with
        status = "Unassigned"
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  description: 'CSV file with columns: serial_number, mac_address'
                  type: string
                  format: binary
                batch_id:
                  description: Batch identifier
                  type: string
              required:
                - file
                - batch_id
        required: true
      responses:
        '200':
          description: Upload successful with error log if any
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Invalid CSV format
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
components:
  securitySchemes:
    ApiKeyAuth:
      description: >-
        API Key for third-party integrations (WhatsApp, Smart PAY, VULT).
        Format: 'Bearer olive_live_xxxxxxxxxxxxx'
      type: apiKey
      name: Authorization
      in: header
    BearerAuth:
      description: >-
        JWT token from admin login for administrative operations. Format:
        'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
      type: apiKey
      name: Authorization
      in: header

````