Understanding the API endpoints
This page lists every endpoint of version 1 of the Bloop API, with its parameters, response fields and errors. It is generated from the same contract Bloop tests the API against, so it matches what the API returns.
- Base URL:
https://api.bloop.plus - Authentication:
Authorization: Bearer <key>. Key format:bloop_sk_followed by 32 base62 characters. - Format: JSON with snake_case fields. Every id and cursor is an opaque string. Times are UTC in ISO 8601.
GET /v1/me
Section titled “GET /v1/me”Check the key and read the shop, plan, scopes and limits.
Works with any scope. plan is a display name for reference only, do not branch on it. Any query parameter returns 400 invalid_request.
Scope: Any scope
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Request-Id |
header | string | No | Optional request id echoed back in X-Request-Id. Used only when it matches ^[A-Za-z0-9_-]{8,64}$, otherwise Bloop generates one. |
Response 200
Section titled “Response 200”The key is valid. Body: MeResponse.
Example me:
{ "data": { "shop": "test-store.myshopify.com", "plan": "Premium", "scopes": [ "referrers:read" ], "limits": { "requests_per_minute": 100, "api_keys": 5, "webhook_endpoints": 5 }, "key": { "name": "LINE integration", "prefix": "bloop_sk_uZT" } }}Errors
Section titled “Errors”| HTTP status | Code | When |
|---|---|---|
| 400 | invalid_request, invalid_cursor |
Invalid or conflicting parameters, or an undecodable cursor. |
| 401 | invalid_api_key |
Missing, malformed, unknown or revoked key. |
| 403 | plan_not_eligible, shop_inactive, insufficient_scope |
The shop cannot use the API, or the key lacks the scope. |
| 429 | rate_limited |
Too many requests for the shop, or too many invalid keys from this IP. |
| 500 | internal_error |
Unexpected error. No internal detail is exposed. |
| 503 | service_unavailable |
The key could not be checked right now. |
GET /v1/referrers
Section titled “GET /v1/referrers”Look up one referrer by email or Shopify customer id, or list referrers.
With email or shopify_customer_id the response is one referrer ({data: Referrer}) or 404 referrer_not_found.
Without them the response is a page ({data: Referrer[], next_cursor}) sorted by updated_at then id, ascending.
A referrer that changes while you page moves to the end and can appear twice; merge by id and keep the newer updated_at.
Unknown, repeated or array query parameters return 400 invalid_request. Lookup and list parameters cannot be mixed, and email cannot be combined with shopify_customer_id.
Scope: referrers:read
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
email |
query | string | No | Look up by email, 1 to 320 characters. Trimmed and compared case-insensitively; also matches the current Shopify email of the customer. |
shopify_customer_id |
query | string | No | Look up by Shopify customer id, numeric or gid://shopify/Customer/<id>. |
campaign_id |
query | string | No | List only memberships of this campaign. A campaign of another shop returns 404 not_found. |
updated_since |
query | string | No | List referrers with updated_at at or after this RFC 3339 time. The offset is required. |
limit |
query | integer | No | Page size from 1 to 100. Values outside the range return 400. From 1 to 100. Default 50. |
cursor |
query | string | No | Opaque next_cursor of the previous page. Send the same filters again with it. |
X-Request-Id |
header | string | No | Optional request id echoed back in X-Request-Id. Used only when it matches ^[A-Za-z0-9_-]{8,64}$, otherwise Bloop generates one. |
Response 200
Section titled “Response 200”One referrer for a lookup, a page of referrers for a list. Body: one of ReferrerResponse or ReferrerListResponse.
Example lookup:
{ "data": { "id": "12345", "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" } } ] }}Example list:
{ "data": [ { "id": "12345", "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" } } ] } ], "next_cursor": "eyJ1IjoiMjAyNi0xMC0wMVQwMzoxMjowMFoiLCJpZCI6IjEyMzQ1In0"}Example last_page:
{ "data": [], "next_cursor": null}Errors
Section titled “Errors”| HTTP status | Code | When |
|---|---|---|
| 400 | invalid_request, invalid_cursor |
Invalid or conflicting parameters, or an undecodable cursor. |
| 401 | invalid_api_key |
Missing, malformed, unknown or revoked key. |
| 403 | plan_not_eligible, shop_inactive, insufficient_scope |
The shop cannot use the API, or the key lacks the scope. |
| 404 | referrer_not_found, not_found |
Not found, or it belongs to another shop. |
| 429 | rate_limited |
Too many requests for the shop, or too many invalid keys from this IP. |
| 500 | internal_error |
Unexpected error. No internal detail is exposed. |
| 503 | service_unavailable |
The key could not be checked right now. |
GET /v1/referrers/{id}
Section titled “GET /v1/referrers/{id}”Read one referrer by Bloop id.
id is the opaque id from a referrer object or a webhook. An id that does not exist or belongs to another shop returns 404 referrer_not_found. Any query parameter returns 400 invalid_request.
Scope: referrers:read
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | Yes | Opaque Bloop referrer id. |
X-Request-Id |
header | string | No | Optional request id echoed back in X-Request-Id. Used only when it matches ^[A-Za-z0-9_-]{8,64}$, otherwise Bloop generates one. |
Response 200
Section titled “Response 200”The referrer. Body: ReferrerResponse.
Example referrer:
{ "data": { "id": "12345", "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" } } ] }}Errors
Section titled “Errors”| HTTP status | Code | When |
|---|---|---|
| 400 | invalid_request, invalid_cursor |
Invalid or conflicting parameters, or an undecodable cursor. |
| 401 | invalid_api_key |
Missing, malformed, unknown or revoked key. |
| 403 | plan_not_eligible, shop_inactive, insufficient_scope |
The shop cannot use the API, or the key lacks the scope. |
| 404 | referrer_not_found, not_found |
Not found, or it belongs to another shop. |
| 429 | rate_limited |
Too many requests for the shop, or too many invalid keys from this IP. |
| 500 | internal_error |
Unexpected error. No internal detail is exposed. |
| 503 | service_unavailable |
The key could not be checked right now. |
Objects
Section titled “Objects”A money amount. amount is a decimal string, currency is an ISO 4217 code.
| Field | Type | Description |
|---|---|---|
amount |
string | Decimal string, for example “120.00”. |
currency |
string | ISO 4217 currency code of the shop. |
Membership
Section titled “Membership”One referrer in one campaign. Same shape in GET /v1/referrers (campaigns[]) and in webhook data.campaign.
| Field | Type | Description |
|---|---|---|
campaign_id |
string | Opaque campaign id. |
campaign_name |
string | Campaign name at read time. |
status |
string | Membership status. New values may be added. Values: active, inactive. |
joined_at |
string | When the referrer last joined this campaign (UTC). A re-join after leaving moves it forward. |
share_code |
string | Referral share code of this membership. |
share_link |
string | Personal referral link: share URL of the shop followed by “/” and share_code. |
discount_code |
string or null | Personal discount code. null when the campaign does not use share codes or the code could not be created yet. |
successful_referrals |
integer | Number of successful referrals in this campaign. |
referral_revenue |
Money |
Referrer
Section titled “Referrer”A referrer of the shop with every campaign membership.
| Field | Type | Description |
|---|---|---|
id |
string | Opaque Bloop referrer id. Do not parse or compare order. |
email |
string | Email of the referrer as stored by Bloop. |
shopify_customer_id |
string or null | Numeric Shopify customer id, null when unknown. |
first_name |
string or null | First name from the Shopify customer, null when unknown. |
last_name |
string or null | Last name from the Shopify customer, null when unknown. |
source |
string | How the referrer was created. New values may be added. Values: self_registered, converted_customer, admin_invited, auto_enrolled, imported, unknown. |
created_at |
string | When the referrer was created (UTC). |
updated_at |
string | Latest change of the referrer or of any of its memberships (UTC). Use it to keep the newest copy. |
campaigns |
array of Membership | Every membership of the referrer in campaigns of this shop. |
ReferrerResponse
Section titled “ReferrerResponse”| Field | Type | Description |
|---|---|---|
data |
Referrer |
ReferrerListResponse
Section titled “ReferrerListResponse”| Field | Type | Description |
|---|---|---|
data |
array of Referrer | |
next_cursor |
string or null | Opaque cursor of the next page, null on the last page. |
| Field | Type | Description |
|---|---|---|
shop |
string | myshopify domain of the shop. |
plan |
string | Display name of the plan, for reference only. |
scopes |
array of string | Scopes of this key. |
limits |
object | |
limits.requests_per_minute |
integer | |
limits.api_keys |
integer | Maximum number of active keys. |
limits.webhook_endpoints |
integer | Maximum number of webhook endpoints. |
key |
object | |
key.name |
string | |
key.prefix |
string | First 12 characters of the key. |
MeResponse
Section titled “MeResponse”| Field | Type | Description |
|---|---|---|
data |
Me |
| Field | Type | Description |
|---|---|---|
code |
string | Stable error code. New codes may be added. Values: invalid_request, invalid_cursor, invalid_api_key, plan_not_eligible, shop_inactive, insufficient_scope, referrer_not_found, not_found, rate_limited, internal_error, service_unavailable. |
message |
string | Human readable, may change. Do not parse. |
request_id |
string | Same value as the X-Request-Id header. |
ErrorResponse
Section titled “ErrorResponse”| Field | Type | Description |
|---|---|---|
error |
Error |
Response headers
Section titled “Response headers”| Header | Type | Description |
|---|---|---|
X-Request-Id |
string | Request id, also in error.request_id. Quote it to support. |
X-RateLimit-Limit |
integer | Requests allowed per 60 second window for the shop. |
X-RateLimit-Remaining |
integer | Requests left in the current window. |
X-RateLimit-Reset |
integer | Seconds until the current window ends. |
Retry-After |
integer | Seconds to wait before retrying. |
Next steps
Section titled “Next steps”- Make a first call in How to make your first API call.
- Handle failures in Understanding errors and rate limits.
- See the payloads Bloop sends in Understanding webhook events.

