Features Pricing Blog Contact API Docs

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.

Base URL https://api.beemlo.com

Quick Start

Get up and running in under a minute.

API access is available on upgraded plans. Contact support@beemlo.com to upgrade your account and get started.

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"
  }
}
API keys are scoped to your shop and should only be used in server-side code. Never expose them in client-side JavaScript.

Rate Limiting

The API allows 120 requests per key per minute using fixed 1-minute windows. Every response includes rate limit headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window (120)
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix 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"
  }
}
StatusTypeDescription
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
GET /v1/events/tags

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

ParameterTypeRequiredDefaultDescription
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
}
GET /v1/events/metafields

Retrieve metafield change events. Beemlo records every metafield create, update, and delete across customers, orders, and products, including the previous and new values.

Parameters

ParameterTypeRequiredDefaultDescription
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
}