Bento API
Search…
⌃K

Multi-Query Example

This is a short example that showcases a few endpoints most API users will need.
The following guide uses basic Ruby in it's examples. You can use any language of choice in your implementation.
Just make sure that you remember to keep your API keys safe and secure 🙏

Basics

To access data in Bento, you'll need three things:
  • Your Site Key/UUID.
  • Your user's Private API Key.
  • Your user's Public API Key.
You can expire your Private and Public Keys but cannot expire your Site Key without a support request. All requests to our API are logged and monitored for anomalies.

Rate Limiting

All requests to fetch have a maximum of 3,600 requests per hour.
All requests to batch have a maximum of 500 requests per hour.

Typical Issues

When we chat to developers we typically see a few issues come up when interacting with the API.
The most common issue is incorrect API or Site Keys. If you can't find them, you can raise a support ticket or ask us in Discord and we'll find them for you.
The second most common issue is hitting rate limits (described above). Please make sure you're using the appropriate endpoint for whatever task you are doing in Bento.

With all that said, let's begin the example!

To begin, let's start wth using the fetch/subscribers endpoint to add a new visitor record into Bento via their email address.
In Bento, a subscriber is essentially a visitor with an email added to their profile.
A GET request to this endpoint will simply try to find a visitor who has the email you specified to confirm that they have been synced whereas a POST request will either lookup the visitor or create it by email. For almost all cases, you will want to POST to the endpoint.
create_subscriber.rb
require 'net/http'
require 'uri'
publishable_key = "XXXX-XXXX-XXXX-XXXX"
secret_key = "XXXX-XXXX-XXXX-XXXX"
site_uuid = "XXXX-XXXX-XXXX-XXXX"
uri = URI.parse("https://app.bentonow.com/api/v1/fetch/subscribers")
request = Net::HTTP::Post.new(uri)
request.basic_auth(publishable_key, secret_key)
request.body = JSON.dump({site_uuid: site_uuid, email: "[email protected]"})
request.content_type = "application/json"
req_options = { use_ssl: uri.scheme == "https", }
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts JSON.parse(response.body)
After running this we will get a response confirming the visitor was added and their details.
{"data"=>{"id"=>"568", "type"=>"visitors", "attributes"=>{"uuid"=>"9b91f034d6692e3ec61830705ceef818", "email"=>"[email protected]", "fields"=>nil, "cached_tag_ids"=>[]}}}

Now, let's add some data to the profile without triggering any automations.

The visitor has now been added to Bento so we're going to want to flesh out their profile with some more detail.
Let's add a customer tag to the profile using the fetch/commands endpoint.
We will be using the add_tag command instead of the add_tag_via_query as we do not want to fire any automations.
add_tag.rb
uri = URI.parse("https://app.bentonow.com/api/v1/fetch/commands")
request = Net::HTTP::Post.new(uri)
request.basic_auth(publishable_key, secret_key)
request.body = JSON.dump({site_uuid: site_uuid, command: {"command": "add_tag", "email": "[email protected]", "query": "example" }})
request.content_type = "application/json"
req_options = { use_ssl: uri.scheme == "https", }
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts JSON.parse(response.body)
After running this we'll see that the tag has been added.
{"data"=>{"id"=>"569", "type"=>"visitors", "attributes"=>{"uuid"=>"29114b07bcfedbff608e5223e88fadc0", "email"=>"[email protected]", "fields"=>nil, "cached_tag_ids"=>["233"]}}}
The ID that you see in the cached_tag_ids field can be looked up via the fetch/tags endpoint if you need it.
In later API updates we may put the names of the tags in this response but have avoided it for now to optimize the request.
Next, let's add a name to the visitor using the fetch/commands endpoint again.
add_custom_field.rb
uri = URI.parse("https://app.bentonow.com/api/v1/fetch/commands")
request = Net::HTTP::Post.new(uri)
request.basic_auth(publishable_key, secret_key)
request.body = JSON.dump({site_uuid: site_uuid, email: "[email protected]", command: {"command": "add_field", "email": "[email protected]", "query": {key: "name", value: "Jesse"} }})
request.content_type = "application/json"
req_options = { use_ssl: uri.scheme == "https", }
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Great! Looks like the visitor now has a customer tag and name added.
{"data"=>{"id"=>"569", "type"=>"visitors", "attributes"=>{"uuid"=>"29114b07bcfedbff608e5223e88fadc0", "email"=>"[email protected]", "fields"=>{"name"=>"Jesse"}, "cached_tag_ids"=>["233"]}}}
They're now ready to receive email marketing!
If you visit the dashboard you'll be able to search for this visitor by any of the data you've added. These endpoints are processed and synced to our search engine within 5-15 seconds most of the time.

Let's backfill all our old data.

Now that the above code is sending in user data in real-time it's time to upload all our old subscribers.
For this, we use our batch/subscribers endpoint.
This takes in an array of subscriber information and queues it up quickly to our importer background jobs. This generally processes over a period of 5 to 50 minutes depending on the queue size, if our importer servers are warm, and how many you're adding.
import_subscribers.rb
import_data = [
{ email: "[email protected]", name: "Jesse", customer_id: "123", favourite_food: "onigiri" },
{ email: "[email protected]", name: "Scott", customer_id: "124" },
]
uri = URI.parse("https://app.bentonow.com/api/v1/batch/subscribers")
request = Net::HTTP::Post.new(uri)
request.basic_auth(publishable_key, secret_key)
request.body = JSON.dump({site_uuid: site_uuid, subscribers: import_data })
request.content_type = "application/json"
req_options = { use_ssl: uri.scheme == "https", }
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Once this runs the data will be added to a queue and you will see a count as the response. No further action is required and you can just wait for the import to finish running in your account.

Let's get some event data into the system.

publishable_key = "XXXX-XXXX-XXXX-XXXX"
secret_key = "XXXX-XXXX-XXXX-XXXX"
site_uuid = "XXXX-XXXX-XXXX-XXXX"
import_data = [
{ email: "[email protected]", type: "$custom_event", fields: {"first_name": "Jesse"}, details: {"custom_stat": 1000}},
{ email: "[email protected]", type: "$custom_event_with_no_details", fields: {"first_name": "Jesse", "last_name": "Hanley"}},
{ email: "[email protected]", type: "$custom_event_with_workflow_bypass", details: {"bypass_workflows": 'true'}},
{ email: "[email protected]", type: "$custom_event_with_nothing_else"},
{ email: "[email protected]", type: "$purchase", fields: {"first_name": "Jesse"}, details: {"unique": {"key": "test123" }, "value": {"currency": "USD", "amount": 8000}}},
{ email: "[email protected]", type: "$purchase", fields: {"first_name": "Jesse"}, details: {"unique": {"key": "test123" }, "value": {"currency": "USD", "amount": 8000}, 'cart' => { 'items' => [{'product_sku': 'SKU123', 'product_name': 'Test', 'quantity': 100 }], 'abandoned_checkout_url': "https://test.com" }}},
{ email: "[email protected]", type: "$backdated_event", date: 3.years.ago }
]
uri = URI.parse("https://app.bentonow.com/api/v1/batch/events")
request = Net::HTTP::Post.new(uri)
request.basic_auth(publishable_key, secret_key)
request.body = JSON.dump({site_uuid: site_uuid, events: import_data })
request.content_type = "application/json"
req_options = { use_ssl: uri.scheme == "https", }
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts JSON.parse(response.body)
In the above script, we're including new events, old events, and events that bypass automations. Without the bypass key we'd expect them to trigger every Workflow that's turned on.