Filter Excel files and get matching rows as JSON.
Upload an Excel spreadsheet, define one or more filters, and receive the matching rows as structured JSON. Built for applications that need to process Excel data without manually opening or manipulating spreadsheets.
Upload your Excel file
Send an .xlsx file to the filtering
endpoint using a multipart form request.
Define your filters
Specify the worksheet, column, filter name, and values you want to match.
Receive matching rows
The API returns each filter's matching rows together with the total number of matching rows.
How it works
The API processes the uploaded Excel workbook synchronously. Your request contains the Excel file and the filters you want to apply. The API validates the workbook, applies each filter independently, and immediately returns the matching rows.
Filter behavior
| Behavior | Description |
|---|---|
| Multiple filters | Each filter is evaluated independently and gets its own result in the response. |
| Multiple values | Values within a filter use OR matching. |
| Empty values |
values: [] matches every value
in the specified column, including blank cells.
|
| Column matching |
Column names are case-sensitive.
Status and status
are different columns.
|
| Value matching | Values are compared using their actual types rather than converting everything to strings. |
| Duplicate rows | Duplicate Excel rows are preserved. The API does not deduplicate results. |
Your first request
The following example filters an Excel spreadsheet
using the Status column and returns
separate results for successful and failed rows.
import json
import requests
url = "https://filterapi.zendix.app/v1/filter/"
headers = {
"Authorization": "Bearer YOUR_API_KEY"
}
filters = [
{
"name": "successful",
"column": "Status",
"values": ["successful"]
},
{
"name": "failed",
"column": "Status",
"values": ["failed"]
}
]
with open("transactions.xlsx", "rb") as excel_file:
response = requests.post(
url,
headers=headers,
files={
"file": (
"transactions.xlsx",
excel_file,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
},
data={
"filters": json.dumps(filters)
},
timeout=60
)
print(response.json())
const formData = new FormData();
const filters = [
{
name: "successful",
column: "Status",
values: ["successful"]
},
{
name: "failed",
column: "Status",
values: ["failed"]
}
];
formData.append(
"filters",
JSON.stringify(filters)
);
formData.append(
"file",
fileInput.files[0]
);
const response = await fetch(
"https://filterapi.zendix.app/v1/filter/",
{
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY"
},
body: formData
}
);
const data = await response.json();
console.log(data);
curl -X POST https://filterapi.zendix.app/v1/filter/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@transactions.xlsx" \
-F 'filters=[{"name":"successful","column":"Status","values":["successful"]},{"name":"failed","column":"Status","values":["failed"]}]'
{
"success": true,
"data": {
"successful": {
"rows": [
{
"ID": 1,
"Customer": "John",
"Status": "successful",
"Amount": 5000
}
],
"total_rows": 1
},
"failed": {
"rows": [
{
"ID": 2,
"Customer": "Mary",
"Status": "failed",
"Amount": 3000
}
],
"total_rows": 1
}
}
}
Authentication
All API requests must include your API key in the
Authorization header using the Bearer format.
Your API keys should be kept secret and secure. Never expose them in frontend applications, public repositories, or client-side code.
Create an API key
Create or obtain an API key from your account dashboard.
Include it in requests
Send the key using the
Authorization: Bearer YOUR_API_KEY
header.
headers = {
"Authorization": "Bearer YOUR_API_KEY"
}
const headers = {
Authorization: "Bearer YOUR_API_KEY"
};
curl https://filterapi.zendix.app/v1/filter/ \
-H "Authorization: Bearer YOUR_API_KEY"
Authentication errors
Requests with missing or invalid API keys are rejected with a standardized error response.
{
"success": false,
"error": {
"code": "authentication_failed",
"message": "Invalid API key."
}
}
Filter Excel
Filter an Excel workbook by one or more column values.
The endpoint accepts an .xlsx file using
multipart form data and returns matching rows as JSON.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
file
|
File | yes |
The Excel workbook to filter.
Only .xlsx files are supported.
|
sheet
|
string | optional | The worksheet to process. If omitted, the first worksheet in the workbook is used. |
filters
|
JSON array | yes | A list containing one or more filter objects. |
Filter object
Each object inside filters defines one
independent result group.
| Field | Type | Required | Description |
|---|---|---|---|
name
|
string | yes | Name of the result group. It becomes the key in the response. Names must be unique and must not exceed 100 characters. |
column
|
string | yes | The exact column name to filter. Column matching is case-sensitive. |
values
|
array | yes | Values to match in the specified column. Multiple values are treated as OR conditions. |
If values is an empty array,
the filter matches every row where the specified
column exists, including rows where that cell is blank.
Example request
{
"sheet": "Transactions",
"filters": [
{
"name": "successful",
"column": "Status",
"values": ["successful"]
},
{
"name": "failed",
"column": "Status",
"values": ["failed"]
}
]
}
Multiple values
Multiple values inside the same filter are treated as OR conditions.
{
"name": "pending_or_failed",
"column": "Status",
"values": ["pending", "failed"]
}
This matches rows where Status is either
pending or failed.
Filter matching
Values are compared using their actual types. The API does not convert Excel values and filter values into strings before comparison.
| Excel value | Filter value | Match |
|---|---|---|
500 |
500 |
Yes |
500.0 |
500 |
Yes |
"500" |
500 |
No |
true |
1 |
No |
"successful" |
"successful" |
Yes |
Excel structure requirements
The workbook must follow a predictable structure so that no spreadsheet data is silently discarded.
- Row 1 must contain the column headers.
- Column names must be unique and are case-sensitive.
- Completely empty rows are ignored.
- Completely empty columns are ignored.
-
Blank cells inside named columns are valid and are
returned as
null. - Data under an unnamed column is rejected.
- Data beyond the range covered by the header cells is rejected.
- Duplicate rows are preserved.
If the workbook contains data that does not belong to a named column, the API rejects the workbook instead of silently ignoring that data.
Request examples
import json
import requests
url = "https://filterapi.zendix.app/v1/filter/"
headers = {
"Authorization": "Bearer YOUR_API_KEY"
}
filters = [
{
"name": "successful",
"column": "Status",
"values": ["successful"]
},
{
"name": "failed",
"column": "Status",
"values": ["failed"]
}
]
with open("transactions.xlsx", "rb") as excel_file:
response = requests.post(
url,
headers=headers,
files={
"file": (
"transactions.xlsx",
excel_file,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
},
data={
"sheet": "Transactions",
"filters": json.dumps(filters)
},
timeout=60
)
print(response.status_code)
print(response.json())
const formData = new FormData();
const filters = [
{
name: "successful",
column: "Status",
values: ["successful"]
},
{
name: "failed",
column: "Status",
values: ["failed"]
}
];
formData.append(
"sheet",
"Transactions"
);
formData.append(
"filters",
JSON.stringify(filters)
);
formData.append(
"file",
fileInput.files[0]
);
const response = await fetch(
"https://filterapi.zendix.app/v1/filter/",
{
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY"
},
body: formData
}
);
const data = await response.json();
console.log(data);
curl -X POST https://filterapi.zendix.app/v1/filter/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@transactions.xlsx" \
-F "sheet=Transactions" \
-F 'filters=[{"name":"successful","column":"Status","values":["successful"]},{"name":"failed","column":"Status","values":["failed"]}]'
Response
Each filter name becomes a key inside
data. Every result contains the matching
rows and the number of matching rows.
{
"success": true,
"data": {
"successful": {
"rows": [
{
"ID": 1,
"Customer": "John",
"Status": "successful",
"Amount": 5000
},
{
"ID": 3,
"Customer": "David",
"Status": "successful",
"Amount": 7200
}
],
"total_rows": 2
},
"failed": {
"rows": [
{
"ID": 2,
"Customer": "Mary",
"Status": "failed",
"Amount": 3000
}
],
"total_rows": 1
}
}
}
Rate limiting
The API enforces rate limits to help maintain fair usage, reliability, and system stability.
Each user has its own request limit. Requests from different users are tracked separately.
| Type | Rate Limit | Window |
|---|---|---|
| User | 60 requests | per minute |
Each user can make a maximum of 60 requests per minute.
File & data limits
The API enforces limits on uploaded workbooks and the amount of spreadsheet data processed in a request.
| Limit | Value |
|---|---|
| Maximum file size | 5 MB |
| Maximum data rows | 10,000 non-empty rows |
| Supported format |
.xlsx
|
| Header row | Row 1 |
Completely empty rows are ignored and do not count toward the 10,000-row maximum.
What happens when a limit is exceeded?
The API rejects the request and returns a standardized error response. No partial result is returned.
Error codes
Errors follow a standardized structure to make failures predictable and easy to handle programmatically.
{
"success": false,
"error": {
"code": "error_code",
"message": "Human readable message"
}
}
Common error codes
| Code | Meaning |
|---|---|
validation_error
|
The request data is invalid or a required field is missing. |
method_not_allowed
|
The HTTP method is not supported by the endpoint. |
rate_limit_exceeded
|
The API key has exceeded its allowed request rate. |
authentication_failed
|
The API key is missing or invalid. |
parse_error
|
The request body or multipart form data could not be parsed. |
invalid_workbook
|
The uploaded file is not a valid readable
.xlsx workbook.
|
sheet_not_found
|
The requested worksheet does not exist in the workbook. |
column_not_found
|
A requested filter column does not exist in the selected worksheet. |
duplicate_column
|
The worksheet contains duplicate column names. |
unnamed_column
|
The worksheet contains data under an unnamed column or beyond the header range. |
row_limit_exceeded
|
The worksheet contains more than 10,000 non-empty data rows. |
Example errors
{
"success": false,
"error": {
"code": "column_not_found",
"message": "Column 'Status' was not found in worksheet 'Transactions'."
}
}
{
"success": false,
"error": {
"code": "invalid_workbook",
"message": "The uploaded file is not a valid .xlsx workbook."
}
}
{
"success": false,
"error": {
"code": "row_limit_exceeded",
"message": "Worksheet 'Transactions' contains more than 10,000 data rows."
}
}