Bluebarry
  • Pricing
  • Reviews
  • Resources
Sign inStart building
Help Center
Developer platform
Read Profiles via the API

Read Profiles via the API

MD
Martijn Douma · Co-founder bluebarry
Last updated: July 1, 2026

Read profile data from bluebarry over the Data API and sync it into your own systems, such as a data warehouse, a CRM, or a custom dashboard. bluebarry resolves the many touchpoints of one shopper (an anonymous quiz session, a later identified visit, a second device) into a single identity. This guide shows how to authenticate, read those identities, and pull only what changed since your last run without missing or duplicating records.

Before you start

You need an API key. Create one in Studio under Integrations, then API keys, and copy the key value. An API key is scoped to a single workspace and can read every profile in that workspace, so treat it as a secret and call the API only from a secure server, never from storefront or browser code.

Base URL
Production   https://data.bluebarry.ai/data
Staging      https://staging.data.bluebarry.ai/data

Authenticate

Send your key in the Authorization header. Use the raw key value on its own. Do not add a Bearer prefix, because a Bearer token is routed to a different login method and your request will be rejected with a 401.

List the first identities
curl "https://data.bluebarry.ai/data/Identities?\$top=5" \
  -H "Authorization: bb_your_api_key_here"

Identities or Profiles

There are two related collections. Use Identities unless you have a specific reason not to.

  • Identities returns one row per shopper, merged from every touchpoint. Each row has a stable id you can store and upsert on, plus the resolved email, phone, name, quiz answers, and recommendations. This is the right surface for syncing people into another system.
  • Profiles returns the raw, unmerged rows (one per session and user). Use it only when you specifically need the per-session detail. The same shopper can appear as several Profiles rows.

The identity shape

A valid key returns HTTP 200 with a JSON envelope. The identities are in the value array. Field names use camelCase. The quiz answers under properties and the product picks under recommendations are returned inline.

Response
{
  "@odata.context": "https://data.bluebarry.ai/data/$metadata#Identities",
  "value": [
    {
      "id": "0193b8a1-7e2c-7a10-9f4d-2b6f3c8e1a55",
      "email": "[email protected]",
      "phoneNumber": null,
      "firstName": "Alice",
      "lastName": "A",
      "userId": "34d33fe3-e88e-47cd-8b70-d0f978b5bd2a",
      "createdDate": "2026-06-01T10:00:00Z",
      "updatedDate": "2026-06-14T09:12:00Z",
      "memberCount": 3,
      "consentAccepted": true,
      "mergedIntoId": null,
      "properties": [
        { "name": "skill_level", "value": "beginner" }
      ],
      "recommendations": [
        {
          "position": 1,
          "title": "Starter Rope",
          "url": "https://shop.example/rope",
          "quizName": "Climbing Quiz",
          "price": 49.99
        }
      ]
    }
  ]
}
  • id is stable. Store it and upsert on it. It does not change as new sessions or devices join the same shopper.
  • memberCount is how many raw touchpoints were merged into this identity.
  • mergedIntoId is normally null. See Handle merges below.

Select fields, filter, and sort

The endpoint accepts the standard OData query options. URL-encode the values, so a space becomes %20 and a plus becomes %2B.

  • $select returns only the fields you list, for example $select=id,email,updatedDate.
  • $filter narrows the rows, for example on updatedDate or an email.
  • $orderby sorts the rows. Always set this when you paginate, because without it the order is not guaranteed.
  • $count=true adds an @odata.count field with the total.

For timestamps, gt is exclusive of the boundary value and ge includes it. Use an ISO 8601 UTC value such as 2026-06-01T10:10:00Z.

Paginate through large result sets

A single request returns at most 5000 rows. Set $top to choose a smaller page size (1 to 5000) and $skip to move to the next page, always alongside a stable $orderby. A $top outside the 1 to 5000 range returns HTTP 400. If you leave $top off and the result is larger than 5000 rows, the response includes an @odata.nextLink URL. Keep following it until it is no longer present.

Sync only what changed, without missing records

Every identity has an updatedDate that moves forward whenever the shopper is active. To sync incrementally, remember the newest updatedDate you processed and, on the next run, ask for identities that changed since then. Upsert each one into your system keyed on its id.

