Skip to content

How to make your first API call

This guide takes you from no key to a working lookup in a few minutes. You need a store on the Premium plan (Scale on older plans), and a server or a terminal where the key stays private.

  1. In Bloop, open Settings, select the Integration tab, then select Manage on the API & Webhooks card.
  2. Under API keys, select Create API key. In Key name, type a name that tells you where the key is used, for example LINE bot, then select Create API key.
  3. Copy the key from the Secret key field. It starts with bloop_sk_ and is shown only once: Bloop keeps a fingerprint of the key, not the key itself, so nobody can show it to you again.
  4. Select I’ve saved the key to close the window. Until you do, the window cannot be closed.

The list of keys shows each key’s Name, its first characters (Key), its Permissions, when it was Last used and who created it. A store can have up to 5 active keys. In version 1 every key has the referrers:read scope, shown under Permissions.

  • Call the API from your server only. The API sends no CORS headers, so a browser blocks calls from a theme, a storefront script or any web page.
  • Never put the key in theme code, a mobile app or a code repository.
  • Lost a key? Create a new one, switch your integration to it, then revoke the old one. A revoked key stops working within 60 seconds.
  • Keys do not expire. Revoke the keys you no longer use.

GET /v1/me works with any key and returns your store, plan, scopes and limits. Use it to confirm that the key works.

Terminal window
curl https://api.bloop.plus/v1/me \
-H "Authorization: Bearer bloop_sk_YOUR_KEY"
{
"data": {
"shop": "your-store.myshopify.com",
"plan": "Premium",
"scopes": ["referrers:read"],
"limits": {
"requests_per_minute": 100,
"api_keys": 5,
"webhook_endpoints": 5
},
"key": {
"name": "LINE bot",
"prefix": "bloop_sk_uZT"
}
}
}

401 invalid_api_key means the key is missing, mistyped or revoked. A 403 means the store cannot use the API right now. Every code is explained in Understanding errors and rate limits. plan is a display name, so don’t branch on it.

Look up by Shopify customer id when you have it. The id never changes, while a customer can change their email.

Terminal window
curl "https://api.bloop.plus/v1/referrers?shopify_customer_id=7012345678901" \
-H "Authorization: Bearer bloop_sk_YOUR_KEY"

Both 7012345678901 and gid://shopify/Customer/7012345678901 work. The response always gives the numeric form.

To look up by email, let curl encode the value:

Terminal window
curl -G https://api.bloop.plus/v1/referrers \
--data-urlencode "[email protected]" \
-H "Authorization: Bearer bloop_sk_YOUR_KEY"

Email matching ignores case and spaces around the value. It also finds a referrer through the customer’s current Shopify email when that differs from the email Bloop stored. A lookup returns one referrer:

{
"data": {
"id": "12345",
"email": "[email protected]",
"shopify_customer_id": "7012345678901",
"first_name": "Somchai",
"last_name": null,
"source": "auto_enrolled",
"created_at": "2026-10-01T03:12:00Z",
"updated_at": "2026-10-01T03:12:00Z",
"campaigns": [
{
"campaign_id": "88",
"campaign_name": "VIP referral",
"status": "active",
"joined_at": "2026-10-01T03:12:00Z",
"share_code": "AB12CD34",
"share_link": "https://refer.example.com/AB12CD34",
"discount_code": "REF_AB12CD34",
"successful_referrals": 3,
"referral_revenue": {
"amount": "120.00",
"currency": "THB"
}
}
]
}
}

No match returns 404 referrer_not_found, and so does a referrer of another store or an id that is not a valid referrer id. To read a referrer by the Bloop id you received in a webhook:

Terminal window
curl https://api.bloop.plus/v1/referrers/12345 \
-H "Authorization: Bearer bloop_sk_YOUR_KEY"

Each entry in campaigns is one campaign the referrer belongs to:

Field What it holds
share_link The referrer’s personal referral link for this campaign
share_code The code at the end of the link
discount_code The referrer’s personal discount code. null when the campaign does not use share codes, or while the code is not created yet
status active or inactive (the referrer left the campaign)
joined_at When the referrer most recently joined the campaign. Joining again after leaving sets a new time
successful_referrals Referrals counted for the referrer in this campaign
referral_revenue Revenue from the referrer’s approved referrals

Every id is an opaque string: store it as text, never parse it or compare ids by size. All fields are described in Understanding the API endpoints.

To build or refresh your own copy of your referrers, list the ones that changed since a point in time and follow the cursor.

  1. Call GET /v1/referrers?updated_since=2026-10-01T00:00:00Z&limit=100.
  2. Save each referrer by id.
  3. While next_cursor is not null, call again with the same filters plus cursor=<next_cursor>. The cursor only marks a position: it does not remember your filters.
  4. When next_cursor is null, keep the largest updated_at you saw. Start the next sync from it.
const BASE = 'https://api.bloop.plus/v1/referrers';
async function syncReferrers(key, since, save) {
let cursor = null;
let newest = since;
for (;;) {
const params = new URLSearchParams({ updated_since: since, limit: '100' });
if (cursor) params.set('cursor', cursor);
const res = await fetch(`${BASE}?${params}`, { headers: { Authorization: `Bearer ${key}` } });
if (res.status === 429 || res.status === 503) {
const wait = Number(res.headers.get('Retry-After') || 5);
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
continue;
}
if (!res.ok) throw new Error(`Bloop API ${res.status}: ${await res.text()}`);
const page = await res.json();
for (const referrer of page.data) {
await save(referrer);
if (Date.parse(referrer.updated_at) > Date.parse(newest)) newest = referrer.updated_at;
}
if (!page.next_cursor) return newest;
cursor = page.next_cursor;
}
}
  • updated_since needs a time zone, Z or an offset like +07:00. Without one you get 400 invalid_request.
  • limit goes from 1 to 100 and defaults to 50. A value outside that range returns 400, it is not adjusted for you.
  • Add campaign_id to list only the members of one campaign. A campaign_id that does not exist in your store returns 404 not_found.
  • A referrer that changes while you page moves to the end of the list and can appear twice. It is never skipped. Keep the copy with the newer updated_at.
  • Lookup parameters (email, shopify_customer_id) cannot be mixed with list parameters, and email cannot be combined with shopify_customer_id. An unknown or repeated parameter returns 400, so a typo fails loudly instead of returning a list.
  • Building the URL by hand with a raw email. A + turns into a space and the lookup misses.
  • Looking up by email when you have the customer id. Customers change emails; ids stay.
  • Restarting a sync from the beginning every time. Save the largest updated_at and continue from it.
  • Reusing a cursor with different filters. Send the same filters with every page.
  • Calling the API from a browser. It fails, and it would expose your key.