L Loyalino Developers

API reference

The Loyalino REST API lets you read and write loyalty data from your own backend. It is organized around predictable resources, uses standard HTTP verbs, and returns JSON for every response.

Introduction

The base URL for all endpoints is:

text
https://app.loyalino.io/api/v1

Send and receive JSON. Every request must be made over HTTPS and authenticated with an API key. Resource ids, amounts, and timestamps are returned as stable, snake_case fields.

Authentication

Authenticate every request by passing your secret key as a bearer token in the Authorization header. Create and manage keys in your Loyalino admin under Settings, API keys. The secret is shown only once when you create it, so store it somewhere safe.

bash
curl https://app.loyalino.io/api/v1/program \
  -H "Authorization: Bearer lzk_live_your_secret_key"

Keys come in two scopes and always expire. Read only is the default and can call GET endpoints. Choose read and write only when an integration must mutate data; it is rejected with a 403 otherwise and is capped at 90 days. Never expose a secret key in client-side code or a public repository. Use one key per integration, rotate it before expiry, and revoke it immediately if it leaks.

Keep it secret. Treat your API key like a password. All API calls are server to server.
Paid plans. The REST API and webhooks are available on the Starter, Essential, Growth, and Enterprise plans. Free plans return 402 plan_upgrade_required for paid operations. Authenticated Wallet status, preference changes and deletion remain available so members can manage existing cards after a downgrade. Upgrade under Billing to enable paid API access.

Errors

Loyalino uses conventional HTTP status codes. Errors return a JSON body with a stable type, a machine readable code, and a human readable message.

json
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The API key is invalid or has been revoked."
  }
}
StatusMeaning
200OK. The request succeeded.
201Created. A new resource was created.
400Bad request, for example invalid JSON.
401Missing, invalid, revoked, or expired API key.
402Your plan does not include API access. Upgrade to a paid plan.
403The key does not have permission, for example a read only key on a write.
404The resource does not exist.
409An idempotency key was reused for a different request.
413The request body exceeds 1 MB.
422Validation failed, for example a missing required field.
429Too many requests. See rate limits.
500Something went wrong on our side.

Pagination

List endpoints return a list object and accept limit (default 20, maximum 100) and page (1 based) query parameters. The envelope includes the total count and whether more pages remain.

json
{
  "object": "list",
  "data": [ /* ... */ ],
  "page": 1,
  "limit": 20,
  "total_count": 134,
  "has_more": true
}

Rate limits

Each API key may make up to 120 requests per minute. If you exceed the limit you receive a 429 response with a retry_after value in seconds. Back off and retry after that interval.

Customers

A customer is a loyalty member of your shop, with a points balance, lifetime points, and an optional VIP tier.

GET/v1/customers

List your loyalty customers, most recent first. Filter with email for an exact match or search for a name or email substring.

FieldTypeDescription
limitintegerPage size, 1 to 100. Default 20.
pageintegerPage number, 1 based.
emailstringReturn the customer with this exact email.
searchstringMatch name or email substring.
bash
curl https://app.loyalino.io/api/v1/customers?limit=1 \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "list",
  "data": [
    {
      "id": "cl9x2a1b0000",
      "object": "customer",
      "email": "ada@example.com",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "points_balance": 320,
      "lifetime_points": 1200,
      "pending_points": 0,
      "vip_tier": "Gold",
      "total_spent": 540,
      "created_at": "2026-05-01T10:00:00.000Z"
    }
  ],
  "page": 1,
  "limit": 1,
  "total_count": 134,
  "has_more": true
}
GET/v1/customers/:id

Retrieve a single customer by Loyalino id, Shopify customer id, or email address (pass the email directly in the path).

bash
curl https://app.loyalino.io/api/v1/customers/ada@example.com \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "id": "cl9x2a1b0000",
  "object": "customer",
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "points_balance": 320,
  "lifetime_points": 1200,
  "vip_tier": "Gold",
  "total_spent": 540,
  "created_at": "2026-05-01T10:00:00.000Z"
}
POST/v1/customers

Create a customer, or update the existing one with the same email. Requires a read and write key.

