Merly Merchant Public API
Last updated: 2026-06-16
Getting started
The Merchant Public API lets you build headless storefronts, ERP integrations, and custom loyalty experiences on top of Merly.
Create API keys from your Integrations screen. Each key is scoped to your store and can be revoked at any time.
Authentication
Send your API key on every request using either an Authorization Bearer header or x-merchant-api-key.
Do not publish or embed API keys in client-side JavaScript. Keys grant access to customer wallet data for your store.
curl -X GET "https://{your-gateway}/api/v1/merchant/customers/{customer_user_id}/balance" \
-H "Authorization: Bearer pk_live_…" \
-H "x-correlation-id: $(uuidgen)"Security: Keep API keys on your server only. Never expose them in client-side JavaScript, mobile apps, or public repositories.
Base URL & versioning
All merchant public routes are exposed through your Merly API gateway under /api/v1/merchant.
Use your production gateway hostname in all environments except local sandboxes provided by your Merly contact.
https://{your-gateway}/api/v1/merchantRate limits
Each API key has a per-minute rate limit (default 120 requests/minute, configurable at key creation between 10 and 600).
When exceeded, the gateway returns HTTP 429 with error rate_limit_exceeded and a correlation_id for support.
Default: 120 req/min · Configurable 10–600 at key creation.
Scopes
| Scope | Label | Description |
|---|---|---|
read:balance | Read balance | Wallet balance and plan tier |
read:tier | Read tier | Subscription tier and status |
read:activity | Read activity | Paginated wallet transaction history |
read:coupons | Validate coupons | Checkout validation for Merly credit coupon codes (headless) |
write:webhooks | Test webhooks | Send signed test lifecycle events to your configured outbound webhook URL |
write:catalog | Publish catalog | Publish store policy and product directory (headless merchants) |
write:customers | Link customers | Link external customer IDs to Merly wallets (headless merchants) |
write:orders | Ingest orders | Report paid orders for purchase earn (headless merchants) |
Endpoints
GETCustomer wallet balance
/api/v1/merchant/customers/{customer_id}/balance
Scope: read:balance
Returns the Merly wallet balance and plan tier for a customer. customer_id is the Merly Identity user_id (UUID).
Example response
{
"customer_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"platform": "shopify",
"store_key": "your-store.myshopify.com",
"balance": "1500.0000",
"plan_tier": "SILVER",
"correlation_id": "…"
}GETSubscription tier
/api/v1/merchant/customers/{customer_id}/tier
Scope: read:tier
Returns the customer's Merly subscription tier and status.
Example response
{
"customer_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"platform": "shopify",
"store_key": "your-store.myshopify.com",
"plan_tier": "SILVER",
"subscription_status": "active",
"correlation_id": "…"
}GETWallet activity
/api/v1/merchant/customers/{customer_id}/activity
Scope: read:activity
Paginated wallet transaction history for the customer.
Query parameters
{
"page": "Page number (default 1)",
"page_size": "Items per page (default 20, max 100)",
"type": "Optional transaction type filter"
}Example response
{
"customer_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"current_balance": "1500.0000",
"total_count": 42,
"page": 1,
"page_size": 20,
"transactions": []
}POSTTest outbound webhook
/api/v1/merchant/webhooks/test
Scope: write:webhooks
Sends a signed test lifecycle event to the outbound webhook URL configured in Integrations.
Request body
{
"event_type": "merly.points.earned"
}Example response
{
"ok": true,
"event_type": "merly.points.earned",
"correlation_id": "…"
}POSTPublish catalog policy and products
/api/v1/merchant/catalog/publish
Scope: write:catalog
Headless merchants only. Requires x-idempotency-key.
Request body
{
"policy_store_only": true,
"cap": {
"max_coupon_value_usd": 50
}
}Example response
{
"ok": true,
"product_count": 0,
"catalog_store_id": "hl_boutique-example-com",
"correlation_id": "…"
}POSTLink external customer to Merly wallet
/api/v1/merchant/customers/link
Scope: write:customers
Request body
{
"external_customer_id": "cust_1",
"email": "buyer@example.com"
}Example response
{
"customer_user_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"created": true,
"linked": true,
"correlation_id": "…"
}POSTIngest paid order
/api/v1/merchant/orders
Scope: write:orders
Request body
{
"order_id": "ord_1",
"external_customer_id": "cust_1",
"customer_email": "buyer@example.com",
"currency": "USD",
"total": "120.00",
"subtotal": "110.00"
}Example response
{
"order_id": "ord_1",
"earn_granted": 110,
"correlation_id": "…"
}POSTValidate Merly credit coupon at merchant checkout
/api/v1/merchant/coupons/validate
Scope: read:coupons
Request body
{
"coupon_code": "MERLY-ABC123"
}Example response
{
"valid": true,
"coupon_code": "MERLY-ABC123",
"credits_amount": "300.0000",
"expires_at": null,
"correlation_id": "…"
}Outbound webhooks
Configure your outbound webhook URL under Integrations. Merly signs payloads with X-Merly-Signature: sha256={hex} when a signing secret is set.
Use POST /api/v1/merchant/webhooks/test (scope write:webhooks) to verify delivery.
| Canonical | Public alias |
|---|---|
merly.points.earned | points.earned |
merly.points.redeemed | points.redeemed |
merly.tier.changed | tier.changed |
merly.order.ingested | order.ingested |
Key management
Create and revoke API keys from the Integrations section of your merchant admin: Shopify app, WooCommerce plugin, or the Merly Merchant Portal for headless stores. Each key is shown in full only once at creation — store it securely.
Errors
| HTTP | error | Description |
|---|---|---|
| 401 | missing_api_key | No Bearer or x-merchant-api-key header |
| 401 | invalid_api_key | Key revoked, wrong hash, or unknown prefix |
| 403 | insufficient_scope | Key lacks required scope for route |
| 429 | rate_limit_exceeded | Per-key RPM exceeded |
| 404 | customer_wallet_not_found | No wallet for customer_id |