Filtering & Sorting

Introduction

You can narrow the posts you get back by type and by publish date, and choose their order. This page covers every filter and sort option for the REST endpoint GET /api/v1/me and the GraphQL me query.

The examples use curl. Pass -g so curl doesn't treat the square brackets as a pattern.

Free and Premium

Filters and sorting work the same way on both plans, but they apply to different sets of posts:

  • Premium keys filter and sort every post Feedframer has stored for the account, and can page through the results. See Pagination.
  • Free keys only ever see the account's 6 most recent posts. Filters and sorting apply within those 6. filter[type]=VIDEO returns the videos among the latest 6, which may be none. sort=published_at returns the same 6 posts, oldest first. A date range that ends before the sixth-newest post returns nothing.

Filter by post type

Value Returns
IMAGE Single-image posts
VIDEO Video posts, including reels
CAROUSEL_ALBUM Posts with several images or videos
REELS The same posts as VIDEO

Instagram reports reels as VIDEO and doesn't give Feedframer a separate type for them, so REELS is accepted as another name for VIDEO. The posts come back with mediaType: "VIDEO". Since Instagram turned video posts into reels in 2022, almost every VIDEO post is a reel.

REST: filter[type]. Case doesn't matter, so image works too.

# Images only
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=IMAGE'

# Videos and reels (these two return the same posts)
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=VIDEO'
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=REELS'

# Carousels only
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=CAROUSEL_ALBUM'

GraphQL: the type argument. Use upper case: GraphQL rejects "video".

query {
  me(type: "VIDEO") {
    posts {
      id
      type
      thumbnailUrl
      permalink
    }
  }
}

In GraphQL the post's type is the type field. In REST it is mediaType.

For video posts, show thumbnailUrl in an <img>. mediaUrl is usually an .mp4 file.

Filter by date

REST parameter GraphQL argument Keeps posts published
filter[publishedAfter] publishedAfter at or after this time
filter[publishedBefore] publishedBefore at or before this time

Rules:

  • Both bounds are inclusive. A post published at exactly the time you give is included.
  • Use ISO 8601. A date (2026-03-25) or a date and time (2026-03-25T15:10:06Z, 2026-03-25T16:10:06+01:00).
  • Offsets are honoured. 2026-03-25T16:10:06+01:00 means 15:10:06 UTC. A time with no offset is read as UTC.
  • A plain date on publishedAfter means 00:00:00 UTC on that day.
  • A plain date on publishedBefore covers the whole day, up to 23:59:59 UTC. So publishedBefore=2026-03-31 includes posts from 31 March.
  • Encode + as %2B in REST query strings. An unencoded + turns into a space, and the request fails with a 422. Z needs no encoding. In GraphQL you send dates inside the JSON body, so no encoding is needed.

Post times in responses are UTC (timestamp in REST, publishedAt in GraphQL).

REST:

# Posts published in March 2026 (1 March 00:00 UTC to 31 March 23:59:59 UTC)
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[publishedAfter]=2026-03-01&filter[publishedBefore]=2026-03-31'

# Posts published on or after 1 January 2026
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[publishedAfter]=2026-01-01'

# Posts published before 9am UK summer time on 25 March 2026 (note the %2B)
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[publishedBefore]=2026-03-25T09:00:00%2B01:00'

GraphQL:

query {
  me(publishedAfter: "2026-03-01", publishedBefore: "2026-03-31") {
    posts {
      id
      caption
      publishedAt
    }
  }
}

If publishedAfter is later than publishedBefore, you get an empty posts array, not an error.

Combining filters

Filters combine with AND: a post must match all of them.

REST:

# Image posts from March 2026
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=IMAGE&filter[publishedAfter]=2026-03-01&filter[publishedBefore]=2026-03-31'

GraphQL:

query {
  me(type: "IMAGE", publishedAfter: "2026-03-01", publishedBefore: "2026-03-31") {
    posts {
      id
      mediaUrl
      publishedAt
    }
  }
}

There is no filter by account. Each API key belongs to one Instagram account, so the key already decides which account's posts you get.

Sorting

The default order is newest first.

REST: the sort parameter

Value Order
-published_at Newest first. This is the default.
published_at Oldest first
-publishedAt Same as -published_at
publishedAt Same as published_at
-id Most recently stored by Feedframer first
id First stored by Feedframer first

A leading - means descending. id is the order Feedframer stored the posts, not Instagram's post id. It usually matches publish order, but not always. There is no sorting by likes or comments.