FieldTypeDescription
emailstringRequired. The customer email.
first_namestringOptional first name.
last_namestringOptional last name.
birthdaystringOptional, format YYYY-MM-DD.
shopify_customer_idstringOptional Shopify customer id to link.
bash
curl https://app.loyalino.io/api/v1/customers \
  -H "Authorization: Bearer lzk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"grace@example.com","first_name":"Grace"}'
json
{
  "id": "cl9x9z0000",
  "object": "customer",
  "email": "grace@example.com",
  "first_name": "Grace",
  "points_balance": 0,
  "lifetime_points": 0,
  "vip_tier": null,
  "created_at": "2026-06-07T12:00:00.000Z"
}
PATCH/v1/customers/:id

Update a customer profile. Only the fields you send are changed. Requires a read and write key.

FieldTypeDescription
first_namestringNew first name.
last_namestringNew last name.
birthdaystringNew birthday, YYYY-MM-DD.
bash
curl -X PATCH https://app.loyalino.io/api/v1/customers/cl9x9z0000 \
  -H "Authorization: Bearer lzk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"last_name":"Hopper"}'
json
{
  "id": "cl9x9z0000",
  "object": "customer",
  "email": "grace@example.com",
  "first_name": "Grace",
  "last_name": "Hopper",
  "points_balance": 0
}

Members in your app

Updated 1 October 2026: each wallet item has origin: points_redemption for a reward paid for with points, reward_grant for a reward delivered without a points debit, scratch_card for a zero-point reward with an exact owned physical-card economic relation, tier_reward for a finite tier grant (including recurring grants), or tier_perk for a permanent tier benefit. Payment is verified against the member's immutable delivery or exact ledger record. It is null when the source is unknown; a catalogue's current points cost is not evidence of payment. tier_name is the granting tier's localized name when the original tier relation still exists. A deleted tier can leave that name null while origin stays tier_reward. Do not infer point redemption from redeemed_at or a missing tier name: tier grants have a grant date too.

Show a member everything they see on your storefront, in your own app or site, and let them earn from it. Both endpoints run the same code as the storefront, so the numbers always match and an action done in one place counts as done in the other.

GET/v1/customers/:id/member

Retrieve a member's balances, tier progress, wallet (redeemed codes, tier rewards and permanent tier perks), completed one-time actions, daily visit and birthday state, and the last 50 transactions. pending marks order points that are not spendable yet. earn_rule_state entries are null when that way to earn is turned off. A read only key is enough. As on the storefront, a read on the member's birthday grants the yearly birthday points if they are due.

FieldTypeDescription
localestringOptional, for example da. Returns tier names in that language when you translated them in Translate & Adapt.
countrystringOptional two-letter country code. Picks the market used to show money amounts in reward names.
bash
curl "https://app.loyalino.io/api/v1/customers/8123456789/member?locale=da&country=DK" \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "member",
  "points": 1240,
  "pending_points": 299,
  "lifetime_points": 2100,
  "qualifying_points": 2100,
  "current_tier": { "id": "vt_1", "name": "Silver", "image_url": "https://cdn.shopify.com/..." },
  "next_tier": { "id": "vt_2", "name": "Gold", "points_required": 4000, "remaining": 1900 },
  "points_expires_at": null,
  "referral_url": null,
  "wallet": [
    {
      "id": "LOYALTYAB12",
      "code": "LOYALTYAB12",
      "name": "Free shipping",
      "type": "free_shipping",
      "value": null,
      "expires_at": "2026-12-01T00:00:00.000Z",
      "used": false,
      "redeemed_at": "2026-09-10T12:00:00.000Z",
      "is_permanent": false,
      "is_automatic": false,
      "tier_name": null,
      "origin": "points_redemption"
    }
  ],
  "completed_action_types": ["newsletter", "subscribe"],
  "earn_rule_state": {
    "daily_visit": { "can_claim": true, "next_reward_in": null },
    "birthday": { "birthday_set": true, "birthday_claimed": false, "birthday_date": "1995-04-12" }
  },
  "transactions": [
    {
      "id": "tx_71a2",
      "points": 299,
      "type": "earned",
      "description": "Order #1234 - 299 DKK",
      "order_number": "1234",
      "created_at": "2026-09-20T10:00:00.000Z",
      "pending": true
    }
  ]
}
POST/v1/customers/:id/member_actions