One thing to know: updatedDate is stamped when a shopper event is produced, but the change is written a moment later, and those writes are not guaranteed to land in timestamp order. So a change carrying an earlier updatedDate can become visible after you have already read past that point in time. If you filtered strictly greater than your last timestamp, you could miss it. Avoid this with a small overlap window: start each run a little before your last timestamp (for example one hour) and re-read the overlap. Because you upsert by id, re-reading a row you already have is harmless.

Incremental sync loop (pseudocode)
// cursor is the newest updatedDate you have fully processed.
let cursor = loadCursor() ?? "1970-01-01T00:00:00Z";
const OVERLAP_MS = 60 * 60 * 1000; // 1 hour safety window

async function sync() {
  const from = new Date(Date.parse(cursor) - OVERLAP_MS).toISOString();
  let newest = cursor;
  let skip = 0;

  while (true) {
    const url = new URL("https://data.bluebarry.ai/data/Identities");
    url.searchParams.set("$filter", `updatedDate ge ${from}`);
    url.searchParams.set("$orderby", "updatedDate asc,id asc");
    url.searchParams.set("$top", "1000");
    url.searchParams.set("$skip", String(skip));

    const res = await fetch(url, {
      headers: { Authorization: process.env.BLUEBARRY_API_KEY },
    });
    const { value } = await res.json();
    if (value.length === 0) break;

    for (const identity of value) {
      if (identity.mergedIntoId) {
        // This identity was merged into another; fold your local copy into mergedIntoId.
        redirect(identity.id, identity.mergedIntoId);
      } else {
        upsertById(identity.id, identity); // idempotent: re-reads are harmless
      }
      if (identity.updatedDate > newest) newest = identity.updatedDate;
    }
    skip += value.length;
  }

  saveCursor(newest); // advance only after the run fully succeeds
}

Advance and store the cursor only after a run completes successfully. If a run fails halfway, the next run starts from the old cursor and the overlap window covers anything in between.

Handle merges

Occasionally two identities turn out to be the same shopper. For example, an anonymous visitor later provides an email that was already on another identity. When that happens, bluebarry keeps one surviving identity and marks the other with a mergedIntoId that points at the survivor. The tombstoned identity still appears in the changes feed, so your sync can fold your local copy of the old id into the survivor. Filter with mergedIntoId eq null when you only want live identities.

Limits and good practices

  • Request at most 5000 rows per call and page through the rest.
  • Use $select to fetch only the fields you need. It keeps responses small and fast.
  • Identities contain personal data such as email, phone, and name. Store and process it in line with your privacy obligations, and honor the consentAccepted flag.
  • Keep your API key on the server. If a key is exposed, delete it in Studio and create a new one.

Related articles

API Authentication Overview

bluebarry supports API authentication for approved integrations through API keys, OAuth, and tenant-aware requests. Use the method that matches your integration type.

Manage API Keys

Create API keys for approved external tools, server-side automations, and integration workflows that need to read bluebarry data.

Use the Identify API

Use the Identify API to attach a known email or external identity to an existing quiz visitor after checkout or login.

Join the bluebarry community on Discord

Ask questions, share wins, and get support from the team and other e-com brands building with bluebarry.

Join Discord (free forever)

Need help?

If you can't figure it out, we probably can. Just give us a heads up in Discord or email ([email protected]).

Contact us

Platform

  • E-Com Funnels
  • Landing pages
  • Product Quiz
  • Recommendations
  • Integrations
  • Search
  • Pricing
  • Features
  • Reviews

Integrations

  • Shopify
  • Magento
  • WooCommerce
  • Klaviyo

Resources

  • Getting started
  • Resources
  • Help center
  • Shopify Quiz FAQ
  • Klaviyo Quiz FAQ

Contact

  • Partners & affiliate
  • Contact us
  • Request demo

[email protected]

+31 6 57 16 10 87

Hamburgerstraat 10, 9714 JB Groningen (The Netherlands)

LinkedInYouTube
Martijn Douma
Stan van Rooy
Anco Postma
Jelmer Reitsma

© 2026 Bluebarry AI. All rights reserved.

Privacy PolicyCookie PolicyTerms & Conditions