# Customer Data

Access and manage customer-related data including e-wallet balances, bulk imports, PDF tickets, and custom metadata.

### E-Wallet & Balance

Retrieve e-wallet automatic reload configuration and balance history for a customer. Balance history tracks all e-wallet transactions (credits, debits, refunds).

### `GET /customers/{customerId}/ewallet_automatic_reload` - Get E-Wallet Auto-Reload Config

Retrieve the automatic e-wallet reload configuration for a customer.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| customerId | integer | Yes | The unique identifier of the customer. |

#### Response

```json
{
  "status": 200,
  "code": "customer_ewallet_automatic_reload_succeed",
  "message": "Configuration retrieved successfully.",
  "data": {
    "automaticEwalletReloadActive": true,
    "automaticEwalletReloadMinBalance": 500,
    "automaticEwalletReloadAmount": 2000,
    "automaticEwalletReloadCardId": 12345
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customer\_ewallet\_automatic\_reload\_succeed" | Machine-readable application code for the result. |
| message | string | "Configuration retrieved successfully." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.automaticEwalletReloadActive | boolean | true | The automatic ewallet reload active value. |
| data.automaticEwalletReloadMinBalance | integer | 500 | The automatic ewallet reload min balance value. |
| data.automaticEwalletReloadAmount | integer | 2000 | The automatic ewallet reload amount value. |
| data.automaticEwalletReloadCardId | integer | 12345 | Identifier of the associated automatic ewallet reload card. |

##### Balance History

The full reference for `GET /customers/{customerId}/balance_history` (parameters, includes, and response schema) lives in the [E-Wallet Balance & Transactions](https://developers.innovorder.io/docs/e-wallet/ewallet-transactions.md) section.  
In addition to the parameters documented there, the endpoint supports `include=order` and a date-range filter using unix timestamps: `applyDate[gte]=1700000000&applyDate[lte]=1710000000`.

### `GET /customers/{customerId}/balance_history/count` - Get Balance History Count

Retrieve the total number of balance history entries for a customer. Useful for pagination.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| customerId | integer | Yes | The unique identifier of the customer. |

#### Response

```json
{
  "status": 200,
  "code": "balance_count_succeed",
  "message": "Balance count retrieved.",
  "data": {
    "total": 142
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "balance\_count\_succeed" | Machine-readable application code for the result. |
| message | string | "Balance count retrieved." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.total | integer | 142 | Total number of matching records. |

### Customer Import

Bulk import customers from a file. The endpoint accepts a file upload and processes it asynchronously, streaming progress updates back to the client via chunked transfer encoding.

#### Streaming Response

This endpoint uses `Transfer-Encoding: chunked` to stream progress updates during the import. The final chunk contains the standard JSON response with import results (customers created, updated, and unchanged).

### `POST /customers/import` - Import Customers from File

Upload a CSV/Excel file to bulk import customers for a brand. Requires a file in multipart/form-data format.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | Yes | The brand ID to import customers into. |
| isMultiBadge | boolean | No | If true, the file format supports multiple badges per customer. |
| autoImportGuestHierarchy | boolean | No | If true, automatically creates guest group hierarchy from the file data. |

#### Request Body

```json
multipart/form-data with a 'file' field containing the CSV or Excel file.
```

#### Response

```json
{
  "status": 200,
  "code": "customers_import_create_succeed",
  "message": "Import completed successfully.",
  "data": {
    "customersCreated": 15,
    "customersUpdated": 3,
    "customersUnchanged": 82
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customers\_import\_create\_succeed" | Machine-readable application code for the result. |
| message | string | "Import completed successfully." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.customersCreated | integer | 15 | The customers created value. |
| data.customersUpdated | integer | 3 | The customers updated value. |
| data.customersUnchanged | integer | 82 | The customers unchanged value. |

### `POST /customers/import_phoenix` - Import Phoenix Customer File

Upload a Phoenix-formatted customer file for a brand. The endpoint streams text progress chunks and ends with the standard JSON result payload.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | Yes | Brand that owns the imported customers. |

#### Request Body

```json
file=[binary]
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Required | Example | Description |
| --- | --- | --- | --- | --- |
| file | binary | Yes | \[binary\] | Phoenix-formatted customer file uploaded as multipart/form-data. |

#### Response

```json
{
  "status": 200,
  "code": "customers_import_create_succeed",
  "message": "Customers have been imported successfully.",
  "data": {
    "customersCreated": 15,
    "customersUpdated": 3,
    "customersUnchanged": 82,
    "customersError": [
      {
        "line": 7,
        "email": "invalid@example.com",
        "invalidFields": [
          "email"
        ]
      }
    ],
    "customersWarn": [
      {
        "line": 8,
        "email": "duplicate@example.com",
        "invalidFields": [
          "email"
        ]
      }
    ],
    "otherWarnings": [
      {
        "type": "pricingRule",
        "list": [
          "UNKNOWN-RULE"
        ]
      }
    ],
    "validationErrors": []
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customers\_import\_create\_succeed" | Machine-readable application code for the result. |
| message | string | "Customers have been imported successfully." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.customersCreated | integer | 15 | The customers created value. |
| data.customersUpdated | integer | 3 | The customers updated value. |
| data.customersUnchanged | integer | 82 | The customers unchanged value. |
| data.customersError | array | \[…\] | List of customers error entries. |
| data.customersError\[\] | object | {…} | Object containing customers error fields. |
| data.customersError\[\].line | integer | 7 | The line value. |
| data.customersError\[\].email | string | "invalid@example.com" | Email address. |
| data.customersError\[\].invalidFields | array | \[…\] | List of invalid fields entries. |
| data.customersError\[\].invalidFields\[\] | string | "email" | The invalid fields value. |
| data.customersWarn | array | \[…\] | List of customers warn entries. |
| data.customersWarn\[\] | object | {…} | Object containing customers warn fields. |
| data.customersWarn\[\].line | integer | 8 | The line value. |
| data.customersWarn\[\].email | string | "duplicate@example.com" | Email address. |
| data.customersWarn\[\].invalidFields | array | \[…\] | List of invalid fields entries. |
| data.customersWarn\[\].invalidFields\[\] | string | "email" | The invalid fields value. |
| data.otherWarnings | array | \[…\] | List of other warnings entries. |
| data.otherWarnings\[\] | object | {…} | Object containing other warnings fields. |
| data.otherWarnings\[\].type | string | "pricingRule" | The type value. |
| data.otherWarnings\[\].list | array | \[…\] | List of list entries. |
| data.otherWarnings\[\].list\[\] | string | "UNKNOWN-RULE" | The list value. |
| data.validationErrors | array | \[\] | List of validation errors entries. |

### Customer Base Export

Export a filtered customer base directly as CSV or XLSX. If a large export cannot complete within the synchronous request window, request the asynchronous report instead and retrieve it from report generation.

### `GET /customers/export` - Export Customer Base File

Returns a CSV or XLSX attachment. The export is scoped to the requested brand and supports the same filters as the customer list.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | Yes | Brand whose customers are exported. |
| fileType | string | Yes | Output format: csv or xlsx. |
| restaurantIds | string | No | Comma-separated restaurant IDs used to filter the export. |
| search | string | No | Free-text customer search filter. |
| groups | string | No | Comma-separated customer-group filters. |
| mustDisplayArchivedCustomers | boolean | No | Include archived customers when true. |

#### Response

```json
Binary attachment. Content-Type is text/csv for csv or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for xlsx; Content-Disposition contains the filename.
```

### `GET /customers/export/async` - Request Asynchronous Customer Base Export

Creates a report-generation request for the same export filters. Use this when the synchronous export times out or for large customer bases.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | Yes | Brand whose customers are exported. |
| fileType | string | Yes | Requested output format: csv or xlsx. |
| restaurantIds | string | No | Comma-separated restaurant IDs used to filter the export. |
| search | string | No | Free-text customer search filter. |
| groups | string | No | Comma-separated customer-group filters. |
| mustDisplayArchivedCustomers | boolean | No | Include archived customers when true. |

#### Response

```json
{
  "status": 200,
  "code": "customer_base_export_request_created",
  "message": "Customer base export request is created successfully."
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customer\_base\_export\_request\_created" | Machine-readable application code for the result. |
| message | string | "Customer base export request is created successfully." | Human-readable result message. Do not use this value for program logic. |

### Retrieve Generated Reports

An asynchronous export is made available through report generation. Brand and restaurant users see only reports they created. Admin and brand-group users must provide `brandId` when they do not have a brand context, and can include `impersonatedUserId` to see reports created by that user.

### `GET /report_generation` - List Generated Reports

Lists generated report files in the caller scope. Customer-base export reports become expired after their retention window; use expired to avoid requesting an unavailable download.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | No | Brand context required for an admin or brand-group user who has no own brand. |
| impersonatedUserId | integer | No | Optional impersonated user whose reports are included for an authorized admin or brand-group caller. |

#### Response

```json
{
  "status": 200,
  "code": "report_generations_succeed",
  "message": "The list of report generations have been found.",
  "data": [
    {
      "reportGenerationId": 812,
      "name": "customer-base-export-3325-2026-07-11.xlsx",
      "createdAt": "Fri Jul 11 2026 09:15:00 GMT+0000 (Coordinated Universal Time)",
      "reportType": "customer_base_export",
      "status": "succeed",
      "expired": false
    }
  ]
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "report\_generations\_succeed" | Machine-readable application code for the result. |
| message | string | "The list of report generations have been found." | Human-readable result message. Do not use this value for program logic. |
| data | array | \[…\] | Endpoint-specific response payload. |
| data\[\] | object | {…} | Endpoint-specific response payload. |
| data\[\].reportGenerationId | integer | 812 | Identifier of the associated report generation. |
| data\[\].name | string | "customer-base-export-3325-2026-07-11.xlsx" | The name value. |
| data\[\].createdAt | string | "Fri Jul 11 2026 09:15:00 GMT+0000 (Coordinated Universal Time)" | Timestamp when this resource was created. |
| data\[\].reportType | string | "customer\_base\_export" | The report type value. |
| data\[\].status | string | "succeed" | HTTP status code returned by the API. |
| data\[\].expired | boolean | false | The expired value. |

### `GET /report_generation/{reportGenerationId}/signed-url` - Get Generated Report Download URL

Returns a time-limited signed URL for a generated report after verifying that the report belongs to the requested brand and to the caller (or authorized impersonated user). Expired or missing files cannot be downloaded.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| reportGenerationId | integer | Yes | Generated report identifier returned by the list endpoint. |
| brandId | integer | No | Brand context required for an admin or brand-group user who has no own brand. |
| impersonatedUserId | integer | No | Optional impersonated user whose report is being downloaded by an authorized caller. |

#### Response

```json
{
  "status": 200,
  "code": "report_generations_succeed",
  "message": "The list of report generations have been found.",
  "data": {
    "url": "https://storage.googleapis.com/<signed-report-url>"
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "report\_generations\_succeed" | Machine-readable application code for the result. |
| message | string | "The list of report generations have been found." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.url | string | "https://storage.googleapis.com/&lt;signed-report-url&gt;" | The url value. |

### `POST /customers/{customerId}/unarchive` - Unarchive Customer

Restores an archived customer. Brand and brand-group users may only restore a customer in a brand they are authorized to manage.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| customerId | integer | Yes | Archived customer to restore. |

#### Response

```json
{
  "status": 200,
  "code": "customer_unarchive_succeed",
  "message": "Customer has been successfully unarchived.",
  "data": {
    "success": true
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customer\_unarchive\_succeed" | Machine-readable application code for the result. |
| message | string | "Customer has been successfully unarchived." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.success | boolean | true | The success value. |

### Customer Tickets

Generate PDF receipts for individual orders or export a customer's receipt history as a PDF. Bulk exports can be counted and paginated before downloading to keep large histories manageable.

### Single Ticket PDF

### `GET /orders/tickets/{orderId}` - Get Ticket PDF

Generate and download a PDF receipt for a specific order. Returns the file directly as application/pdf.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| orderId | string | Yes | The unique identifier of the order. |

#### Response

```json
Binary PDF file (Content-Type: application/pdf). The response is an attachment; read the filename from the Content-Disposition response header.
```

* * *

### Bulk PDF Export

First count the selected customer history, then request a PDF. For very large histories, use`limit` and `offset` to retrieve bounded batches. A date range must include both`startDate` and `endDate`.

### `GET /orders/tickets/export/count` - Count Tickets Available for Export

Returns the number of customer tickets matching the optional inclusive ISO-date range.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| customerId | integer | Yes | Customer whose tickets are counted. |
| startDate | string | No | ISO 8601 start of the export range. Required together with endDate. |
| endDate | string | No | ISO 8601 end of the export range. Required together with startDate. |

#### Response

```json
{
  "count": 142
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| count | integer | 142 | Total number of matching records. |

### `POST /orders/tickets/export` - Download Customer Ticket History PDF

Generates a PDF attachment for the selected customer history. The X-Total-Count response header contains the total matching records before pagination; Content-Disposition contains the filename.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| customerId | integer | Yes | Customer whose tickets are exported. |
| startDate | string | No | ISO 8601 start of the export range. Required together with endDate. |
| endDate | string | No | ISO 8601 end of the export range. Required together with startDate. |
| limit | integer | No | Positive maximum number of tickets included in this PDF batch. |
| offset | integer | No | Zero-based number of matching tickets to skip before this batch. |

#### Response

```json
Binary PDF file (Content-Type: application/pdf). Read the total matching ticket count from X-Total-Count and the filename from Content-Disposition.
```

### Customer Metadata

Store and retrieve arbitrary metadata for a customer within a specific brand context. Metadata is stored as a free-form string and can be organized by namespace.

#### Namespaces

The optional `namespace` field allows you to organize metadata into logical groups (e.g., "preferences", "loyalty", "external\_ids"). When deleting, you can target a specific namespace or remove all metadata at once.

### `POST /brands/{brandId}/customers/{customerId}/metadata` - Save Customer Metadata

Create or update metadata for a customer. If metadata with the same namespace already exists, it will be overwritten.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | Yes | The brand ID. |
| customerId | integer | Yes | The unique identifier of the customer. |

#### Request Body

```json
{
  "data": "{\"preferredLanguage\":\"fr\",\"dietaryRestrictions\":[\"vegetarian\"]}",
  "namespace": "preferences"
}
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| data | string | "{\\"preferredLanguage\\":\\"fr\\",\\"dietaryRestrictions\\":\[\\"vegetarian\\"\]}" | Endpoint-specific response payload. |
| namespace | string | "preferences" | The namespace value. |

#### Response

```json
{
  "status": 200,
  "code": "customer_metadata_saved",
  "message": "Metadata saved successfully.",
  "data": {
    "customerMetadataId": 1234,
    "customerId": 5337578,
    "brandId": 100,
    "data": "{\"preferredLanguage\":\"fr\",\"dietaryRestrictions\":[\"vegetarian\"]}",
    "namespace": "preferences"
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customer\_metadata\_saved" | Machine-readable application code for the result. |
| message | string | "Metadata saved successfully." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.customerMetadataId | integer | 1234 | Identifier of the associated customer metadata. |
| data.customerId | integer | 5337578 | Identifier of the customer. |
| data.brandId | integer | 100 | Identifier of the brand. |
| data.data | string | "{\\"preferredLanguage\\":\\"fr\\",\\"dietaryRestrictions\\":\[\\"vegetarian\\"\]}" | Endpoint-specific response payload. |
| data.namespace | string | "preferences" | The namespace value. |

### `GET /brands/{brandId}/customers/{customerId}/metadata` - Get Customer Metadata

Retrieve all metadata entries for a customer within a brand.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | Yes | The brand ID. |
| customerId | integer | Yes | The unique identifier of the customer. |

#### Response

```json
{
  "status": 200,
  "code": "customer_metadata_fetched",
  "message": "Metadata retrieved successfully.",
  "data": [
    {
      "customerMetadataId": 1234,
      "customerId": 5337578,
      "brandId": 100,
      "data": "{\"preferredLanguage\":\"fr\",\"dietaryRestrictions\":[\"vegetarian\"]}",
      "namespace": "preferences"
    },
    {
      "customerMetadataId": 1235,
      "customerId": 5337578,
      "brandId": 100,
      "data": "{\"externalId\":\"EXT-99887\"}",
      "namespace": "external_ids"
    }
  ]
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customer\_metadata\_fetched" | Machine-readable application code for the result. |
| message | string | "Metadata retrieved successfully." | Human-readable result message. Do not use this value for program logic. |
| data | array | \[…\] | Endpoint-specific response payload. |
| data\[\] | object | {…} | Endpoint-specific response payload. |
| data\[\].customerMetadataId | integer | 1234 | Identifier of the associated customer metadata. |
| data\[\].customerId | integer | 5337578 | Identifier of the customer. |
| data\[\].brandId | integer | 100 | Identifier of the brand. |
| data\[\].data | string | "{\\"preferredLanguage\\":\\"fr\\",\\"dietaryRestrictions\\":\[\\"vegetarian\\"\]}" | Endpoint-specific response payload. |
| data\[\].namespace | string | "preferences" | The namespace value. |

### `DELETE /brands/{brandId}/customers/{customerId}/metadata` - Delete Customer Metadata

Delete metadata for a customer. Optionally filter by namespace to only delete a specific set.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| brandId | integer | Yes | The brand ID. |
| customerId | integer | Yes | The unique identifier of the customer. |
| namespace | string | No | If provided, only metadata with this namespace will be deleted. If omitted, all metadata for the customer is deleted. |

#### Response

```json
{
  "status": 200,
  "code": "customer_metadata_deleted",
  "message": "Metadata deleted successfully.",
  "data": {}
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "customer\_metadata\_deleted" | Machine-readable application code for the result. |
| message | string | "Metadata deleted successfully." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