Complete a way to earn for a member: newsletter (also subscribes their email in Shopify), daily_visit, birthday, visit_link, signup or a social follow such as social_instagram_follow. The rule must be turned on. Each one-time action pays once per member across your storefront and your app; already_completed tells you it was done before. birthday saves the date and pays automatically every year on the day, so it returns awarded: false. Order, review, referral and Flow events are awarded automatically and cannot be claimed here. A Shopify customer who is not a member yet is enrolled; an id that is not a customer of your store returns 404 customer_not_found. Requires a read and write key.

FieldTypeDescription
action_typestringRequired. The way to earn to complete.
birthdaystringRequired for birthday, format YYYY-MM-DD.
bash
curl https://app.loyalino.io/api/v1/customers/8123456789/member_actions \
  -H "Authorization: Bearer lzk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"action_type":"newsletter"}'
json
{
  "object": "member_action",
  "awarded": true,
  "points": 50,
  "already_completed": false
}

Shopify store credit

GET/v1/customers/:id/store_credit

Read the customer's current native Shopify store-credit balances. A read-only API key is enough. Each currency has its own decimal string amount; never add different currencies together or infer credit from loyalty points or past rewards. An empty balances array means Shopify verified that this customer has no credit accounts. The endpoint returns a complete fresh list or an error, never a partial balance or a guessed zero. It requires an active paid program and a currently installed, authorized app. Missing or deleted customers return 404, erased subjects return 410, and unavailable Shopify data returns 503 store_credit_unavailable. This is a read operation and grants or debits no credit.

bash
curl https://app.loyalino.io/api/v1/customers/8123456789/store_credit \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "balances": [
    { "amount": "125.50", "currencyCode": "DKK" },
    { "amount": "8.90", "currencyCode": "EUR" }
  ]
}

Credit belongs to the Shopify customer account. To spend it at checkout the customer must authenticate through Shopify new customer accounts. An app's own email-code login does not establish that checkout authentication. Keep the balance endpoint and API key on your backend.

Physical QR scratch cards

Updated 4 October 2026: create up to 5,000 cards under Scratch cards, with one guaranteed frozen prize per card. The Lucky Days mixed pool fixes three 500-unit Golden Tickets and a total of 5,000; other quantities, currency and sunglasses products are configured before issuance. Download at most 500 original card numbers per print file and keep QR codes covered and private. Reprinting copies the same cards and their original winning symbols; each card can pay only once. Financial prizes cost zero points and are restricted to the claiming member. Free-item prizes cover exactly one eligible unit, exclude gift cards and subscriptions, and require the installed quantity-one Shopify Function.

MethodPathBehavior
POST/v1/customers/:id/scratch_cards/previewBody {code}. Read-only key permitted. Returns {status,pending,campaign,prize,claimedAt}; preview never awards value.
GET/v1/customers/:id/scratch_cards?cursor=<opaque>Read-only key permitted. Returns up to 30 owned {id,serial,campaignName,claimedAt,prize,status,expiresAt} receipts plus nullable nextCursor. Status: pending, ready, redeemed, expired, manual_review or revoked. The bounded signed cursor belongs to this shop and member; mismatched, malformed or deleted anchors return 422 invalid_cursor. Serial numbers identify printed cards and never authorize claims. No bearer, discount code or provider identity appears in a receipt.
POST/v1/customers/:id/scratch_cards/claimSame body, read/write key and UUIDv4 Idempotency-Key. 202 {pending:true} is unresolved; only 200 {claimed:true,idempotentReplay,claimedAt,campaignName,prize,remainingPoints} confirms completion.

Accept only canonical LSC1: plus unpadded Base64URL for 32 bytes. Never place the code in URLs, logs, analytics or persistent mobile storage. Preserve the transport key on pending/ambiguous retries. After a lost session, rescanning the same owned card can recover its original economic receipt. A request key cannot claim two different cards. Unknown, another tenant or another owner receive the same 404 invalid_scratch_card.

409 manual_review means an existing prize needs store confirmation; never retry it as a new grant. Pausing, schedules and permanent revocation block new claims, while original confirmed claims replay safely. Erasure removes claimant identity but keeps an anonymous spent marker. Verified Shopify merges move the receipt to the surviving account; a quantity-one coupon stays hidden until its original provider entitlement has been rebound and checked. Receipt expiry comes from the accepted reward, not its campaign. Points and credit are shown as awarded, and only exact owned voucher usage is shown as redeemed. The Node SDK provides previewScratchCard(id,code), claimScratchCard(id,code,idempotencyKey) and listScratchCardClaims(id,{cursor}). Responses never expose discount codes, print seeds or another member's identity.

