Admin API Reference
Setup
Base URL
Admin API endpoints are relative to the base API URL:
https://api.behold.so/v1
Authentication
All API requests must be authenticated with an API access token. API access tokens can be generated on the developer settings page of your Behold dashboard. You can have up to two active API access tokens at a time. This is useful for rolling tokens without downtime.
Access tokens should be sent as a Bearer
token in the Authorization
header.
API tokens provide privileged access to your account and should never be used in client-side code or committed to public repositories.
Limitations
- Bulk updates are not supported. You can create or update only one object per request
- Currently only “grid” widgets are available to create or update via the API
- Klaviyo widgets cannot be created or updated via API
Rate limits
Currently the only hard limit on API usage is a cap of 120 requests per minute. If you exceed this you will receive a 429
“Too many requests” error.
In general you should rely on webhooks to monitor your sources and feeds and keep your DB in sync with your Behold account, rather than something like polling.
If you’re regularly bumping into this limit and can’t adjust your request frequency we are happy to set up a custom plan to accommodate. We always reserve the right to deny access to our API for any reason, however, including if we cannot come to an agreement and usage is too high or abusive in some way.
All responses from the API will include the following ratelimit-*
headers that allow you to track and manage your usage.
ratelimit-policy
Describes the rate limit policy that currently applies. In the format 120;w=60
, which describes a policy of 120 allowed requests in a window of 60 seconds.
ratelimit-limit
The maximum number of requests allowed in the given window.
ratelimit-remaining
The number of requests you are still allowed in the current window.
ratelimit-reset
The number of seconds remaining before the rate-limit window resets.
Dates and time
All timestamps are defined in milliseconds since the UNIX epoch. All dates / intervals are UTC time.
Field filtering
List requests that return multiple objects accept a fields
parameter. This is a comma-separated list of fields to return. The keyword all
may also be used to return all fields.
Some nested map fields have their own fields param. In those cases, the parameter will be named [field]_fields
. E.g. associatedAccounts_fields
.
Field expansion
Some fields will return a simple value by default (e.g. a string or integer), but can be expanded to return more details. These fields are marked with the EXPANDABLE
tag. Expansion is accomplished by using the expand
parameter, which accepts a comma separated list of field keys.
At the moment only the views
field on feeds can be expanded. You would accomplish this by adding the query param &expand=views
to your request.
Pagination
Sources and feeds can both be fetched in bulk using “list” API endpoints. These endpoints return a cursors
field alongside response data. This field contains two properties: before
and after
. When you first make a call to a list endpoint, if there are more results than can be shown in a single response (defined by the limit
parameter), then cursors
will look like this:
This tells you two things:
before
isnull
, so you are at the beginning of the total set of resultsafter
is populated with a cursor ID, so there are more pages of results available
To get the next page of results, make a request with the value of after
in the cursor
param:
This will return the next set of results. By using this method, you can traverse every page of results. When after
is null
, you have reached the end and no more results are available.
Likewise, if before
is populated you can move backwards in the set of results by using the before
cursor ID in the cursor
parameter.
Behind the scenes, cursors mark a specific point in a sorted set of results. When moving forwards through results, all results after the cursor are returned. When moving backwards through results, all results before the cursor are returned.
This can produce a slightly unintuitive result in a specific corner case: If you include a cursor in your request with a before
id, and you also increase the limit
so that it’s higher than the number of results available before the cursor, you will see fewer results than the limit
could theoretically allow. This is because you are only shown results in the dataset before the cursor. The inverse also applies to after
.
Errors
We use standard HTTP response codes to indicate the success or failure of an API request.
Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed because of issues with the request (a required parameter was omitted, a resource wasn’t found, etc.). Codes in the 5xx range indicate an error on our side.
Errors return a JSON object in the response body with the following attributes:
status enum
This will always be error
.
statusCode integer
The HTTP status code.
message string
A message explaining the error.
details map?
Some errors will return a details
field with more specific information about the error.
Example error
The Source object
A source represents a connection to Instagram. There are two types of sources: Basic
and Advanced
. Advanced sources may have one or more associated Instagram accounts. To learn more see Basic vs Advanced Sources.
You cannot create a source directly. Instead, a source is added to your account when a user visits your unique auth link and authorizes Behold to access their Instagram account.
Shared attributes
These attributes are common to both Basic and Advanced sources.
id string
Unique source ID. Basic sources use the Instagram Account ID for this field. So a Basic source and an advanced source associated account could have the same ID.
customId nullable string
This is a custom ID you can define. It’s useful for associating Behold sources with entities in your DB. customId
is added during the auth process and cannot be changed. See connecting to instagram.
type enum
The type of source. One of instagramBasic
or instagramAdvanced
.
label string
A label for this source. For basic sources this is the Instagram username. For advanced sources, it is either the name of the connected Facebook business portfolio or user.
expiresOn nullable timestamp
Advanced sources connected through a Facebook user need to be manually reauthorized every three months. This field contains the expiration date,in the form of a UNIX timestamp. For other sources this will be null
.
needsReauth boolean
If this source has been disconnected from Instagram for any reason (i.e. its access token was invalidated), this will be true
.
Basic attributes
Basic sources have all shared attributes plus the following:
username string
The Instagram username.
website nullable string
The website
field set in Instagram.
biography nullable string
The biography
field set in Instagram.
profilePicture nullable string
The Instagram profilePicture saved as a 500 x 500
.webp image.
followsCount integer
The number of other accounts this account is following.
followersCount integer
The number of followers this account has.
mediaCount integer
The total number of posts this account has published.
Advanced attributes
Advanced sources have all shared attributes plus an associatedAccounts
field:
associatedAccounts array of AssociatedAccounts
This contains an array of associated accounts. These are Instagram accounts attached to this source that can be used to create feeds. Associated accounts share all attributes with Basic
sources except type
, expiresOn
and needsReauth
. In addition to their shared attributes, associated accounts have a recentlyQueriedHashtags
field.
+ Show child attributes Hide child attributes
recentlyQueriedHashtags array of strings
This lists the hashtag queries made on behalf of this account over the past 7 days. Each Instagram account may only access up to 30 hashtags in a 7 day window.
Retrieve a source
GET /sources/:sourceId
Parameters
Accepts no parameters.
Return value
Returns a JSON object containing all fields for a single source.
Example request
List all sources
Returns all available sources, sorted by label
in ascending alphabetical order.
GET /sources
Parameters
limit integer
Limits the number of responses. Limit can range between 1 and 100. The default is 10.
fields comma-delimited string
Specifies a subset of fields to return. Set to all
to return all fields. The default is id
.
associatedAccounts_fields comma-delimited string
Specifies a subset of associated account subfields to return. Set to all
to return all subfields. The default is id
. When this parameter is set, associatedAccounts
will always be returned even if not listed in fields
.
cursor string
See pagination.
Return value
Returns an array of all available sources.
Example request
Delete a source
DELETE /sources/:sourceId
Deletes a single source. This will also delete any feeds using this source.
Parameters
Accepts no parameters.
Return value
Returns a JSON object containing the id
and label
of the source.
Example request
The Feed object
A feed represents a set of the most recent Instagram posts published to an account, output either as a widget for drop-in embedding, or as JSON for consumption by your code.
The Admin API is used only for managing feeds, not consuming them. So there is no endpoint here that will return the actual posts from a feed. Instead, once you have created a feed, you can use it with an embedded widget by specifiying the feed ID, or by sending a GET to feeds.behold.so/FEED_ID
in the case of a JSON feed.
Attributes
Fields marked read-only
are generated server-side and cannot be set during create or update requests. Fields marked immutable
are set during feed creation and then cannot be changed.
id string read-only
The unique ID of this feed.
title string
A title / label for the feed. Not guaranteed to be unique.
sourceId string immutable
The ID of the source associated with this feed.
associatedAccountId string immutable
The ID of the associated Instagram account to use. Only exists on feeds with advanced sources, which may have one or more associated Instagram accounts.
sourceType enum read-only
The type of the source associated with this feed. Either instagramBasic
or instagramAdvanced
.
contentSource enum immutable
The source of posts for this feed. Either user
or hashtag
. Default user
.
User feeds are populated with posts from a single Instagram account. Hashtag feeds are populated with public posts from one or more hashtags. You can learn more on our hashtag feeds page.
hashtags array of strings immutable
An array of the hashtags used to populate this feed.
outputType enum immutable
The type of feed. Either json
or widget
.
created timestamp read-only
A timestamp marking when the feed was created, in milliseconds since the UNIX epoch.
mediaCount integer read-only
The total number of posts published by this account. This is not the number of posts that will be returned by the feed. That is determined by settings.maxPosts
.
views integer | map read-only expandable
By default this is an integer representing the total number of views this feed has received during the current month (all intervals are in UTC time). When expanded, it provides a breakdown of usage by month and day. Both days and months are 1-indexed. In expanded form, only months and days with views are included. So while entries are sorted in ascending order, they may not be consecutive. For example you might have the 1st and 2nd of the month, and then skip to the 4th if there was no usage on the 3rd.
List queries with expanded views only return data for the current month. Single /feeds/:feedId
requests return up to twelve months of usage data.
Example of a views field:
settings map
A map of feed settings. + Show child attributes Hide child attributes
settings.filter map
A map of settings that filter the content returned by this feed.
+ Show child attributes Hide child attributes
settings.filter.allowedTypes array of enums
This setting dictates which post types are included in this feed. At least one type is required. Allowed values are IMAGE
, VIDEO
, REEL
and CAROUSEL_ALBUM
. Default ["IMAGE", "VIDEO", "REEL", "CAROUSEL_ALBUM"]
.
settings.filter.captionExcludeText array of strings
Only posts that do not contain any of the text snippets you add here will be included in your feed. This is case-sensitive and can include spaces. A maximum of 3 strings may be excluded. Default [ ].
settings.filter.captionIncludeText array of strings
Only posts that contain at least one of the text snippets you add here
will be included in your feed. This is case-sensitive and can include spaces. A maximum of 50 strings may be included. Default [ ]
.
settings.maxPosts integer
Sets the number of posts to return. The maximum value is determined by your plan. The Platform
plan allows a max of 50 posts per feed. If you need more, get in touch: sales@behold.so. Default 6
.
settings.domainWhitelist array of strings
This option blocks feed requests that do not originate from one of the whitelisted domains. If you leave this blank, all requests are allowed.
Subdomains are independent and wildcards are not supported. So example.com
and www.example.com
must be entered separately. The protocol (e.g. https://
) is ignored.
localhost
is always whitelisted.
Default [ ]
Note
The domain whitelist provides a layer of defense against people just copy/pasting a feed, but there are ways around it. Because no API keys or secrets are exposed, this isn’t a serious security risk, however.
widgetSettings map
A map of widget settings. Only included in widget feeds. + Show child attributes Hide child attributes
widgetSettings.type enum immutable required
The style of widget. Currently only grid
widgets are supported for creation or update by the admin API. This attribute is required if you are updating any widgetSettings
attributes.
widgetSettings.constrainWidth boolean
If set to false
, the widget will always grow to fit the width of its containing element. If set to true
, the width will be capped at the value of maxWidth
setting. Default false
.
widgetSettings.maxWidth integer
The max width of the widget. Ignored if constrainWidth
is set to false
. Default 650
.
widgetSettings.alignment enum
The horizontal alignment of the widget within its container. One of left
, center
, right
. Ignored if constrainWidth
is set to false
. Default center
widgetSettings.numColumns integer
The number of columns posts will be arranged in for grid
widgets. Default 3
.
widgetSettings.gap map
The vertical and horizontal gap between posts.
+ Show child attributes Hide child attributes
widgetSettings.gap.x integer
The horizontal gap between posts. Default 20
.
widgetSettings.gap.y integer
The vertical gap between posts. Default 20
.
widgetSettings.postAspectRatio map
The aspect ratio of widget posts. If you want to use the format of reels, set to { x: 9, y: 16 }
+ Show child attributes Hide child attributes
widgetSettings.postAspectRatio.x integer
Post width. Default 1
.
widgetSettings.postAspectRatio.y integer
Post height. Default 1
.
widgetSettings.borderRadius integer
The post border radius / rounded corners. Default 0
.
widgetSettings.loadingColor enum
Color to show while a post loads. One of dominant
, muted
, vibrant
, mutedLight
, vibrantLight
, mutedDark
, vibrantDark
, tone
, transparent
. Default dominant
.
If tone
, the color is set by the loadingColorTone
setting.
If transparent
, no color is shown.
The rest of the options extract a color from the post media itself using different algorithms.
widgetSettings.loadingColorTone string
An RGB color as a string in the format r,g,b
. Defines the placeholder color to use if loadingColor
is set to tone
. The rendered color will be slightly lighter or darker depending on the contents of the post media. Default 225,73,57
.
widgetSettings.onHover enum
Defines the behavior on hover. One of showIcon
, showCaption
, or none
. Default showIcon
.
widgetSettings.hoverEffect enum
The effect to display on hover. One of fade
, zoomFade
, blur
, zoomBlur
, toGreyscale
, zoomToGreyscale
, fromGreyscale
, zoomFromGreyscale
, or none
. Default zoomFade
.
widgetSettings.hoverOverlayColor enum
The color of the overlay displayed on hover. One of default
, auto
, or custom
. Default default
(duh).
default is a semi-transparent black overlay.
auto extracts a color from the post media using the dominant
algorithm.
custom allows defining a custom color using the hoverOverlayCustomColor
setting.
This setting is ignored unless hoverEffect
is set to fade
or zoomFade
.
widgetSettings.hoverOverlayCustomColor string
An RGB color as a string in the format r,g,b
. Defines the overlay color to show on hover when hoverOverlayColor
is set to custom
. Default ‘0,0,0’.
widgetSettings.hoverOverlayOpacity integer
An integer ranging from 0 - 100
. Sets the opacity of the overlay to show on hover. This setting is ignored unless hoverEffect
is set to fade
or zoomFade
. Default 65
.
widgetSettings.previewVideosOnHover boolean
If set to true
, videos will autoplay muted on hover. Default true
.
widgetSettings.autoplayVideos boolean
If set to true
, videos will autoplay muted on load. Default false
.
widgetSettings.onPostClick enum
Defines the behavior when a post is clicked. One of linkToPost
, linkToProfile
, customLink
, openPopupGallery
, doNothing
. Default linkToPost
.
widgetSettings.customLinkURL string
Defines where a user will be sent when they click on a post and onPostClick
is set to customLink
. Default ""
.
widgetSettings.linkTarget enum
One of _blank
or _self
. Default _blank
. This dictates if post links should open in a new tab or not. If set to _blank
, links will open in a new tab.
widgetSettings.popupColorTheme enum
Defines the color theme of the popup gallery. Ignored unless onPostClick
is set to openPopupGallery
. One of auto
, light
, or dark
. Default auto
.
widgetSettings.breakpoints map
A map of breakpoint settings. The key of a breakpoint entry is a number representing the width where the breakpoint applies, and the value is a map of options that will override the base options set on the widget. Breakpoints are applied based on the width of the widget itself, not the window.
The options that can be set in a breakpoint are maxPosts
, numColumns
, borderRadius
, postAspectRatio
, and gap
. If you omit an option, it will default to the primary value in widgetSettings
.
To remove a specific breakpoint, set the value to null
.
Here’s an example breakpoint configuration:
In this example, at 900px the widget will have maxPosts set to 6 and numColumns set to 3. Then, once the widget hits 500px, a different set of settings is applied. A previously set breakpoint at 650px is deleted.
Create a feed
POST /feeds
Tip
You can get a ready-to-use feed config in the Behold dashboard by clicking on the three dots next to a feed title and selecting “Copy config”. The copied JSON can be sent to this endpoint to create a new feed.
This lets you style a widget using our GUI and then create new feeds with the same setup via API. You’ll usually want to change the title
and sourceId
.
Request attributes
This endpoint accepts a feed object in the request body as a JSON-encoded string. All feed attributes may be included except those marked read-only.
sourceId
, title
, and outputType
are required. If you are creating a feed using an advanced source, associatedAccountId
is required. Any field you omit will use the default value.
Return value
Returns the Feed object with all fields after successful creation.
Example request
Update a feed
PATCH /feeds/:feedId
Request attributes
This endpoint accepts a feed object in the request body as a JSON-encoded string. All feed attributes may be included except those marked read-only or immutable.
Return value
Returns the Feed object with all fields after successfully updating.
Example request
List all feeds
GET /feeds
Returns all available feeds, sorted by title
in ascending alphabetical order.
Parameters
limit integer
Limits the number of responses. Limit can range between 1 and 100. The default is 10.
fields comma-delimited string
Specifies a subset of fields to return. Set to all
to return all fields. The default is id
.
expand comma-delimited string
Specifies fields to expand. Currently only views
can be expanded. For more information see field expansion.
cursor string
See pagination.
Return value
Returns an array of all active feeds in your account.
Example request
Retrieve a feed
GET /feeds/:feedId
Parameters
Accepts no parameters.
Return value
Returns a JSON object containing all fields for a single feed.
Example request
Delete a feed
DELETE /feeds/:feedId
Parameters
Accepts no parameters.
Return value
Returns a JSON object containing the id
, title
, sourceId
, and sourceType
of the feed. Feeds created with advanced sources will also return associatedAccountId
.