CounterMeasure

Ingestion API

One endpoint. Send each completed transaction and CounterMeasure handles the rest: hashing, filtering, deduplication, retries, and delivery to the store’s Meta dataset as a Purchase · Physical store event.

Endpoint

POST https://countermeasure.bigrush.com/v1/ingest
Authorization: Bearer cm_live_…
Content-Type: application/json

Each API key belongs to exactly one store and can only write to it. Store owners create and rotate keys on the store page of the dashboard. Up to 1,000 transactions per request.

Transaction fields

FieldRequiredNotes
order_idYesUnique per store. Sending the same id again is safe: it’s counted once.
occurred_atYesISO 8601. Include the UTC offset; without one, the store’s time zone is assumed.
total—Sale value in the store’s currency. Rows under $0.01 are skipped by default.
email—Raw or already-normalized. Hashed (SHA-256) the moment it arrives.
phone—Any format. Normalized to digits with country code, then hashed.
first_name / last_name—Optional. Hashed; improves Meta’s match rate.
type—Transaction type (e.g. sale, buy). Stores can choose which types to send.
store_id—Optional. If present, it must match the store the key belongs to.

At least one of email or phone is needed; a sale Meta can’t match to a person is skipped.

Response

HTTP/1.1 202 Accepted
{
  "store": "204",
  "received": 3,
  "accepted": 1,
  "duplicates": 1,
  "skipped": { "low_value": 1 }
}

Skip reasons: low_value, too_old (older than the store’s freshness window, 5 days by default; Meta rejects anything over 7), no_customer_match_keys, no_order_id, bad_timestamp, excluded_type. Errors: 401 invalid_api_key, 422 invalid_body / store_mismatch.

Example: Ruby

require "net/http"
require "json"

# One key per store, from the CounterMeasure dashboard.
uri = URI("https://countermeasure.bigrush.com/v1/ingest")
req = Net::HTTP::Post.new(uri, "Content-Type" => "application/json",
                          "Authorization" => "Bearer #{ENV.fetch("COUNTERMEASURE_API_KEY")}")
req.body = {
  transactions: [{
    order_id:    transaction.id.to_s,          # unique per store; used to dedupe
    occurred_at: transaction.created_at.iso8601,
    total:       transaction.total.to_f,
    email:       customer&.email,
    phone:       customer&.phone,
    first_name:  customer&.first_name,
    last_name:   customer&.last_name,
    type:        transaction.kind,            # e.g. "sale" / "buy"
    store_id:    location.store_number        # optional safety check
  }]
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
raise "CounterMeasure #{res.code}: #{res.body}" unless res.code == "202"

Privacy

Email, phone and names are hashed with SHA-256 before they are stored or sent; raw values are never written to our database or logs. Each store owner attests that customer data was collected in line with Meta’s Business Tools Terms before connecting.