Apple Wallet and Google Wallet

Configure Settings, Wallet Pass and complete the issuer setup before offering saves. Keep the API key in your backend, authenticate the member there, and use their existing Shopify customer id. A card carries current spendable points, resolved tier and a POS membership barcode.

The current rank appears on the card face: Apple's membership-tier field and Google's object-specific tier beside points. A shared Google class reads each member's own tier, so one member's rank cannot become the whole program's rank. Committed tier and point changes queue refreshes, and periodic reconciliation repairs missed events. Actual updates still depend on the wallet provider and the member's device.

MethodPathBehavior
GET/v1/customers/:id/wallet_passRead merchant enablement, Apple/Google availability and existing pass consent, including after a billing downgrade. This does not enable issuance.
POSTSame pathCreate a ten-minute save handoff. Requires a paid active program and read/write key.
PATCHSame pathReplace the complete consent object. Read/write authentication still applies during provider outages or a billing downgrade.
DELETESame pathIdempotently clear local card identifiers and durably queue revocation. A billing downgrade does not prevent deletion.
json
{
  "platform": "apple",
  "locale": "da",
  "consent": { "updates": false, "marketing": false, "location": false }
}

POST accepts platform apple or google, optional locale, and three explicit boolean preferences in consent. A trusted backend can supply its existing barcode and member_number; a conflicting identity is refused. PATCH sends only consent. Request bodies are limited to 4 KB.

POST returns {url, expiresAt, platform}. Open the HTTPS handoff in the system browser: Apple downloads a signed pass and Google redirects to its save flow. Treat this URL as a short-lived credential and never log or expose it in analytics. Wallet/device permissions control notifications and nearby relevance. Location consent sends store coordinates; Loyalino does not receive member location or track visits. Deleting a card cannot force removal of an offline phone's saved copy.

Points transactions

A points transaction changes a customer balance. Award points with a positive value and deduct with a negative value. This is the primary way to manage balances over the API. Every write requires a stable idempotency_key (or Idempotency-Key header); reuse it only when retrying the same logical request.

POST/v1/customers/:id/points_transactions

Create a points transaction for a customer. points must be a non-zero integer, and a deduction cannot drop the balance below zero. Requires a read and write key.

FieldTypeDescription
pointsintegerRequired. Positive to award, negative to deduct.
typestringOptional label, for example earned or adjusted.
descriptionstringOptional note shown in history.
idempotency_keystringRequired. Stable 8-128 character retry key.
bash
curl https://app.loyalino.io/api/v1/customers/cl9x2a1b0000/points_transactions \
  -H "Authorization: Bearer lzk_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: birthday-ada-2026" \
  -d '{"points":100,"type":"earned","description":"Birthday bonus"}'
json
{
  "id": "tx_71a2",
  "object": "points_transaction",
  "customer_id": "cl9x2a1b0000",
  "points": 100,
  "type": "earned",
  "description": "Birthday bonus",
  "created_at": "2026-06-07T12:05:00.000Z"
}
GET/v1/customers/:id/points_transactions

List a single customer transactions, most recent first.

bash
curl https://app.loyalino.io/api/v1/customers/cl9x2a1b0000/points_transactions \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "list",
  "data": [
    {
      "id": "tx_71a2",
      "object": "points_transaction",
      "customer_id": "cl9x2a1b0000",
      "points": 100,
      "type": "earned",
      "created_at": "2026-06-07T12:05:00.000Z"
    }
  ],
  "page": 1,
  "limit": 20,
  "total_count": 1,
  "has_more": false
}
GET/v1/points_transactions

List transactions across all customers. Filter with customer_id or type.

FieldTypeDescription
customer_idstringLimit to one customer (id or email).
typestringLimit to a transaction type.
limitintegerPage size, 1 to 100.
pageintegerPage number.
bash
curl "https://app.loyalino.io/api/v1/points_transactions?type=earned" \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "list",
  "data": [ /* points_transaction objects */ ],
  "page": 1,
  "limit": 20,
  "total_count": 58,
  "has_more": true
}
GET/v1/points_transactions/:id

