Read one post by URL, or many posts by identifier list
const url = 'https://atlas.aspire.io/api/v1/posts?url=https%3A%2F%2Fwww.instagram.com%2Fp%2FDEF456%2F&network=instagram';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://atlas.aspire.io/api/v1/posts?url=https%3A%2F%2Fwww.instagram.com%2Fp%2FDEF456%2F&network=instagram' \ --header 'Authorization: Bearer <token>'Two mutually exclusive forms — supplying both url and ids is a 400. url is a single read: returns the post document wrapped as { data: <post> } (200), a FetchingResponse (202), or an error envelope (404). ids is the batch form: always 200, the three-bucket envelope. A post read can take longer than an account read — it may walk the author’s recent media. Requires posts:read.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The post’s URL — the single-read identifier (a post identifier is a URL, unlike a creator’s clean network/handle segments). Exactly one of url or ids must be supplied.
Examples
https://www.instagram.com/p/DEF456/Comma-separated identifiers, 1–100 — selects the batch form. Same identifier grammar as GET /creators?ids=. Exactly one of url or ids must be supplied.
Default network for BARE identifiers in ids (defaults to instagram). Never a filter — a qualified (instagram:handle) or URL identifier carries its own network.
ASP-1144 — comma-separated AI-enrichment fields to add to the returned analysis object (both the url and ids forms of GET /posts; not supported on POST /posts/batch). Each named field appears under analysis in the response ONLY when requested — an unrequested field’s key is entirely absent, never null-padded. Supported values: narration, transcript, overlayText, languages, aestheticTags, brandSafety, commercialAnalysis, emotionalAnalysis, productionAnalysis, vibeAnalysis, subjectAnalysis, commentSentimentLabel, commentSentimentScore, commentSentimentSummary, commentSentimentRationale, commentSentimentThemes, commentSentimentBreakdown, commentSentimentTotalCommentCount, commentSentimentRelevantCommentCount. An unrecognized value is a 400.
Names a target Organization to act on, when it differs from your credential’s own organization — for a delegated agency/partner relationship.
Attribution only — associates this read’s discovery/refresh work with one of your Profiles, resolved within your organization.
Responses
Section titled “Responses”SinglePostResponse ({ data: <post> }) for the url form; PostsBatchResponse (the three-bucket envelope, Retry-After present iff fetching is non-empty) for the ids form.
Returned with HTTP 200: the document we hold, wrapped the same way a batch read’s data bucket wraps each entry.
object
object
The social network this post is on.
The post’s network-native identifier.
The post’s public permalink.
ISO 8601 timestamp of when the post was published.
The post’s caption text.
The post’s media type — video, image, or carousel.
Total like count.
Total comment count.
Total view count.
Total share count.
Total save count.
The post’s author — a thin, no-PII summary of the creator account.
object
The post author’s network-native account identifier.
The post author’s @handle.
Total number of followers the post author has.
Whether the post author’s identity is verified on the network.
The post author’s country.
The full Instagram-specific field set for this post — present with every field null/empty if not yet observed, never entirely absent.
object
Numeric media id for this post.
The Instagram-scoped user id of the post’s author.
The post author’s @handle (core author.username is canonical).
Short alphanumeric code for this post, as used in its permalink.
The post’s raw media-type value (core mediaKind is the mapped video/image/carousel value).
The type of audio used in the media. Can be MUSIC or ORIGINAL_SOUND.
Product-type classification for this media (e.g. feed post, reel, story).
For Reels only. When true, the reel can appear in both the Feed and Reels tabs. When false, the reel can only appear in the Reels tab.
The post’s public URL — same value as core url.
The post’s caption text — same value as core text.
Likes attributable to organic (non-paid) delivery only.
Total likes across organic and paid delivery — same value as core likeCount.
Comments attributable to organic delivery only.
Total comments across organic and paid delivery — same value as core commentCount.
Views attributable to organic delivery only.
Total views across organic and paid delivery — same value as core viewCount.
Reposts (reshares by other accounts) attributable to organic delivery.
Saves attributable to organic delivery only.
Shares attributable to organic delivery only.
Distinct accounts that organically saw this post.
Sum of organic likes, comments, saves, and shares on this post.
Accounts that started following the creator as a direct result of this post (organic only).
Visits to the creator’s profile attributable to this post (organic only).
The number of actions people took on the creator’s profile after visiting it from this post — bio link clicks, or taps on the call, direction, email, or text buttons (organic only, feed and story posts).
Views of this post’s cross-posted copy on Facebook (organic only).
Total number of times this post was played, aggregated across Instagram and Facebook (organic only, Reels only).
Average watch time per view, for Reels (organic only).
Total cumulative watch time across all views, for Reels (organic only).
Clicks on a link included in this post (e.g. a Story link sticker), organic only.
Total navigation actions taken while viewing this post — the sum of exits, taps forward, taps back, and advances to the next story (organic only, story posts).
Replies sent in response to this post (e.g. Story replies), organic only.
Instances of a viewer exiting out of this post entirely (e.g. leaving a Story), organic only.
Taps to advance past this post (e.g. tapping forward through a Story), organic only.
Taps to go back and re-view this post (e.g. tapping back through a Story), organic only.
Hashtags extracted from this post’s caption.
Accounts mentioned in this post — see PostMention fields above.
object
The @handle of the mentioned account.
How the mention occurred — TAG, CAPTION, STORY, COLLAB, or PAID_PARTNERSHIP.
Whether the mentioned username has been resolved to a known account in our system.
ISO 8601 timestamp of when this post’s current snapshot was produced — how fresh this document is.
AI-generated (Gemini multimodal) enrichment preview — opt-in via ?include= (see the include query parameter), one key per requested field. Coverage and shape may change without notice.
object
AI-generated (Gemini multimodal) narration of the video/audio content.
AI-generated (Gemini multimodal) transcript of spoken audio.
AI-detected on-screen text overlays, in detection order.
AI-detected spoken/on-screen languages, as free-text labels.
AI-generated free-text aesthetic/style tags.
AI-judged brand-safety risk per GARM category — a judged VERDICT, not raw enrichment. null if not yet judged, or if the judged shape no longer matches the current GARM taxonomy.
object
AI-detected commercial signals — featured products/brands, calls to action, promo codes, and a 1-5 promotional-intent score.
object
AI-judged primary emotion and tone.
object
AI-judged production quality and technique signals.
object
Opaque AI-generated vibe classification — shape is not fixed; treat as untyped JSON.
Opaque AI-generated subject classification — shape is not fixed; treat as untyped JSON.
AI-judged overall comment sentiment label.
AI-judged overall comment sentiment score.
AI-generated free-text summary of comment sentiment.
AI-generated free-text rationale for the sentiment judgment.
AI-generated free-text comment themes.
AI-judged comment sentiment split into positive/neutral/negative buckets, each a count and percentage of comments analyzed.
object
object
object
object
Total comments considered in the sentiment judgment.
Comments judged relevant to the sentiment analysis — a subset of the total.
The three-bucket batch envelope, returned with HTTP 200 always — per-item outcomes are buckets, never per-item HTTP statuses. Every submitted identifier appears in exactly one bucket. The response’s Retry-After header is present iff fetching is non-empty.
object
Documents we hold — same shape as the single read’s 200 body.
object
The social network this post is on.
The post’s network-native identifier.
The post’s public permalink.
ISO 8601 timestamp of when the post was published.
The post’s caption text.
The post’s media type — video, image, or carousel.
Total like count.
Total comment count.
Total view count.
Total share count.
Total save count.
The post’s author — a thin, no-PII summary of the creator account.
object
The post author’s network-native account identifier.
The post author’s @handle.
Total number of followers the post author has.
Whether the post author’s identity is verified on the network.
The post author’s country.
The full Instagram-specific field set for this post — present with every field null/empty if not yet observed, never entirely absent.
object
Numeric media id for this post.
The Instagram-scoped user id of the post’s author.
The post author’s @handle (core author.username is canonical).
Short alphanumeric code for this post, as used in its permalink.
The post’s raw media-type value (core mediaKind is the mapped video/image/carousel value).
The type of audio used in the media. Can be MUSIC or ORIGINAL_SOUND.
Product-type classification for this media (e.g. feed post, reel, story).
For Reels only. When true, the reel can appear in both the Feed and Reels tabs. When false, the reel can only appear in the Reels tab.
The post’s public URL — same value as core url.
The post’s caption text — same value as core text.
Likes attributable to organic (non-paid) delivery only.
Total likes across organic and paid delivery — same value as core likeCount.
Comments attributable to organic delivery only.
Total comments across organic and paid delivery — same value as core commentCount.
Views attributable to organic delivery only.
Total views across organic and paid delivery — same value as core viewCount.
Reposts (reshares by other accounts) attributable to organic delivery.
Saves attributable to organic delivery only.
Shares attributable to organic delivery only.
Distinct accounts that organically saw this post.
Sum of organic likes, comments, saves, and shares on this post.
Accounts that started following the creator as a direct result of this post (organic only).
Visits to the creator’s profile attributable to this post (organic only).
The number of actions people took on the creator’s profile after visiting it from this post — bio link clicks, or taps on the call, direction, email, or text buttons (organic only, feed and story posts).
Views of this post’s cross-posted copy on Facebook (organic only).
Total number of times this post was played, aggregated across Instagram and Facebook (organic only, Reels only).
Average watch time per view, for Reels (organic only).
Total cumulative watch time across all views, for Reels (organic only).
Clicks on a link included in this post (e.g. a Story link sticker), organic only.
Total navigation actions taken while viewing this post — the sum of exits, taps forward, taps back, and advances to the next story (organic only, story posts).
Replies sent in response to this post (e.g. Story replies), organic only.
Instances of a viewer exiting out of this post entirely (e.g. leaving a Story), organic only.
Taps to advance past this post (e.g. tapping forward through a Story), organic only.
Taps to go back and re-view this post (e.g. tapping back through a Story), organic only.
Hashtags extracted from this post’s caption.
Accounts mentioned in this post — see PostMention fields above.
object
The @handle of the mentioned account.
How the mention occurred — TAG, CAPTION, STORY, COLLAB, or PAID_PARTNERSHIP.
Whether the mentioned username has been resolved to a known account in our system.
ISO 8601 timestamp of when this post’s current snapshot was produced — how fresh this document is.
AI-generated (Gemini multimodal) enrichment preview — opt-in via ?include= (see the include query parameter), one key per requested field. Coverage and shape may change without notice.
object
AI-generated (Gemini multimodal) narration of the video/audio content.
AI-generated (Gemini multimodal) transcript of spoken audio.
AI-detected on-screen text overlays, in detection order.
AI-detected spoken/on-screen languages, as free-text labels.
AI-generated free-text aesthetic/style tags.
AI-judged brand-safety risk per GARM category — a judged VERDICT, not raw enrichment. null if not yet judged, or if the judged shape no longer matches the current GARM taxonomy.
object
AI-detected commercial signals — featured products/brands, calls to action, promo codes, and a 1-5 promotional-intent score.
object
AI-judged primary emotion and tone.
object
AI-judged production quality and technique signals.
object
Opaque AI-generated vibe classification — shape is not fixed; treat as untyped JSON.
Opaque AI-generated subject classification — shape is not fixed; treat as untyped JSON.
AI-judged overall comment sentiment label.
AI-judged overall comment sentiment score.
AI-generated free-text summary of comment sentiment.
AI-generated free-text rationale for the sentiment judgment.
AI-generated free-text comment themes.
AI-judged comment sentiment split into positive/neutral/negative buckets, each a count and percentage of comments analyzed.
object
object
object
object
Total comments considered in the sentiment judgment.
Comments judged relevant to the sentiment analysis — a subset of the total.
A submitted identifier we don’t hold yet — this batch read started (or joined) discovery for it. Re-submit it after Retry-After.
object
The identifier exactly as submitted.
ISO 8601 instant — every fetching entry in one response shares the same instant, and the response’s Retry-After header (present iff this bucket is non-empty) is its delta-seconds twin.
A submitted identifier that resolved to ‘not obtainable’. Check reason (and retryable) — most values mean stop retrying.
object
The identifier exactly as submitted.
Machine-readable, open vocabulary (additions are non-breaking). outside-recent-media-window and author-unresolved occur on posts only. internal-error means the failure was on our side — retryable is true.
Present, and always true, when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Examples
{ "data": { "network": "instagram", "externalId": "media-def456", "url": "https://www.instagram.com/p/DEF456/", "postedAt": "2026-08-01T00:00:00.000Z", "text": "a conformance caption", "mediaKind": "image", "likeCount": 12, "commentCount": 1, "viewCount": 110, "shareCount": 3, "saveCount": 2, "author": { "accountId": "ig-def456", "username": "somehandle", "followersCount": 1000, "verified": true, "country": "US" }, "instagram": {}, "updatedAt": "2026-08-01T00:00:00.000Z" }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
Present iff fetching is non-empty — delta-seconds until those entries are worth re-submitting (every fetching entry in one response shares the same instant).
We don’t hold this entity yet — THIS request just started (or joined) the work to get it. Wait Retry-After seconds and re-read the same URL: the read is the poll, there is no job resource. A read here is not free of side effects — reading an entity we don’t hold triggers discovery, and reading a stale one triggers a refresh. (url form only — the ids form expresses in-flight discovery as the fetching bucket inside a 200.)
Returned with HTTP 202: the entity isn’t held yet and THIS request just started (or joined) the work to get it. Always exactly one entry (the identifier just submitted) — an array for shape-parity with the batch envelope’s fetching bucket, not because a single read can return more than one. Wait Retry-After seconds, then re-read the same URL — the read is the poll; there is no job resource.
object
A submitted identifier we don’t hold yet — this batch read started (or joined) discovery for it. Re-submit it after Retry-After.
object
The identifier exactly as submitted.
ISO 8601 instant — every fetching entry in one response shares the same instant, and the response’s Retry-After header (present iff this bucket is non-empty) is its delta-seconds twin.
Examplegenerated
{ "fetching": [ { "id": "example", "retryAfter": "example" } ]}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
Delta-seconds (RFC 9110 §10.2.3), always ≥ 1. The server controls the backoff — polling faster than this burns rate limit and gets the data no sooner.
A malformed request — e.g. a batch outside the 1–100 identifier cap, an unrecognized include value, url and ids supplied together, or an unparseable JSON body.
The one JSON shape every error response (any status other than 200/202) carries.
object
The one JSON shape every error response (any status other than 200/202) carries, wrapped under error in apiErrorResponseSchema.
object
The stable, machine-readable error code. Maps 1:1 to the HTTP status.
Human prose for logs and error screens. Never parse it.
Optional structured extras. Today’s one use: a read-miss 404’s reason (and retryable, when our fault) — see details.reason.
object
Machine-readable, open vocabulary — same values a batch unavailable entry’s own reason carries.
Present (and true) only when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Example
{ "error": { "code": "invalid-input", "message": "ids must contain between 1 and 100 identifiers, got 101" }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
Missing, malformed, expired, or revoked credential.
The one JSON shape every error response (any status other than 200/202) carries.
object
The one JSON shape every error response (any status other than 200/202) carries, wrapped under error in apiErrorResponseSchema.
object
The stable, machine-readable error code. Maps 1:1 to the HTTP status.
Human prose for logs and error screens. Never parse it.
Optional structured extras. Today’s one use: a read-miss 404’s reason (and retryable, when our fault) — see details.reason.
object
Machine-readable, open vocabulary — same values a batch unavailable entry’s own reason carries.
Present (and true) only when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Example
{ "error": { "code": "unauthorized", "message": "invalid credential" }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
Valid credential, but it lacks the <resource>:<action> permission this operation requires (stated in the operation description).
The one JSON shape every error response (any status other than 200/202) carries.
object
The one JSON shape every error response (any status other than 200/202) carries, wrapped under error in apiErrorResponseSchema.
object
The stable, machine-readable error code. Maps 1:1 to the HTTP status.
Human prose for logs and error screens. Never parse it.
Optional structured extras. Today’s one use: a read-miss 404’s reason (and retryable, when our fault) — see details.reason.
object
Machine-readable, open vocabulary — same values a batch unavailable entry’s own reason carries.
Present (and true) only when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Example
{ "error": { "code": "forbidden", "message": "token lacks creators:read permission" }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
A read-miss (branch on details.reason — retry only if details.retryable is true, never on message prose), an unknown asProfile (deliberately indistinguishable from a nonexistent one, so slugs are not enumerable), or an unsupported network. details.reason is an open vocabulary (additions are non-breaking). Values today: account-not-discoverable (creators — terminal; a personal account and a nonexistent handle are indistinguishable), not-supported-on-network (the network isn’t supported yet — terminal until it ships), outside-recent-media-window (posts — terminal), author-unresolved (posts), unparseable-identifier, and internal-error with details.retryable: true (our fault — retry after a few minutes).
The one JSON shape every error response (any status other than 200/202) carries.
object
The one JSON shape every error response (any status other than 200/202) carries, wrapped under error in apiErrorResponseSchema.
object
The stable, machine-readable error code. Maps 1:1 to the HTTP status.
Human prose for logs and error screens. Never parse it.
Optional structured extras. Today’s one use: a read-miss 404’s reason (and retryable, when our fault) — see details.reason.
object
Machine-readable, open vocabulary — same values a batch unavailable entry’s own reason carries.
Present (and true) only when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Example
{ "error": { "code": "not-found", "message": "no creator found for instagram/somehandle", "details": { "reason": "account-not-discoverable" } }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
Over the per-principal request budget (fixed one-minute window; default 60 requests/minute, raisable per Service Account). Rejected requests still count against the window. Honour Retry-After.
The one JSON shape every error response (any status other than 200/202) carries.
object
The one JSON shape every error response (any status other than 200/202) carries, wrapped under error in apiErrorResponseSchema.
object
The stable, machine-readable error code. Maps 1:1 to the HTTP status.
Human prose for logs and error screens. Never parse it.
Optional structured extras. Today’s one use: a read-miss 404’s reason (and retryable, when our fault) — see details.reason.
object
Machine-readable, open vocabulary — same values a batch unavailable entry’s own reason carries.
Present (and true) only when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Example
{ "error": { "code": "rate-limited", "message": "rate limit exceeded (60 requests/minute for this principal)" }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
Delta-seconds (RFC 9110 §10.2.3), always ≥ 1. The server controls the backoff — polling faster than this burns rate limit and gets the data no sooner.
Our fault. The message is deliberately generic — internal error detail is never exposed. Safe to retry with backoff.
The one JSON shape every error response (any status other than 200/202) carries.
object
The one JSON shape every error response (any status other than 200/202) carries, wrapped under error in apiErrorResponseSchema.
object
The stable, machine-readable error code. Maps 1:1 to the HTTP status.
Human prose for logs and error screens. Never parse it.
Optional structured extras. Today’s one use: a read-miss 404’s reason (and retryable, when our fault) — see details.reason.
object
Machine-readable, open vocabulary — same values a batch unavailable entry’s own reason carries.
Present (and true) only when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Example
{ "error": { "code": "internal-error", "message": "the request could not be completed" }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.
A dependency needed to verify the credential is unreachable — the credential was neither accepted nor rejected. Retry with backoff.
The one JSON shape every error response (any status other than 200/202) carries.
object
The one JSON shape every error response (any status other than 200/202) carries, wrapped under error in apiErrorResponseSchema.
object
The stable, machine-readable error code. Maps 1:1 to the HTTP status.
Human prose for logs and error screens. Never parse it.
Optional structured extras. Today’s one use: a read-miss 404’s reason (and retryable, when our fault) — see details.reason.
object
Machine-readable, open vocabulary — same values a batch unavailable entry’s own reason carries.
Present (and true) only when the failure was on our side rather than a fact about the entity — retry after a few minutes. Absent means terminal: stop retrying.
Example
{ "error": { "code": "unavailable", "message": "temporarily unavailable" }}Headers
Section titled “Headers”On every response, success or failure. Quote it when contacting support — it’s the fastest way for Aspire to find exactly your request.