API Reference
Authenticated, rate-limited access to your tag and metafield change history. Query events, filter by resource, and integrate with your existing tools. Scoped per-store with rotating API keys.
Quick Start
Get up and running in under a minute.
Create an API key
Once API access is enabled on your account, open the Beemlo app in Shopify Admin, go to Settings → API Access, and create a new key. Copy it immediately. It's only shown once.
Make your first request
Fetch the 5 most recent tag events:
curl "https://api.beemlo.com/v1/events/tags?limit=5" \ -H "Authorization: Bearer bml_sk_your_api_key_here"
const res = await fetch("https://api.beemlo.com/v1/events/tags?limit=5", { headers: { "Authorization": "Bearer bml_sk_your_api_key_here" } }); const { data } = await res.json();
import requests r = requests.get( "https://api.beemlo.com/v1/events/tags", headers={"Authorization": "Bearer bml_sk_your_api_key_here"}, params={"limit": 5} ) data = r.json()["data"]
Paginate through results
Use offset to page through all events. Keep incrementing until has_more is false:
# Page 1 curl "https://api.beemlo.com/v1/events/tags?limit=50&offset=0" \ -H "Authorization: Bearer bml_sk_your_api_key_here" # Page 2 curl "https://api.beemlo.com/v1/events/tags?limit=50&offset=50" \ -H "Authorization: Bearer bml_sk_your_api_key_here"
const API_KEY = "bml_sk_your_api_key_here"; const allEvents = []; let offset = 0; while (true) { const res = await fetch( `https://api.beemlo.com/v1/events/tags?limit=100&offset=${offset}`, { headers: { "Authorization": `Bearer ${API_KEY}` } } ); const page = await res.json(); allEvents.push(...page.data); if (!page.has_more) break; offset += 100; }
import requests API_KEY = "bml_sk_your_api_key_here" all_events = [] offset = 0 while True: r = requests.get( "https://api.beemlo.com/v1/events/tags", headers={"Authorization": f"Bearer {API_KEY}"}, params={"limit": 100, "offset": offset} ) page = r.json() all_events.extend(page["data"]) if not page["has_more"]: break offset += 100
Authentication
Authenticate by including your API key in the Authorization header as a Bearer token. API keys are created in your Beemlo app under Settings → API Access once your account has been upgraded.
Keys use the prefix bml_sk_ followed by a cryptographically random string. The full key is shown only once at creation, so store it securely.
Authorization: Bearer bml_sk_your_api_key_here
If the key is missing, invalid, or revoked, you'll receive a 401 response:
{
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
}
Rate Limiting
The API allows 120 requests per key per minute using fixed 1-minute windows. Every response includes rate limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per window (120) |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets |
When the limit is exceeded, you'll receive a 429 response with a Retry-After header:
HTTP/1.1 429 Too Many Requests Retry-After: 34 X-RateLimit-Limit: 120 X-RateLimit-Remaining: 0 { "error": { "type": "rate_limit", "message": "Rate limit exceeded. Retry after 34s." } }
Pagination
All list endpoints use offset-based pagination. Control page size with limit (1–100, default 50) and skip results with offset (default 0).
Every list response includes:
{
"object": "list",
"data": [...],
"total": 1542,
"has_more": true,
"limit": 50,
"offset": 0
}
To fetch the next page, increment offset by limit. When has_more is false, you've reached the end.
Errors
Errors follow a consistent format. The type field is machine-readable and stable; message is human-readable and may change. The optional param field identifies which parameter caused the error.
{
"error": {
"type": "invalid_request",
"message": "Invalid resource_type. Must be: customer, order, product",
"param": "resource_type"
}
}
| Status | Type | Description |
|---|---|---|
| 400 | invalid_request |
The request was malformed or a parameter is invalid |
| 401 | authentication_error |
Missing, invalid, or revoked API key |
| 403 | forbidden |
API access is not enabled for this shop |
| 404 | not_found |
The requested endpoint or resource does not exist |
| 429 | rate_limit |
Too many requests. Check the Retry-After header |
| 500 | api_error |
Internal server error. Retry with exponential backoff |
Retrieve tag change events. Every time a tag is added to or removed from a customer, order, or product, Beemlo records it. Use filters to narrow results by resource type, resource ID, or time range.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
resource_type |
string | Optional | - | Filter by resource type: customer, order, or product |
resource_id |
string | Optional | - | Filter by Shopify resource ID. Requires resource_type |
since |
string | Optional | - | ISO 8601 timestamp. Only events created at or after this time |
until |
string | Optional | - | ISO 8601 timestamp. Only events created at or before this time |
limit |
integer | Optional | 50 |
Results per page (1-100) |
offset |
integer | Optional | 0 |
Number of results to skip |
Request
curl "https://api.beemlo.com/v1/events/tags?resource_type=customer&limit=10" \ -H "Authorization: Bearer bml_sk_your_api_key_here"
const response = await fetch("https://api.beemlo.com/v1/events/tags?resource_type=customer&limit=10", { headers: { "Authorization": "Bearer bml_sk_your_api_key_here" } }); const data = await response.json(); console.log(data.data); // Array of tag events
import requests response = requests.get( "https://api.beemlo.com/v1/events/tags", headers={"Authorization": "Bearer bml_sk_your_api_key_here"}, params={"resource_type": "customer", "limit": 10} ) data = response.json() print(data["data"]) # List of tag events
Response
{
"object": "list",
"data": [
{
"id": 4821,
"object": "tag_event",
"resource_type": "customer",
"resource_id": "7841203519",
"tag": "vip",
"action": "added",
"created_at": "2026-02-26T10:30:00Z"
},
{
"id": 4820,
"object": "tag_event",
"resource_type": "customer",
"resource_id": "7841203519",
"tag": "wholesale",
"action": "removed",
"created_at": "2026-02-26T10:28:15Z"
}
],
"total": 1542,
"has_more": true,
"limit": 10,
"offset": 0
}
Retrieve metafield change events. Beemlo records every metafield create, update, and delete across customers, orders, and products, including the previous and new values.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
resource_type |
string | Optional | - | Filter by resource type: customer, order, or product |
resource_id |
string | Optional | - | Filter by Shopify resource ID. Requires resource_type |
namespace |
string | Optional | - | Filter by metafield namespace (e.g. custom) |
key |
string | Optional | - | Filter by metafield key (e.g. loyalty_tier) |
since |
string | Optional | - | ISO 8601 timestamp. Only events at or after this time |
until |
string | Optional | - | ISO 8601 timestamp. Only events at or before this time |
limit |
integer | Optional | 50 |
Results per page (1-100) |
offset |
integer | Optional | 0 |
Number of results to skip |
Request
curl "https://api.beemlo.com/v1/events/metafields?resource_type=order&namespace=custom&limit=10" \ -H "Authorization: Bearer bml_sk_your_api_key_here"
const response = await fetch( "https://api.beemlo.com/v1/events/metafields?resource_type=order&namespace=custom&limit=10", { headers: { "Authorization": "Bearer bml_sk_your_api_key_here" } } ); const data = await response.json(); console.log(data.data); // Array of metafield events
import requests response = requests.get( "https://api.beemlo.com/v1/events/metafields", headers={"Authorization": "Bearer bml_sk_your_api_key_here"}, params={ "resource_type": "order", "namespace": "custom", "limit": 10 } ) data = response.json() print(data["data"]) # List of metafield events
Response
{
"object": "list",
"data": [
{
"id": 2917,
"object": "metafield_event",
"resource_type": "order",
"resource_id": "5849201736",
"namespace": "custom",
"key": "priority",
"old_value": "normal",
"new_value": "high",
"action": "updated",
"created_at": "2026-02-26T10:31:00Z"
},
{
"id": 2916,
"object": "metafield_event",
"resource_type": "product",
"resource_id": "9312847561",
"namespace": "custom",
"key": "warehouse_location",
"old_value": null,
"new_value": "US-EAST-1",
"action": "created",
"created_at": "2026-02-26T10:25:42Z"
}
],
"total": 830,
"has_more": true,
"limit": 10,
"offset": 0
}