Retrieve a single points transaction by id.

bash
curl https://app.loyalino.io/api/v1/points_transactions/tx_71a2 \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "id": "tx_71a2",
  "object": "points_transaction",
  "customer_id": "cl9x2a1b0000",
  "points": 100,
  "type": "earned",
  "created_at": "2026-06-07T12:05:00.000Z"
}

Program

Read-only endpoints that describe how your program is configured: the rewards customers can redeem, the ways they earn, your VIP tiers, and your points settings.

GET/v1/rewards

List redemption rewards. Add ?enabled=true to return only active rewards.

bash
curl https://app.loyalino.io/api/v1/rewards?enabled=true \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "list",
  "data": [
    {
      "id": "rw_5",
      "object": "reward",
      "name": "5 off",
      "type": "amount_discount",
      "points_cost": 100,
      "discount_value": 5,
      "enabled": true,
      "variable": null,
      "points_step": 100,
      "expiration_days": 30,
      "minimum_purchase": null,
      "custom_instructions": null,
      "icon_url": null
    }
  ],
  "page": 1,
  "limit": 20,
  "total_count": 6,
  "has_more": false
}
GET/v1/earn_rules

List the ways customers earn points. Add ?enabled=true for active rules only.

bash
curl https://app.loyalino.io/api/v1/earn_rules \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "list",
  "data": [
    {
      "id": "er_1",
      "object": "earn_rule",
      "name": "Place an order",
      "type": "place_order",
      "points": 1,
      "enabled": true
    }
  ],
  "page": 1,
  "limit": 20,
  "total_count": 5,
  "has_more": false
}
GET/v1/vip_tiers

List your VIP tiers, lowest threshold first.

bash
curl https://app.loyalino.io/api/v1/vip_tiers \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "list",
  "data": [
    {
      "id": "vt_2",
      "object": "vip_tier",
      "name": "Gold",
      "points_required": 1000,
      "multiplier": 1.5,
      "discount_type": "percentage",
      "discount_value": 10,
      "free_shipping": true
    }
  ],
  "page": 1,
  "limit": 20,
  "total_count": 3,
  "has_more": false
}
GET/v1/program

Retrieve your program settings and status: whether it is live, your plan, the earn rate, and the currency.

bash
curl https://app.loyalino.io/api/v1/program \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "program",
  "shop_domain": "your-store.myshopify.com",
  "live": true,
  "plan": "growth",
  "points_per_unit": 1,
  "currency": "USD",
  "points_delay_days": 0,
  "points_expiry_days": 365
}

Activities and redemptions

Award points for any custom action, or redeem a reward end to end.

POST/v1/activities

Record a customer activity and award points. Provide explicit points, or omit them to use the matching enabled earn rule for type. Requires a read and write key.

FieldTypeDescription
customer_idstringRequired. Internal id, Shopify id, or email.
typestringRequired. The activity name (also matched to an earn rule).
pointsintegerOptional. Overrides the matching rule's points.
idempotency_keystringRequired. Stable 8-128 character retry key.
bash
curl https://app.loyalino.io/api/v1/activities \
  -H "Authorization: Bearer lzk_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: newsletter-ada-2026" \
  -d '{"customer_id":"ada@example.com","type":"newsletter_signup","points":50}'
json
{
  "object": "activity",
  "type": "newsletter_signup",
  "customer_id": "cl9x2a1b0000",
  "points_awarded": 50,
  "transaction": {
    "id": "tx_a1",
    "object": "points_transaction",
    "points": 50,
    "type": "earned"
  }
}
POST/v1/customers/:id/redemptions

Redeem a reward for a customer. Uses the same pipeline as storefront, checkout and POS: the debit is claimed before Shopify delivery, lost discount responses are recovered with a deterministic code, and ambiguous native store-credit outcomes remain pending for reconciliation. Every request requires a stable Idempotency-Key; reuse it for the identical retry and use a new key only for a new redemption. A response with pending: true must be retried with the same key. Pass points_to_redeem only for variable rewards. Requires a read and write key.