# Oldest first
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&sort=published_at'

# Most recently stored first
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&sort=-id'

Any other value returns a 422 (see Errors below).

GraphQL: the orderBy argument

orderBy takes a list of { column, order } clauses:

  • column: published_at (or publishedAt), or id
  • order: ASC or DESC

Only the first clause is used.

# Oldest first
query {
  me(orderBy: [{ column: "published_at", order: ASC }]) {
    posts {
      id
      publishedAt
    }
  }
}
# Most recently stored first
query {
  me(orderBy: [{ column: "id", order: DESC }]) {
    posts {
      id
      publishedAt
    }
  }
}

Practical examples

The latest 3 posts

page[size] sets how many posts come back. This works on both plans.

curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&page[size]=3'
query {
  me(first: 3) {
    posts {
      id
      caption
      publishedAt
    }
  }
}

A video grid

curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=VIDEO'
const apiKey = 'YOUR_API_KEY';
const url = new URL('https://feedframer.com/api/v1/me');
url.searchParams.set('api_key', apiKey);
url.searchParams.set('filter[type]', 'VIDEO');

const response = await fetch(url);
const body = await response.json();

if (!response.ok) {
  throw new Error(`${body.errors[0].code}: ${body.errors[0].detail}`);
}

const html = body.posts
  .map((post) => `<a href="${post.permalink}"><img src="${post.thumbnailUrl}" alt="" loading="lazy"></a>`)
  .join('');

On Free this returns only the videos among the 6 most recent posts, so the grid may be short or empty.

Images from a date range, oldest first

curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=IMAGE&filter[publishedAfter]=2026-01-01&filter[publishedBefore]=2026-03-31&sort=published_at'
query {
  me(
    type: "IMAGE"
    publishedAfter: "2026-01-01"
    publishedBefore: "2026-03-31"
    orderBy: [{ column: "published_at", order: ASC }]
  ) {
    posts {
      id
      mediaUrl
      publishedAt
    }
    pagination {
      nextCursor
      hasMore
    }
  }
}

On Premium, if hasMore is true, fetch the rest with the cursor, keeping the same filters and sort. See Pagination.

Filtering with variables in GraphQL

Pass filters as variables rather than building the query string yourself:

const apiKey = 'YOUR_API_KEY';

const query = `
  query Posts($type: String, $after: DateTimeTz) {
    me(type: $type, publishedAfter: $after) {
      posts { id type publishedAt permalink }
    }
  }
`;

const response = await fetch(`https://feedframer.com/graphql?api_key=${apiKey}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query, variables: { type: 'IMAGE', after: '2026-01-01' } }),
});
const body = await response.json();

if (!response.ok) {
  // 401: bad or missing API key, in the REST error format
  throw new Error(body.errors[0].code);
}
if (body.errors) {
  // GraphQL errors, e.g. an invalid type or date
  throw new Error(body.errors[0].message);
}

console.log(body.data.me.posts);

Errors

REST

An invalid filter or sort value returns HTTP 422 with one entry per bad parameter:

curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=STORY&filter[publishedAfter]=not-a-date&sort=likes'
{
  "errors": [
    {
      "status": "422",
      "code": "VALIDATION_ERROR",
      "title": "Invalid Parameter",
      "detail": "The selected filter[type] is invalid.",
      "source": { "parameter": "filter[type]" }
    },
    {
      "status": "422",
      "code": "VALIDATION_ERROR",
      "title": "Invalid Parameter",
      "detail": "The filter[publishedAfter] field must be a valid date.",
      "source": { "parameter": "filter[publishedAfter]" }
    },
    {
      "status": "422",
      "code": "VALIDATION_ERROR",
      "title": "Invalid Parameter",
      "detail": "The sort value must be one of: -published_at, published_at, -publishedAt, publishedAt, -id, id.",
      "source": { "parameter": "sort" }
    }
  ]
}

GraphQL

GraphQL returns HTTP 200 with an errors array. For a bad type or orderBy, data.me is null. For a bad date, the response has no data at all.

  • An invalid type gives the message Validation failed for the field [me]. with the detail in extensions.validation.type: ["The selected type is invalid."].
  • An invalid date gives a message like "not-a-date" is not a valid date. Use ISO 8601, e.g. 2024-01-31 or 2024-01-31T09:00:00Z.
  • An unknown orderBy column gives Cannot order by "likes". Use published_at or id.

See Error Handling.

Next steps