FieldTypeDescription
reward_idstringRequired. The reward to redeem.
points_to_redeemintegerRequired only for variable-redemption rewards.
Idempotency-KeyheaderRequired. Stable 16-128 character key; persist before sending and reuse for the same retry.
bash
curl https://app.loyalino.io/api/v1/customers/cl9x2a1b0000/redemptions \
  -H "Authorization: Bearer lzk_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 123e4567-e89b-42d3-a456-426614174000" \
  -d '{"reward_id":"rw_5"}'
json
{
  "id": "LOYALTY7F3A2B",
  "object": "redemption",
  "customer_id": "cl9x2a1b0000",
  "reward_id": "rw_5",
  "points_spent": 100,
  "remaining_balance": 220,
  "discount_code": "LOYALTY7F3A2B",
  "apply_mode": "code",
  "expires_at": "2026-10-22T12:00:00.000Z"
}

Webhooks

Register HTTPS endpoints to receive signed loyalty events as they happen. Manage them here or in your admin under Settings, Webhooks.

EventWhen it fires
points.createdPoints are awarded (order, API, or activity).
customer.createdA new loyalty customer is created.
customer.updatedA customer profile changes.
redemption.createdA reward is redeemed anywhere: storefront, checkout, POS or the API. source says where. A store-credit redemption that is still pending confirmation sends it once the credit is confirmed.
tier.changedA customer moves VIP tier, up or down, including manual and Shopify Flow assignments and revocations. Includes previous_tier, new_tier and direction.

Each delivery is a signed POST with this JSON body:

json
{
  "id": "evt_3a9f1c",
  "object": "event",
  "type": "points.created",
  "created_at": "2026-06-07T12:00:00.000Z",
  "data": { "customer_id": "cl9x2a1b0000", "points": 100 }
}

Every event carries customer_id (the Loyalino id) and, for order points, redemptions and tier changes, shopify_customer_id. A tier change looks like this:

json
{
  "customer_id": "cl9x2a1b0000",
  "shopify_customer_id": "8123456789",
  "email": "ada@example.com",
  "previous_tier": { "id": "vt_1", "name": "Silver" },
  "new_tier": { "id": "vt_2", "name": "Gold" },
  "direction": "up"
}

Verify signatures

Every request carries a Loyalino-Signature: t=<unix>,v1=<hmac> header. Recompute the HMAC-SHA256 of the timestamp, a dot, and the raw request body using your endpoint secret, then compare in constant time. The Node SDK exports verifyWebhook for this.

javascript
import crypto from "node:crypto";

function verify(secret, header, rawBody) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto
    .createHmac("sha256", secret)
    .update(parts.t + "." + rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(parts.v1, "hex"),
    Buffer.from(expected, "hex"),
  );
}
GET/v1/webhook_endpoints

List your webhook endpoints. The signing secret is only ever returned once, at creation.

bash
curl https://app.loyalino.io/api/v1/webhook_endpoints \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "object": "list",
  "data": [
    {
      "id": "we_1",
      "object": "webhook_endpoint",
      "url": "https://you.example.com/hook",
      "events": ["*"],
      "enabled": true,
      "last_status": 200
    }
  ],
  "page": 1,
  "limit": 20,
  "total_count": 1,
  "has_more": false
}
POST/v1/webhook_endpoints

Register an endpoint. The response includes the signing secret once. Subscribe to specific events, or omit events for all. Requires a read and write key.

FieldTypeDescription
urlstringRequired. A public https URL.
eventsarrayOptional. Event names to subscribe to, or omit for all.
descriptionstringOptional label.
bash
curl https://app.loyalino.io/api/v1/webhook_endpoints \
  -H "Authorization: Bearer lzk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://you.example.com/hook","events":["points.created","redemption.created"]}'
json
{
  "id": "we_1",
  "object": "webhook_endpoint",
  "url": "https://you.example.com/hook",
  "events": ["points.created", "redemption.created"],
  "enabled": true,
  "secret": "whsec_9f2a7c..."
}
DELETE/v1/webhook_endpoints/:id

Delete a webhook endpoint. You can also PATCH it to change the url, events, or enabled state.

bash
curl -X DELETE https://app.loyalino.io/api/v1/webhook_endpoints/we_1 \
  -H "Authorization: Bearer lzk_live_xxx"
json
{
  "id": "we_1",
  "object": "webhook_endpoint",
  "deleted": true
}