# Managing Elevated Instagram Feed with Your AI Agent (agent documentation)

> Machine-readable documentation for AI agents. Human version: https://elevatedextensions.com/documentation/instagram-feed/managing-with-ai-agent/

This is the complete machine-readable reference for the 27 `elevated-instagram-feed/*` abilities in Elevated Instagram Feed. Every schema below is served verbatim from the ability registry (the same schemas the MCP server and the REST surface enforce), and every example is a real captured response.

## Calling conventions

Two equivalent surfaces, one registry:

- **MCP**: connect to `/wp-json/mcp/mcp-adapter-default-server` (MCP Streamable HTTP). Each ability is exposed as an MCP tool with the same name. Pass the input object as the tool arguments.
- **REST**: `/wp-json/wp-abilities/v1/abilities/{ability-name}/run`, authenticated as an administrator (use an application password). The HTTP method is enforced from the ability's annotations:

| Annotations | Method | Where the input goes |
|---|---|---|
| `readonly: true` | GET | `input` query parameter, PHP bracket syntax: `?input[query]=test&input[limit]=5` |
| `destructive: true` and `idempotent: true` | DELETE | `input` query parameter |
| everything else | POST | JSON body: `{"input": { ... }}` |

Each ability section below states its resolved method.

`GET /wp-json/wp-abilities/v1/abilities` lists every ability with its full input and output schema; `GET /wp-json/wp-abilities/v1/abilities/{ability-name}` returns one.

Wrong method:

```json
{
 "status": 405,
 "data": {
  "code": "rest_ability_invalid_method",
  "message": "Read-only abilities require GET method.",
  "data": {
   "status": 405
  }
 }
}
```

The other two rejection messages, from the same rule: `"Abilities that perform destructive actions require DELETE method."` and `"Abilities that perform updates require POST method."`

Unauthenticated:

```json
{
 "status": 401,
 "data": {
  "code": "rest_ability_cannot_execute",
  "message": "Sorry, you are not allowed to execute this ability.",
  "data": {
   "status": 401
  }
 }
}
```

Input is validated against the schema before any handler runs. Unknown keys are rejected, not ignored, and every rejection names the valid values (see the error catalog at the end).

**Agent access switch.** The site owner can turn agent access off (Elevated Instagram Feed settings, stored as option `elevated_instagram_feed_agent_access` = `"no"`). While off, the abilities are not registered and every call fails with:

```json
{
 "status": 404,
 "error": {
  "code": "rest_ability_not_found",
  "message": "Ability not found."
 }
}
```

Only a human can switch access back on; do not retry, ask the site owner.

**Connecting Instagram accounts is human-only.** No ability accepts Instagram credentials or completes OAuth. `prepare-account-connection` opens a single-use connection window that expires after 600 seconds and returns the authorization URL for a human to open; `cancel-account-connection` closes it. Everything else operates on accounts a human has already connected.

## The feed settings object

One settings object backs `create-feed` and `update-feed` (their `settings` schemas are identical). Patches merge into the stored feed: maps merge recursively, lists replace wholesale, and an explicit `null` is a value, not an omission; the schema decides which keys are maps and which are lists. Server-managed fields (`id`, `updatedAt`, `account`, `account_id` on the saved feed) and derived fields (`template.icon`, `layoutSettings.type`, `styleSettings.theme`) are not part of this writable schema.

The schema (served by the registry):

```json
{
 "type": "object",
 "properties": {
  "title": {
   "type": "string",
   "maxLength": 200
  },
  "account_id": {
   "type": "string",
   "maxLength": 191
  },
  "template": {
   "type": "object",
   "properties": {
    "id": {
     "type": "string",
     "enum": [
      "grid-header",
      "grid-clean",
      "grid-slider-header",
      "grid-slider-clean",
      "mosaic-header",
      "mosaic-clean"
     ]
    },
    "name": {
     "type": "string",
     "maxLength": 120
    }
   },
   "additionalProperties": false
  },
  "postStyles": {
   "type": "object",
   "properties": {
    "aspectRatio": {
     "type": "string",
     "enum": [
      "1:1",
      "4:5"
     ]
    },
    "clickAction": {
     "type": "string",
     "enum": [
      "modal",
      "instagram",
      "none"
     ]
    },
    "elements": {
     "type": "object",
     "properties": {
      "likesCount": {
       "type": "boolean"
      },
      "commentsCount": {
       "type": "boolean"
      },
      "text": {
       "type": "boolean"
      },
      "autoplayVideo": {
       "type": "boolean"
      }
     },
     "additionalProperties": false
    },
    "modalElements": {
     "type": "object",
     "properties": {
      "user": {
       "type": "boolean"
      },
      "followButton": {
       "type": "boolean"
      },
      "instagramLink": {
       "type": "boolean"
      },
      "likesCount": {
       "type": "boolean"
      },
      "share": {
       "type": "boolean"
      },
      "text": {
       "type": "boolean"
      },
      "comments": {
       "type": "boolean"
      },
      "date": {
       "type": "boolean"
      }
     },
     "additionalProperties": false
    }
   },
   "additionalProperties": false
  },
  "layoutSettings": {
   "type": "object",
   "properties": {
    "columnsMode": {
     "type": "string",
     "enum": [
      "auto",
      "manual"
     ]
    },
    "columns": {
     "type": "integer",
     "minimum": 1,
     "maximum": 12
    },
    "tabletColumns": {
     "type": "integer",
     "minimum": 1,
     "maximum": 12
    },
    "mobileColumns": {
     "type": "integer",
     "minimum": 1,
     "maximum": 12
    },
    "rows": {
     "type": "integer",
     "minimum": 1,
     "maximum": 20
    },
    "tabletRows": {
     "type": "integer",
     "minimum": 1,
     "maximum": 20
    },
    "mobileRows": {
     "type": "integer",
     "minimum": 1,
     "maximum": 20
    },
    "gap": {
     "type": "integer",
     "minimum": 0,
     "maximum": 200
    },
    "tabletGap": {
     "type": "integer",
     "minimum": 0,
     "maximum": 200
    },
    "mobileGap": {
     "type": "integer",
     "minimum": 0,
     "maximum": 200
    },
    "width": {
     "type": "string",
     "maxLength": 16,
     "description": "Either \"auto\" or a pixel count between 1 and 5000."
    },
    "tabletWidth": {
     "type": "string",
     "maxLength": 16,
     "description": "Either \"auto\" or a pixel count between 1 and 5000."
    },
    "mobileWidth": {
     "type": "string",
     "maxLength": 16,
     "description": "Either \"auto\" or a pixel count between 1 and 5000."
    },
    "showHeader": {
     "type": "boolean"
    },
    "headerElements": {
     "type": "object",
     "properties": {
      "showTitle": {
       "type": "boolean"
      },
      "profilePicture": {
       "type": "boolean"
      },
      "fullName": {
       "type": "boolean"
      },
      "username": {
       "type": "boolean"
      },
      "verifiedBadge": {
       "type": "boolean"
      },
      "postsCount": {
       "type": "boolean"
      },
      "followersCount": {
       "type": "boolean"
      },
      "followingCount": {
       "type": "boolean"
      },
      "followButton": {
       "type": "boolean"
      }
     },
     "additionalProperties": false
    },
    "sliderSettings": {
     "type": "object",
     "properties": {
      "arrowsControl": {
       "type": "boolean"
      },
      "dragControl": {
       "type": "boolean"
      },
      "animationSpeed": {
       "type": "number",
       "minimum": 0,
       "maximum": 10
      },
      "autoplay": {
       "type": "integer",
       "minimum": 0,
       "maximum": 30000
      }
     },
     "additionalProperties": false
    },
    "loadMoreSettings": {
     "type": "object",
     "properties": {
      "enabled": {
       "type": "boolean"
      },
      "buttonText": {
       "type": "string",
       "maxLength": 120
      },
      "loadingText": {
       "type": "string",
       "maxLength": 120
      },
      "postsPerLoad": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "textColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 50
      },
      "hoverBackgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "hoverTextColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showLoader": {
       "type": "boolean"
      },
      "loaderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      }
     },
     "additionalProperties": false
    },
    "headerLabels": {
     "type": "object",
     "properties": {
      "titleText": {
       "type": "string",
       "maxLength": 200
      },
      "postsText": {
       "type": "string",
       "maxLength": 120
      },
      "followersText": {
       "type": "string",
       "maxLength": 120
      },
      "followingText": {
       "type": "string",
       "maxLength": 120
      },
      "followButtonText": {
       "type": "string",
       "maxLength": 120
      }
     },
     "additionalProperties": false
    }
   },
   "additionalProperties": false
  },
  "styleSettings": {
   "type": "object",
   "properties": {
    "feed": {
     "type": "object",
     "properties": {
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "padding": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "margin": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    },
    "header": {
     "type": "object",
     "properties": {
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "textColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "followButtonColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "followButtonTextColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    },
    "post": {
     "type": "object",
     "properties": {
      "hoverCardBackgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "hoverCardTextColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    },
    "arrows": {
     "type": "object",
     "properties": {
      "color": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      }
     },
     "additionalProperties": false
    },
    "modal": {
     "type": "object",
     "properties": {
      "overlayColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "textColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "linksColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "followButtonColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    }
   },
   "additionalProperties": false
  },
  "filterSettings": {
   "type": "object",
   "properties": {
    "maxPosts": {
     "type": "integer",
     "minimum": 0,
     "maximum": 500
    },
    "filters": {
     "type": "array",
     "items": {
      "type": "object",
      "properties": {
       "type": {
        "type": "string",
        "enum": [
         "show",
         "hide"
        ]
       },
       "value": {
        "type": "string",
        "maxLength": 200
       }
      },
      "additionalProperties": false
     },
     "maxItems": 50
    }
   },
   "additionalProperties": false
  }
 },
 "additionalProperties": false
}
```

## The saved feed object

What `get-feed`, `create-feed`, and `update-feed` return under `feed`. It is the settings object plus the server-managed fields.

The schema (served by the registry):

```json
{
 "type": "object",
 "properties": {
  "id": {
   "type": "string",
   "maxLength": 64
  },
  "title": {
   "type": "string",
   "maxLength": 200
  },
  "updatedAt": {
   "type": "string",
   "maxLength": 40
  },
  "account_id": {
   "type": "string",
   "maxLength": 191
  },
  "account": {
   "type": "object",
   "properties": {
    "username": {
     "type": "string",
     "maxLength": 191
    },
    "profilePicture": {
     "type": "string",
     "maxLength": 2048,
     "format": "uri"
    },
    "userId": {
     "type": "string",
     "maxLength": 64
    },
    "mediaCount": {
     "type": "integer",
     "minimum": 0,
     "maximum": 1000000000
    },
    "accountType": {
     "type": "string",
     "maxLength": 64
    },
    "followersCount": {
     "type": "integer",
     "minimum": 0,
     "maximum": 1000000000
    },
    "followingCount": {
     "type": "integer",
     "minimum": 0,
     "maximum": 1000000000
    },
    "accountId": {
     "type": "string",
     "maxLength": 191
    }
   },
   "additionalProperties": false
  },
  "template": {
   "type": "object",
   "properties": {
    "id": {
     "type": "string",
     "enum": [
      "grid-header",
      "grid-clean",
      "grid-slider-header",
      "grid-slider-clean",
      "mosaic-header",
      "mosaic-clean"
     ]
    },
    "name": {
     "type": "string",
     "maxLength": 120
    },
    "icon": {
     "type": [
      "object",
      "string",
      "null"
     ]
    }
   },
   "additionalProperties": false
  },
  "cacheSettings": {
   "type": "object",
   "properties": {
    "cacheTime": {
     "type": "integer",
     "minimum": 60,
     "maximum": 604800
    }
   },
   "additionalProperties": false
  },
  "postStyles": {
   "type": "object",
   "properties": {
    "aspectRatio": {
     "type": "string",
     "enum": [
      "1:1",
      "4:5"
     ]
    },
    "clickAction": {
     "type": "string",
     "enum": [
      "modal",
      "instagram",
      "none"
     ]
    },
    "elements": {
     "type": "object",
     "properties": {
      "likesCount": {
       "type": "boolean"
      },
      "commentsCount": {
       "type": "boolean"
      },
      "text": {
       "type": "boolean"
      },
      "autoplayVideo": {
       "type": "boolean"
      }
     },
     "additionalProperties": false
    },
    "modalElements": {
     "type": "object",
     "properties": {
      "user": {
       "type": "boolean"
      },
      "followButton": {
       "type": "boolean"
      },
      "instagramLink": {
       "type": "boolean"
      },
      "likesCount": {
       "type": "boolean"
      },
      "share": {
       "type": "boolean"
      },
      "text": {
       "type": "boolean"
      },
      "comments": {
       "type": "boolean"
      },
      "date": {
       "type": "boolean"
      }
     },
     "additionalProperties": false
    }
   },
   "additionalProperties": false
  },
  "layoutSettings": {
   "type": "object",
   "properties": {
    "type": {
     "type": "string",
     "enum": [
      "grid",
      "slider"
     ]
    },
    "columnsMode": {
     "type": "string",
     "enum": [
      "auto",
      "manual"
     ]
    },
    "columns": {
     "type": "integer",
     "minimum": 1,
     "maximum": 12
    },
    "tabletColumns": {
     "type": "integer",
     "minimum": 1,
     "maximum": 12
    },
    "mobileColumns": {
     "type": "integer",
     "minimum": 1,
     "maximum": 12
    },
    "rows": {
     "type": "integer",
     "minimum": 1,
     "maximum": 20
    },
    "tabletRows": {
     "type": "integer",
     "minimum": 1,
     "maximum": 20
    },
    "mobileRows": {
     "type": "integer",
     "minimum": 1,
     "maximum": 20
    },
    "gap": {
     "type": "integer",
     "minimum": 0,
     "maximum": 200
    },
    "tabletGap": {
     "type": "integer",
     "minimum": 0,
     "maximum": 200
    },
    "mobileGap": {
     "type": "integer",
     "minimum": 0,
     "maximum": 200
    },
    "width": {
     "type": "string",
     "maxLength": 16,
     "description": "Either \"auto\" or a pixel count between 1 and 5000."
    },
    "tabletWidth": {
     "type": "string",
     "maxLength": 16,
     "description": "Either \"auto\" or a pixel count between 1 and 5000."
    },
    "mobileWidth": {
     "type": "string",
     "maxLength": 16,
     "description": "Either \"auto\" or a pixel count between 1 and 5000."
    },
    "showHeader": {
     "type": "boolean"
    },
    "headerElements": {
     "type": "object",
     "properties": {
      "showTitle": {
       "type": "boolean"
      },
      "profilePicture": {
       "type": "boolean"
      },
      "fullName": {
       "type": "boolean"
      },
      "username": {
       "type": "boolean"
      },
      "verifiedBadge": {
       "type": "boolean"
      },
      "postsCount": {
       "type": "boolean"
      },
      "followersCount": {
       "type": "boolean"
      },
      "followingCount": {
       "type": "boolean"
      },
      "followButton": {
       "type": "boolean"
      }
     },
     "additionalProperties": false
    },
    "sliderSettings": {
     "type": "object",
     "properties": {
      "arrowsControl": {
       "type": "boolean"
      },
      "dragControl": {
       "type": "boolean"
      },
      "animationSpeed": {
       "type": "number",
       "minimum": 0,
       "maximum": 10
      },
      "autoplay": {
       "type": "integer",
       "minimum": 0,
       "maximum": 30000
      }
     },
     "additionalProperties": false
    },
    "loadMoreSettings": {
     "type": "object",
     "properties": {
      "enabled": {
       "type": "boolean"
      },
      "buttonText": {
       "type": "string",
       "maxLength": 120
      },
      "loadingText": {
       "type": "string",
       "maxLength": 120
      },
      "postsPerLoad": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "textColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 50
      },
      "hoverBackgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "hoverTextColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showLoader": {
       "type": "boolean"
      },
      "loaderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      }
     },
     "additionalProperties": false
    },
    "headerLabels": {
     "type": "object",
     "properties": {
      "titleText": {
       "type": "string",
       "maxLength": 200
      },
      "postsText": {
       "type": "string",
       "maxLength": 120
      },
      "followersText": {
       "type": "string",
       "maxLength": 120
      },
      "followingText": {
       "type": "string",
       "maxLength": 120
      },
      "followButtonText": {
       "type": "string",
       "maxLength": 120
      }
     },
     "additionalProperties": false
    }
   },
   "additionalProperties": false
  },
  "styleSettings": {
   "type": "object",
   "properties": {
    "theme": {
     "type": "string",
     "enum": [
      "light",
      "dark"
     ]
    },
    "feed": {
     "type": "object",
     "properties": {
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "padding": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "paddingLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "margin": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "marginLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 500
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    },
    "header": {
     "type": "object",
     "properties": {
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "textColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "followButtonColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "followButtonTextColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    },
    "post": {
     "type": "object",
     "properties": {
      "hoverCardBackgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "hoverCardTextColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    },
    "arrows": {
     "type": "object",
     "properties": {
      "color": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      }
     },
     "additionalProperties": false
    },
    "modal": {
     "type": "object",
     "properties": {
      "overlayColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "backgroundColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "textColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "linksColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "followButtonColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "showBorder": {
       "type": "boolean"
      },
      "borderColor": {
       "type": "string",
       "maxLength": 64,
       "description": "A CSS colour: hex, rgb()/rgba(), hsl()/hsla(), or a colour keyword."
      },
      "borderWidth": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthTop": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthRight": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthBottom": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderWidthLeft": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      },
      "borderRadius": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusTR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBR": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      },
      "borderRadiusBL": {
       "type": "integer",
       "minimum": 0,
       "maximum": 200
      }
     },
     "additionalProperties": false
    }
   },
   "additionalProperties": false
  },
  "filterSettings": {
   "type": "object",
   "properties": {
    "maxPosts": {
     "type": "integer",
     "minimum": 0,
     "maximum": 500
    },
    "filters": {
     "type": "array",
     "items": {
      "type": "object",
      "properties": {
       "type": {
        "type": "string",
        "enum": [
         "show",
         "hide"
        ]
       },
       "value": {
        "type": "string",
        "maxLength": 200
       }
      },
      "additionalProperties": false
     },
     "maxItems": 50
    }
   },
   "additionalProperties": false
  },
  "shortcode": {
   "type": "string",
   "description": "The shortcode that renders this feed."
  }
 },
 "additionalProperties": true
}
```

## Abilities

### `elevated-instagram-feed/get-account-connection-status`

Reports whether an Instagram connection is currently pending, when its window expires, and how many accounts are already connected. Reads local state only. Annotations: readonly, idempotent. REST method: GET.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "connection_pending": {
   "type": "boolean"
  },
  "expires_at": {
   "type": [
    "integer",
    "null"
   ]
  },
  "expires_in": {
   "type": [
    "integer",
    "null"
   ]
  },
  "opened_by_current_user": {
   "type": "boolean"
  },
  "connected_accounts": {
   "type": "integer"
  },
  "active_account_id": {
   "type": [
    "string",
    "null"
   ]
  },
  "accounts_with_unusable_token": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "connection_pending",
  "expires_at",
  "expires_in",
  "opened_by_current_user",
  "connected_accounts",
  "active_account_id",
  "accounts_with_unusable_token"
 ]
}
```

**Example: no window open**

Input:

```json
{}
```

Response:

```json
{
 "connection_pending": false,
 "expires_at": null,
 "expires_in": null,
 "opened_by_current_user": false,
 "connected_accounts": 1,
 "active_account_id": "@elias.soflyy",
 "accounts_with_unusable_token": 0
}
```

**Example: while a connection window is open**

Input:

```json
{}
```

Response:

```json
{
 "connection_pending": true,
 "expires_at": 1788137935,
 "expires_in": 600,
 "opened_by_current_user": true,
 "connected_accounts": 1,
 "active_account_id": "@elias.soflyy",
 "accounts_with_unusable_token": 0
}
```

### `elevated-instagram-feed/prepare-account-connection`

Produces the Instagram authorization URL and arms the short-lived window that lets the eventual callback be accepted, then stops. Hand the URL to the human and wait: they must open it in a browser signed in to this site as the same administrator this request ran as. Never open the URL, sign in, approve consent or call the callback. Contacts nothing outside this site. An already-armed window is reused rather than replaced, and a cooldown prevents repeated arming. Annotations: write, idempotent. REST method: POST.

Returns the authorization URL for a human to open. The window is single use and expires after 600 seconds; no ability can complete the OAuth flow.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "authorization_url": {
   "type": "string"
  },
  "expires_at": {
   "type": [
    "integer",
    "null"
   ]
  },
  "expires_in": {
   "type": [
    "integer",
    "null"
   ]
  },
  "reused_existing_window": {
   "type": "boolean"
  },
  "next_action": {
   "type": "string",
   "enum": [
    "wait_for_human"
   ]
  },
  "instructions": {
   "type": "string"
  }
 },
 "additionalProperties": false,
 "required": [
  "authorization_url",
  "expires_at",
  "expires_in",
  "reused_existing_window",
  "next_action",
  "instructions"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "authorization_url": "https://auth.elevatedextensions.com/wp-json/elex/v1/auth/ig?state=https://elevated-discount-rules-source.instawp.local",
 "expires_at": 1788137935,
 "expires_in": 600,
 "reused_existing_window": false,
 "next_action": "wait_for_human",
 "instructions": "Give this URL to the person who owns the Instagram account and stop. They must open it themselves in a browser that is signed in to this site as the same WordPress administrator this request ran as, approve access on Instagram, and let the redirect return here. Do not open it, do not sign in, do not approve anything, and do not call the callback. If the connection is abandoned, run cancel-account-connection."
}
```

### `elevated-instagram-feed/cancel-account-connection`

Closes a pending connection window so an abandoned authorization can no longer be completed. Idempotent, local only, and strictly a reduction in exposure. It does not shorten the cooldown before another connection can be prepared. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "closed": {
   "type": "boolean"
  },
  "was_open": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "closed",
  "was_open"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "closed": true,
 "was_open": true
}
```

### `elevated-instagram-feed/get-account`

Retrieves one connected account with profile data refreshed from Instagram. NOT a read: it validates the stored token, which can trigger a token refresh and a write, and then fetches the profile from Instagram. Annotations: write, not idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "account_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 191
  }
 },
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "account": {
   "type": "object",
   "properties": {
    "account_id": {
     "type": "string"
    },
    "username": {
     "type": "string"
    },
    "user_id": {
     "type": "string"
    },
    "profile_picture": {
     "type": "string"
    },
    "media_count": {
     "type": "integer"
    },
    "followers_count": {
     "type": "integer"
    },
    "following_count": {
     "type": "integer"
    },
    "account_type": {
     "type": "string"
    },
    "is_active": {
     "type": "boolean"
    }
   },
   "additionalProperties": false,
   "required": [
    "account_id",
    "username",
    "user_id",
    "profile_picture",
    "is_active"
   ]
  }
 },
 "additionalProperties": false,
 "required": [
  "account"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "account": {
  "account_id": "@elias.soflyy",
  "username": "elias.soflyy",
  "user_id": "24081640811536578",
  "profile_picture": "https://instagram.fvlc10-1.fna.fbcdn.net/v/t51.75761-19/511549718_17857224936450675_2473376247818252031_n.jpg?stp=dst-jpg_s206x206_tt6&_nc_cat=109&ccb=7-5&_nc_sid=bf7eb4&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLnd3dy4xMDgwLkMzIn0%3D&_nc_ohc=S6SkuaCNOKoQ7kNvwEg4VvM&_nc_oc=AdrhaTYXPPHRYqP9EGMtwhlFJJlzhKZltHxXM0sadYbYyvfCXuRqob6zsJPM-pS-pMU&_nc_zt=24&_nc_ht=instagram.fvlc10-1.fna&edm=AP4hL3IEAAAA&_nc_gid=5h2YXbTqndpPZuLqFvw_IQ&_nc_tpa=Q5bMBQJ2SwuCQt0Tu0LMwRBEFrxf1EGi6VMOzZBIY18BpS46-zMiX6AJ_3aeN_1M9eCBKB_IKNxTSh1F&oh=00_AQIHzcyrsw8Gyx3TpvLbCtj1te1mpSvEc0O3NZ7swWyqlA&oe=6A9A9EB9",
  "media_count": 22,
  "followers_count": 4,
  "following_count": 0,
  "account_type": "MEDIA_CREATOR",
  "is_active": true
 }
}
```

### `elevated-instagram-feed/list-accounts`

Lists connected accounts with profile data refreshed from Instagram. NOT a read: it makes one Instagram Graph request per connected account and rewrites the stored accounts option with the refreshed profile-picture URLs. Use list-accounts-local unless live data is required. Annotations: write, not idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "accounts": {
   "type": "array",
   "items": {
    "type": "object",
    "properties": {
     "account_id": {
      "type": "string"
     },
     "username": {
      "type": "string"
     },
     "user_id": {
      "type": "string"
     },
     "profile_picture": {
      "type": "string"
     },
     "media_count": {
      "type": "integer"
     },
     "followers_count": {
      "type": "integer"
     },
     "following_count": {
      "type": "integer"
     },
     "account_type": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     }
    },
    "additionalProperties": false,
    "required": [
     "account_id",
     "username",
     "user_id",
     "profile_picture",
     "is_active"
    ]
   }
  },
  "active_account_id": {
   "type": [
    "string",
    "null"
   ]
  },
  "total": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "accounts",
  "active_account_id",
  "total"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "accounts": [
  {
   "account_id": "@elias.soflyy",
   "username": "elias.soflyy",
   "user_id": "24081640811536578",
   "profile_picture": "https://instagram.fvlc10-1.fna.fbcdn.net/v/t51.75761-19/511549718_17857224936450675_2473376247818252031_n.jpg?stp=dst-jpg_s206x206_tt6&_nc_cat=109&ccb=7-5&_nc_sid=bf7eb4&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLnd3dy4xMDgwLkMzIn0%3D&_nc_ohc=S6SkuaCNOKoQ7kNvwEg4VvM&_nc_oc=AdrhaTYXPPHRYqP9EGMtwhlFJJlzhKZltHxXM0sadYbYyvfCXuRqob6zsJPM-pS-pMU&_nc_zt=24&_nc_ht=instagram.fvlc10-1.fna&edm=AP4hL3IEAAAA&_nc_gid=UtckxN-7A6ROj2QuzuWVpA&_nc_tpa=Q5bMBQJb1Xq_-KTeWbyS97wEaBjO43Nqsv23jCDm2VhR_EEQTuT_BgM01Um97Em5WklvfQjgE9qn4pon&oh=00_AQKKq1Fp6phoPBmMwtJ7EKyegQi9Q3T7uvRH9GwGjVGi3w&oe=6A9A9EB9",
   "media_count": 0,
   "followers_count": 0,
   "following_count": 0,
   "account_type": "",
   "is_active": true
  }
 ],
 "active_account_id": "@elias.soflyy",
 "total": 1
}
```

### `elevated-instagram-feed/list-accounts-local`

Lists connected Instagram accounts from local storage, with the state of each stored token. Makes no request to Instagram and writes nothing. Prefer this over list-accounts unless live profile data is genuinely required. Annotations: readonly, idempotent. REST method: GET.

Reads the locally stored accounts without calling Instagram.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "accounts": {
   "type": "array",
   "items": {
    "type": "object",
    "properties": {
     "account_id": {
      "type": "string"
     },
     "username": {
      "type": "string"
     },
     "user_id": {
      "type": "string"
     },
     "profile_picture": {
      "type": "string"
     },
     "token_status": {
      "type": "string",
      "enum": [
       "present",
       "unreadable",
       "plaintext",
       "missing"
      ]
     },
     "token_expires_at": {
      "type": [
       "integer",
       "null"
      ]
     },
     "is_active": {
      "type": "boolean"
     }
    },
    "additionalProperties": false,
    "required": [
     "account_id",
     "username",
     "user_id",
     "profile_picture",
     "token_status",
     "token_expires_at",
     "is_active"
    ]
   }
  },
  "active_account_id": {
   "type": [
    "string",
    "null"
   ]
  },
  "total": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "accounts",
  "active_account_id",
  "total"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "accounts": [
  {
   "account_id": "@elias.soflyy",
   "username": "elias.soflyy",
   "user_id": "24081640811536578",
   "profile_picture": "https://instagram.fvlc10-1.fna.fbcdn.net/v/t51.75761-19/511549718_17857224936450675_2473376247818252031_n.jpg?stp=dst-jpg_s206x206_tt6&_nc_cat=109&ccb=7-5&_nc_sid=bf7eb4&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLnd3dy4xMDgwLkMzIn0%3D&_nc_ohc=X9HFsL_8Ic4Q7kNvwHltobT&_nc_oc=AdpI3m28ohJVrqt2J82t2kePC5j4ezRERYsCPCbqwfFO3ZHRB5Xv10hNp-ZBvXqgWGo&_nc_zt=24&_nc_ht=instagram.fvlc10-1.fna&edm=AP4hL3IEAAAA&_nc_gid=Gbz2_ECFQwPyUNY-M4z7RA&_nc_tpa=Q5bMBQLw7ZKR863FPLNpJFoUr-3uzgcODY1PT5Uzf_rjw9oqwKXRDLx5zS5VXn_Sc4ioRzXWA1Y15_F5&oh=00_AQFf87sG7kCcwQxkk0qXdsGVvT7Ai30ZKwjrP-yMxSXK9A&oe=6A9396B9",
   "token_status": "present",
   "token_expires_at": 1793294583,
   "is_active": true
  }
 ],
 "active_account_id": "@elias.soflyy",
 "total": 1
}
```

### `elevated-instagram-feed/list-account-media`

Fetches recent posts for a connected account directly from Instagram. NOT a read: it validates the stored token first, which can trigger a token refresh and a write. Prefer get-cache-info and the feed abilities for questions that cached data can answer. Annotations: write, not idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "account_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 191
  },
  "limit": {
   "type": "integer",
   "minimum": 1,
   "maximum": 100,
   "default": 25
  }
 },
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "account_id": {
   "type": "string"
  },
  "media": {
   "type": "array",
   "items": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "permalink": {
      "type": "string"
     },
     "media_type": {
      "type": "string"
     },
     "timestamp": {
      "type": "string"
     },
     "caption": {
      "type": "string"
     },
     "likes": {
      "type": "integer"
     },
     "comments": {
      "type": "integer"
     }
    },
    "additionalProperties": false,
    "required": [
     "id",
     "permalink",
     "media_type",
     "timestamp",
     "caption",
     "likes",
     "comments"
    ]
   }
  },
  "total": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "account_id",
  "media",
  "total"
 ]
}
```

**Example: two most recent posts**

Input:

```json
{
 "limit": 2
}
```

Response:

```json
{
 "account_id": "@elias.soflyy",
 "media": [
  {
   "id": "18120630196500143",
   "permalink": "https://www.instagram.com/p/DThlLC_kS1f/",
   "media_type": "CAROUSEL_ALBUM",
   "timestamp": "2026-01-15T08:30:56+0000",
   "caption": "The best canele in Phrom Phong #tastytreats",
   "likes": 0,
   "comments": 0
  },
  {
   "id": "18374482816154716",
   "permalink": "https://www.instagram.com/reel/DRqDyYbAp6B/",
   "media_type": "VIDEO",
   "timestamp": "2025-11-29T22:30:01+0000",
   "caption": "By the lake",
   "likes": 0,
   "comments": 0
  }
 ],
 "total": 2
}
```

### `elevated-instagram-feed/set-active-account`

Marks a connected account as the active one used when a feed does not name an account. Local write. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "account_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 191
  }
 },
 "additionalProperties": false,
 "required": [
  "account_id"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "active_account_id": {
   "type": "string"
  },
  "changed": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "active_account_id",
  "changed"
 ]
}
```

**Example: setting the already-active account reports changed: false**

Input:

```json
{
 "account_id": "@elias.soflyy"
}
```

Response:

```json
{
 "active_account_id": "@elias.soflyy",
 "changed": false
}
```

### `elevated-instagram-feed/disconnect-account`

Permanently removes a connected account and its stored tokens. Requires confirmation. If the removed account was the active one, another remaining account is automatically promoted; the response reports which. Feeds bound to the removed account keep pointing at it and will stop updating. Annotations: write, destructive, idempotent. REST method: DELETE.

Permanently removes the account's stored tokens. Requires `confirm: true`.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "account_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 191
  },
  "confirm": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "account_id",
  "confirm"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "account_id": {
   "type": "string"
  },
  "disconnected": {
   "type": "boolean"
  },
  "active_account_id": {
   "type": [
    "string",
    "null"
   ]
  },
  "active_account_promoted": {
   "type": "boolean"
  },
  "affected_feed_ids": {
   "type": "array",
   "items": {
    "type": "string"
   }
  },
  "remaining_accounts": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "account_id",
  "disconnected",
  "active_account_id",
  "active_account_promoted",
  "affected_feed_ids",
  "remaining_accounts"
 ]
}
```

**Example: without confirm (fails before any side effect)**

Input:

```json
{
 "account_id": "x"
}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/disconnect-account\" has invalid input. Reason: confirm is a required property of input."
 }
}
```

### `elevated-instagram-feed/list-feeds`

Lists every saved Instagram feed with its title, template, account and shortcode. layout_type is the layout family derived from the template: grid, slider or mosaic. Reads local storage only. Annotations: readonly, idempotent. REST method: GET.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "feeds": {
   "type": "array",
   "items": {
    "type": "object",
    "properties": {
     "feed_id": {
      "type": "string"
     },
     "title": {
      "type": [
       "string",
       "null"
      ]
     },
     "template_id": {
      "type": [
       "string",
       "null"
      ]
     },
     "account_id": {
      "type": [
       "string",
       "null"
      ]
     },
     "layout_type": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "slider",
       "mosaic",
       "grid",
       null
      ]
     },
     "max_posts": {
      "type": "integer"
     },
     "updated_at": {
      "type": [
       "string",
       "null"
      ]
     },
     "shortcode": {
      "type": "string"
     }
    },
    "additionalProperties": false,
    "required": [
     "feed_id",
     "title",
     "template_id",
     "account_id",
     "layout_type",
     "max_posts",
     "updated_at",
     "shortcode"
    ]
   }
  },
  "total": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "feeds",
  "total"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "feeds": [
  {
   "feed_id": "9",
   "title": "Feed QA español",
   "template_id": "grid-header",
   "account_id": "@elias.soflyy",
   "layout_type": "grid",
   "max_posts": 6,
   "updated_at": "2026-07-28T22:25:08.361Z",
   "shortcode": "[elevated_instagram_feed id=\"9\"]"
  },
  {
   "feed_id": "10",
   "title": "I18N release feed",
   "template_id": "grid-header",
   "account_id": "@elias.soflyy",
   "layout_type": "grid",
   "max_posts": 0,
   "updated_at": "2026-07-29T00:25:45.915Z",
   "shortcode": "[elevated_instagram_feed id=\"10\"]"
  },
  {
   "feed_id": "11",
   "title": "Browser i18n filtered feed",
   "template_id": "grid-header",
   "account_id": "@elias.soflyy",
   "layout_type": "grid",
   "max_posts": 1,
   "updated_at": "2026-07-29T23:18:07.642Z",
   "shortcode": "[elevated_instagram_feed id=\"11\"]"
  }
 ],
 "total": 3
}
```

### `elevated-instagram-feed/get-feed`

Retrieves one saved feed in full, including its shortcode. Reads local storage only. Annotations: readonly, idempotent. REST method: GET.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 64,
   "pattern": "^[A-Za-z0-9_-]+$"
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id"
 ]
}
```

Output schema: the `feed` value is the saved feed object above.

```json
{
 "type": "object",
 "properties": {
  "feed": "<the saved feed object: see The saved feed object above>"
 },
 "additionalProperties": false,
 "required": [
  "feed"
 ]
}
```

**Example:**

Input:

```json
{
 "feed_id": "9"
}
```

Response:

```json
{
 "feed": {
  "id": "9",
  "account": {
   "username": "elias.soflyy",
   "profilePicture": "https://scontent.cdninstagram.com/v/t51.75761-19/511549718_17857224936450675_2473376247818252031_n.jpg?stp=dst-jpg_s206x206_tt6&_nc_cat=109&ccb=7-5&_nc_sid=bf7eb4&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLnd3dy4xMDgwLkMzIn0%3D&_nc_ohc=VXMwyB7md0YQ7kNvwGOu7eJ&_nc_oc=AdrdwOOdZYAWrRO9MNHcFc2MD0Lk8dO8cecarg8SRjtgK-KUIOxVdm5IsWgFavHoeiU&_nc_zt=24&_nc_ht=scontent.cdninstagram.com&edm=AP4hL3IEAAAA&_nc_gid=YRchLFLVvjeRMK4wq4ahDg&_nc_tpa=Q5bMBQGSoAOoBCBLN_54dF52hQ8_eZvtybbfwHgMRCpGudPdQ15a_FXTXp-yzq4Fqdyx_CO64gPCZXHO&oh=00_AQCabaU7CUVrXonovsoNKoe3fcurbP8jCxpa_SI8yg0zXg&oe=6A6EE4F9",
   "userId": "24081640811536578",
   "mediaCount": 22,
   "accountType": "MEDIA_CREATOR",
   "followersCount": 4,
   "followingCount": 0,
   "accountId": "@elias.soflyy"
  },
  "template": {
   "id": "grid-header",
   "name": "Cuadrícula con encabezado",
   "icon": {
    "type": {
     "displayName": "Grid3x3"
    },
    "key": null,
    "ref": null,
    "props": {
     "className": "w-6 h-6"
    },
    "_owner": null
   }
  },
  "postStyles": {
   "aspectRatio": "1:1",
   "elements": {
    "likesCount": true,
    "commentsCount": true,
    "text": true,
    "autoplayVideo": false
   },
   "clickAction": "modal",
   "modalElements": {
    "user": true,
    "followButton": true,
    "instagramLink": true,
    "likesCount": true,
    "share": true,
    "text": true,
    "comments": true,
    "date": true
   }
  },
  "layoutSettings": {
   "type": "grid",
   "columnsMode": "auto",
   "columns": 4,
   "tabletColumns": 3,
   "mobileColumns": 2,
   "rows": 2,
   "tabletRows": 2,
   "mobileRows": 3,
   "gap": 8,
   "tabletGap": 6,
   "mobileGap": 4,
   "width": "auto",
   "tabletWidth": "auto",
   "mobileWidth": "auto",
   "showHeader": true,
   "headerElements": {
    "showTitle": true,
    "profilePicture": true,
    "fullName": true,
    "username": true,
    "verifiedBadge": true,
    "postsCount": true,
    "followersCount": true,
    "followingCount": true,
    "followButton": true
   },
   "sliderSettings": {
    "arrowsControl": true,
    "dragControl": true,
    "animationSpeed": 0.6,
    "autoplay": 0
   },
   "loadMoreSettings": {
    "enabled": true,
    "buttonText": "Cargar más QA",
    "loadingText": "Cargando QA...",
    "postsPerLoad": 0,
    "backgroundColor": "#0177C2",
    "textColor": "#FFFFFF",
    "borderRadius": 8,
    "hoverBackgroundColor": "#015a94",
    "hoverTextColor": "#FFFFFF",
    "showLoader": true,
    "loaderColor": "#FFFFFF"
   },
   "headerLabels": {
    "titleText": "Publicaciones destacadas QA",
    "postsText": "Entradas QA",
    "followersText": "Seguidores QA",
    "followingText": "Siguiendo QA",
    "followButtonText": "Seguir QA"
   }
  },
  "styleSettings": {
   "theme": "light",
   "header": {
    "backgroundColor": "#FFFFFF",
    "textColor": "#000000",
    "followButtonColor": "#4CB5F9",
    "followButtonTextColor": "#FFFFFF",
    "borderColor": "transparent",
    "borderWidth": 0,
    "borderRadius": 0
   },
   "post": {
    "hoverCardBackgroundColor": "rgba(0, 0, 0, 0.6)",
    "hoverCardTextColor": "#FFFFFF",
    "borderColor": "transparent",
    "borderWidth": 0,
    "borderRadius": 0
   },
   "arrows": {
    "color": "#FFFFFF",
    "backgroundColor": "rgba(0, 0, 0, 0.5)"
   },
   "modal": {
    "overlayColor": "rgba(0, 0, 0, 0.5)",
    "backgroundColor": "#FFFFFF",
    "textColor": "#000000",
    "linksColor": "#4CB5F9",
    "followButtonColor": "#4CB5F9",
    "borderColor": "transparent",
    "borderWidth": 0,
    "borderRadius": 0
   },
   "feed": {
    "backgroundColor": "#FFFFFF",
    "padding": 12,
    "margin": 0,
    "borderColor": "transparent",
    "borderWidth": 0,
    "borderRadius": 0
   }
  },
  "filterSettings": {
   "filters": [],
   "maxPosts": 6
  },
  "title": "Feed QA español",
  "updatedAt": "2026-07-28T22:25:08.361Z",
  "account_id": "@elias.soflyy",
  "shortcode": "[elevated_instagram_feed id=\"9\"]"
 }
}
```

**Example: unknown id**

Input:

```json
{
 "feed_id": "999999"
}
```

Response:

```json
{
 "error": {
  "code": "feed_not_found",
  "message": "No saved feed with the id 999999."
 }
}
```

### `elevated-instagram-feed/create-feed`

Creates a saved feed from the supplied settings and returns the stored result. When media caching is enabled this also schedules a background job that fetches the feed from Instagram. Annotations: write, not idempotent. REST method: POST.

Everything lives inside `settings`; there is no top-level title key. The response returns the saved feed.

Input schema: the `settings` value is the feed settings object above.

```json
{
 "type": "object",
 "properties": {
  "settings": "<the feed settings object: see The feed settings object above>"
 },
 "additionalProperties": false,
 "required": [
  "settings"
 ]
}
```

Output schema: the `feed` value is the saved feed object above.

```json
{
 "type": "object",
 "properties": {
  "feed": "<the saved feed object: see The saved feed object above>"
 },
 "additionalProperties": false,
 "required": [
  "feed"
 ]
}
```

**Example: minimal valid feed (response feed elided)**

Input:

```json
{
 "settings": {
  "title": "Docs example feed",
  "template": {
   "id": "grid-header"
  }
 }
}
```

Response:

```json
{
 "feed": "<the saved feed object, elided>"
}
```

**Example: top-level title is rejected**

Input:

```json
{
 "title": "x",
 "settings": {}
}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/create-feed\" has invalid input. Reason: title is not a valid property of Object."
 }
}
```

**Example: invalid template id (the error names all valid ids)**

Input:

```json
{
 "settings": {
  "template": {
   "id": "not-a-template"
  }
 }
}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/create-feed\" has invalid input. Reason: input[settings][template][id] is not one of grid-header, grid-clean, grid-slider-header, grid-slider-clean, mosaic-header, and mosaic-clean."
 }
}
```

### `elevated-instagram-feed/update-feed`

Applies a partial change to a saved feed. Supplied keys are merged into the stored feed, so anything omitted keeps its current value; filterSettings.filters is a list and replaces wholesale. The merged feed is validated and the stored result is read back and returned. Do not write localized text into headerLabels or loadMoreSettings text: they are English source strings translated at render time, and a localized value overrides translation for every visitor in every language. Annotations: write, idempotent. REST method: POST.

A partial patch: only the keys you send change (merge semantics above). Any other caller omitting keys no longer wipes them; the merged result is validated as a whole.

Input schema: the `settings` value is the feed settings object above.

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 64,
   "pattern": "^[A-Za-z0-9_-]+$"
  },
  "settings": "<the feed settings object: see The feed settings object above>"
 },
 "additionalProperties": false,
 "required": [
  "feed_id",
  "settings"
 ]
}
```

Output schema: the `feed` value is the saved feed object above.

```json
{
 "type": "object",
 "properties": {
  "feed": "<the saved feed object: see The saved feed object above>"
 },
 "additionalProperties": false,
 "required": [
  "feed"
 ]
}
```

**Example: change the column count (response feed elided)**

Input:

```json
{
 "feed_id": "41",
 "settings": {
  "layoutSettings": {
   "columns": 4
  }
 }
}
```

Response:

```json
{
 "feed": "<the saved feed object, elided>"
}
```

### `elevated-instagram-feed/delete-feed`

Permanently removes a saved feed, together with its rows in the feed-posts and cache tables; the response reports how many of each were removed. Requires confirmation. Media downloaded for the feed stays on disk: files are shared between feeds, and cleanup-orphaned-media will not reclaim them either, because it only deletes files no post row claims. Annotations: write, destructive, idempotent. REST method: DELETE.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 64,
   "pattern": "^[A-Za-z0-9_-]+$"
  },
  "confirm": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id",
  "confirm"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string"
  },
  "deleted": {
   "type": "boolean"
  },
  "feed_post_rows_removed": {
   "type": "integer"
  },
  "cache_rows_removed": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id",
  "deleted",
  "feed_post_rows_removed",
  "cache_rows_removed"
 ]
}
```

**Example: without confirm (fails before any side effect)**

Input:

```json
{
 "feed_id": "41"
}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/delete-feed\" has invalid input. Reason: confirm is a required property of input."
 }
}
```

**Example: confirmed**

Input:

```json
{
 "feed_id": "41",
 "confirm": true
}
```

Response:

```json
{
 "feed_id": "41",
 "deleted": true,
 "feed_post_rows_removed": 0,
 "cache_rows_removed": 0
}
```

**Example: get-feed afterwards**

Input:

```json
{
 "feed_id": "41"
}
```

Response:

```json
{
 "error": {
  "code": "feed_not_found",
  "message": "No saved feed with the id 41."
 }
}
```

### `elevated-instagram-feed/get-cache-info`

Reports one feed's cache entries, their ages and sizes, and how many posts are linked to it. site_storage_bytes is the exception: it is the whole site's downloaded images, videos and profile pictures, identical for every feed, because media is shared between feeds. Byte counts only, never filesystem paths. Reads local state only. Annotations: readonly, idempotent. REST method: GET.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 64,
   "pattern": "^[A-Za-z0-9_-]+$"
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string"
  },
  "entries": {
   "type": "array",
   "items": {
    "type": "object",
    "properties": {
     "cache_key": {
      "type": "string"
     },
     "last_updated": {
      "type": [
       "string",
       "null"
      ]
     },
     "age_seconds": {
      "type": [
       "integer",
       "null"
      ]
     },
     "size_bytes": {
      "type": "integer"
     },
     "marked_for_cron_update": {
      "type": "boolean"
     }
    },
    "additionalProperties": false,
    "required": [
     "cache_key",
     "last_updated",
     "age_seconds",
     "size_bytes",
     "marked_for_cron_update"
    ]
   }
  },
  "posts_cache_age_seconds": {
   "type": [
    "integer",
    "null"
   ]
  },
  "linked_posts": {
   "type": "integer"
  },
  "media_caching_enabled": {
   "type": "boolean"
  },
  "site_storage_bytes": {
   "type": "object",
   "properties": {
    "images": {
     "type": "integer"
    },
    "videos": {
     "type": "integer"
    },
    "profile_pictures": {
     "type": "integer"
    },
    "total": {
     "type": "integer"
    }
   },
   "additionalProperties": false,
   "required": [
    "images",
    "videos",
    "profile_pictures",
    "total"
   ]
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id",
  "entries",
  "posts_cache_age_seconds",
  "linked_posts",
  "media_caching_enabled",
  "site_storage_bytes"
 ]
}
```

**Example:**

Input:

```json
{
 "feed_id": "9"
}
```

Response:

```json
{
 "feed_id": "9",
 "entries": [
  {
   "cache_key": "header",
   "last_updated": "2026-08-31 00:04:02",
   "age_seconds": 2692,
   "size_bytes": 319,
   "marked_for_cron_update": true
  },
  {
   "cache_key": "header_backup",
   "last_updated": "2026-08-31 00:04:02",
   "age_seconds": 2692,
   "size_bytes": 319,
   "marked_for_cron_update": true
  },
  {
   "cache_key": "posts",
   "last_updated": "2026-08-31 00:04:02",
   "age_seconds": 2692,
   "size_bytes": 26510,
   "marked_for_cron_update": true
  },
  {
   "cache_key": "posts_backup",
   "last_updated": "2026-08-31 00:04:02",
   "age_seconds": 2692,
   "size_bytes": 26510,
   "marked_for_cron_update": true
  }
 ],
 "posts_cache_age_seconds": 2692,
 "linked_posts": 7,
 "media_caching_enabled": true,
 "site_storage_bytes": {
  "images": 1726644,
  "videos": 12854559,
  "profile_pictures": 3418,
  "total": 14584621
 }
}
```

### `elevated-instagram-feed/clear-feed-cache`

Deletes the cached posts and header for one feed. Requires confirmation. The feed rebuilds its cache on the next request or scheduled update. Downloaded media is left on disk; this is the scoped, safer alternative to clear-cache. Annotations: write, destructive, idempotent. REST method: DELETE.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 64,
   "pattern": "^[A-Za-z0-9_-]+$"
  },
  "confirm": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id",
  "confirm"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string"
  },
  "cleared": {
   "type": "boolean"
  },
  "cache_entries_removed": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id",
  "cleared",
  "cache_entries_removed"
 ]
}
```

**Example: without confirm**

Input:

```json
{
 "feed_id": "41"
}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/clear-feed-cache\" has invalid input. Reason: confirm is a required property of input."
 }
}
```

**Example: confirmed**

Input:

```json
{
 "feed_id": "41",
 "confirm": true
}
```

Response:

```json
{
 "feed_id": "41",
 "cleared": true,
 "cache_entries_removed": 0
}
```

### `elevated-instagram-feed/refresh-feed-cache`

Queues a background refresh of one feed from Instagram and returns immediately. Requires confirmation because the job it schedules consumes the site's Instagram API quota. If a refresh is already running, the running job is reported and no second job is scheduled. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "feed_id": {
   "type": "string",
   "minLength": 1,
   "maxLength": 64,
   "pattern": "^[A-Za-z0-9_-]+$"
  },
  "confirm": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "feed_id",
  "confirm"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "state": {
   "type": "string",
   "enum": [
    "scheduled",
    "already_running",
    "nothing_to_refresh"
   ]
  },
  "feed_ids": {
   "type": "array",
   "items": {
    "type": "string"
   }
  },
  "scheduled_at": {
   "type": [
    "integer",
    "null"
   ]
  },
  "message": {
   "type": "string"
  }
 },
 "additionalProperties": false,
 "required": [
  "state",
  "feed_ids",
  "scheduled_at",
  "message"
 ]
}
```

**Example: without confirm (fails before any side effect)**

Input:

```json
{
 "feed_id": "9"
}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/refresh-feed-cache\" has invalid input. Reason: confirm is a required property of input."
 }
}
```

### `elevated-instagram-feed/refresh-all-feed-caches`

Queues a background refresh of every saved feed from Instagram and returns immediately. Requires confirmation because it consumes the site's Instagram API quota once per feed. If a refresh is already running, the running job is reported and no second job is scheduled. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "confirm": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "confirm"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "state": {
   "type": "string",
   "enum": [
    "scheduled",
    "already_running",
    "nothing_to_refresh"
   ]
  },
  "feed_ids": {
   "type": "array",
   "items": {
    "type": "string"
   }
  },
  "scheduled_at": {
   "type": [
    "integer",
    "null"
   ]
  },
  "message": {
   "type": "string"
  }
 },
 "additionalProperties": false,
 "required": [
  "state",
  "feed_ids",
  "scheduled_at",
  "message"
 ]
}
```

**Example: without confirm (fails before any side effect)**

Input:

```json
{}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/refresh-all-feed-caches\" has invalid input. Reason: confirm is a required property of input."
 }
}
```

### `elevated-instagram-feed/get-cache-refresh-progress`

Reports progress of a running feed refresh. Reads one local transient and makes no outbound request of any kind. Annotations: readonly, idempotent. REST method: GET.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "status": {
   "type": "string",
   "enum": [
    "idle",
    "processing",
    "complete",
    "error"
   ]
  },
  "total_feeds": {
   "type": "integer"
  },
  "feeds_done": {
   "type": "integer"
  },
  "total_posts": {
   "type": "integer"
  },
  "posts_done": {
   "type": "integer"
  },
  "current_feed": {
   "type": [
    "string",
    "null"
   ]
  },
  "message": {
   "type": "string"
  }
 },
 "additionalProperties": false,
 "required": [
  "status",
  "total_feeds",
  "feeds_done",
  "total_posts",
  "posts_done",
  "current_feed",
  "message"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "status": "idle",
 "total_feeds": 0,
 "feeds_done": 0,
 "total_posts": 0,
 "posts_done": 0,
 "current_feed": null,
 "message": ""
}
```

### `elevated-instagram-feed/clear-cache`

Deletes every cache entry for every feed AND every downloaded image, video and profile picture on disk, then marks all posts for re-download. Requires confirmation. Site-wide and not scoped to one feed; prefer clear-feed-cache. Re-downloading the media consumes Instagram bandwidth and quota. Annotations: write, destructive, idempotent. REST method: DELETE.

Clears all cached media across every feed; feeds re-download media on next render. Requires `confirm: true`.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "confirm": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "confirm"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "images_deleted": {
   "type": "integer"
  },
  "videos_deleted": {
   "type": "integer"
  },
  "profile_pictures_deleted": {
   "type": "integer"
  },
  "cache_entries_deleted": {
   "type": "integer"
  }
 },
 "additionalProperties": false,
 "required": [
  "images_deleted",
  "videos_deleted",
  "profile_pictures_deleted",
  "cache_entries_deleted"
 ]
}
```

**Example: without confirm (fails before any side effect)**

Input:

```json
{}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/clear-cache\" has invalid input. Reason: confirm is a required property of input."
 }
}
```

### `elevated-instagram-feed/cleanup-orphaned-media`

Deletes downloaded images and videos whose Instagram post no longer exists locally, and removes feed-post links pointing at missing posts. Requires confirmation. Run with dry_run first to see what would be removed without deleting anything. Annotations: write, destructive, idempotent. REST method: DELETE.

Deletes cached media files no feed references any more and reports exactly what was removed.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "confirm": {
   "type": "boolean"
  },
  "dry_run": {
   "type": "boolean",
   "default": false
  }
 },
 "additionalProperties": false,
 "required": [
  "confirm"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "dry_run": {
   "type": "boolean"
  },
  "images_deleted": {
   "type": "integer"
  },
  "videos_deleted": {
   "type": "integer"
  },
  "bytes_freed": {
   "type": "integer"
  },
  "feed_post_links_removed": {
   "type": "integer"
  },
  "message": {
   "type": "string"
  }
 },
 "additionalProperties": false,
 "required": [
  "dry_run",
  "images_deleted",
  "videos_deleted",
  "bytes_freed",
  "feed_post_links_removed",
  "message"
 ]
}
```

**Example: without confirm**

Input:

```json
{}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/cleanup-orphaned-media\" has invalid input. Reason: confirm is a required property of input."
 }
}
```

**Example: confirmed**

Input:

```json
{
 "confirm": true
}
```

Response:

```json
{
 "dry_run": false,
 "images_deleted": 24,
 "videos_deleted": 1,
 "bytes_freed": 8708195,
 "feed_post_links_removed": 0,
 "message": "Orphaned media and feed-post links were removed."
}
```

### `elevated-instagram-feed/get-feed-update-schedule`

Reports how often feeds refresh in the background, when the next run is due and what the last run did. Reads local state only. Annotations: readonly, idempotent. REST method: GET.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "active": {
   "type": "boolean"
  },
  "interval": {
   "type": [
    "string",
    "null"
   ]
  },
  "interval_seconds": {
   "type": [
    "integer",
    "null"
   ]
  },
  "next_run_at": {
   "type": [
    "integer",
    "null"
   ]
  },
  "last_run": {
   "type": [
    "object",
    "null"
   ],
   "properties": {
    "time_ran": {
     "type": "string"
    },
    "feeds_found": {
     "type": "integer"
    },
    "feeds_updated": {
     "type": "integer"
    },
    "feeds_skipped": {
     "type": "integer"
    },
    "feeds_failed": {
     "type": "integer"
    },
    "execution_time": {
     "type": "number"
    }
   },
   "additionalProperties": true
  },
  "available_intervals": {
   "type": "array",
   "items": {
    "type": "string"
   }
  }
 },
 "additionalProperties": false,
 "required": [
  "active",
  "interval",
  "interval_seconds",
  "next_run_at",
  "last_run",
  "available_intervals"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "active": true,
 "interval": "hourly",
 "interval_seconds": 3600,
 "next_run_at": 1788138074,
 "last_run": {
  "time_ran": "2026-08-31 00:04:02",
  "feeds_found": 6,
  "feeds_updated": 3,
  "feeds_skipped": 3,
  "feeds_failed": 0,
  "execution_time": 2.01
 },
 "available_intervals": [
  "elex_30mins",
  "hourly",
  "twicedaily",
  "elex_12hours",
  "daily"
 ]
}
```

### `elevated-instagram-feed/set-feed-update-schedule`

Changes how often feeds refresh in the background. Reschedules the cron event; it does not run an update. A shorter interval means more frequent Instagram requests. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "interval": {
   "type": "string",
   "enum": [
    "elex_30mins",
    "hourly",
    "twicedaily",
    "elex_12hours",
    "daily"
   ]
  }
 },
 "additionalProperties": false,
 "required": [
  "interval"
 ]
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "active": {
   "type": "boolean"
  },
  "interval": {
   "type": [
    "string",
    "null"
   ]
  },
  "interval_seconds": {
   "type": [
    "integer",
    "null"
   ]
  },
  "next_run_at": {
   "type": [
    "integer",
    "null"
   ]
  },
  "last_run": {
   "type": [
    "object",
    "null"
   ],
   "properties": {
    "time_ran": {
     "type": "string"
    },
    "feeds_found": {
     "type": "integer"
    },
    "feeds_updated": {
     "type": "integer"
    },
    "feeds_skipped": {
     "type": "integer"
    },
    "feeds_failed": {
     "type": "integer"
    },
    "execution_time": {
     "type": "number"
    }
   },
   "additionalProperties": true
  },
  "available_intervals": {
   "type": "array",
   "items": {
    "type": "string"
   }
  }
 },
 "additionalProperties": false,
 "required": [
  "active",
  "interval",
  "interval_seconds",
  "next_run_at",
  "last_run",
  "available_intervals"
 ]
}
```

**Example:**

Input:

```json
{
 "interval": "hourly"
}
```

Response:

```json
{
 "active": true,
 "interval": "hourly",
 "interval_seconds": 3600,
 "next_run_at": 1788140935,
 "last_run": {
  "time_ran": "2026-08-31 00:04:02",
  "feeds_found": 6,
  "feeds_updated": 3,
  "feeds_skipped": 3,
  "feeds_failed": 0,
  "execution_time": 2.01
 },
 "available_intervals": [
  "elex_30mins",
  "hourly",
  "twicedaily",
  "elex_12hours",
  "daily"
 ]
}
```

**Example: invalid interval (the error names all valid values)**

Input:

```json
{
 "interval": "weekly"
}
```

Response:

```json
{
 "error": {
  "code": "ability_invalid_input",
  "message": "Ability \"elevated-instagram-feed/set-feed-update-schedule\" has invalid input. Reason: input[interval] is not one of elex_30mins, hourly, twicedaily, elex_12hours, and daily."
 }
}
```

### `elevated-instagram-feed/get-global-settings`

Retrieves the plugin-wide settings: whether media is cached locally and whether debug logging is on. Annotations: readonly, idempotent. REST method: GET.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "enable_cache": {
   "type": "boolean"
  },
  "enable_debug_logging": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "enable_cache",
  "enable_debug_logging"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "enable_cache": true,
 "enable_debug_logging": false
}
```

### `elevated-instagram-feed/update-global-settings`

Updates the plugin-wide settings. Turning media caching off has a wide effect: local media stops being served, header and profile-picture caching stop, and feeds fall back to Instagram CDN URLs. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": {
  "enable_cache": {
   "type": "boolean"
  },
  "enable_debug_logging": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "enable_cache": {
   "type": "boolean"
  },
  "enable_debug_logging": {
   "type": "boolean"
  }
 },
 "additionalProperties": false,
 "required": [
  "enable_cache",
  "enable_debug_logging"
 ]
}
```

**Example:**

Input:

```json
{
 "enable_cache": true
}
```

Response:

```json
{
 "enable_cache": true,
 "enable_debug_logging": false
}
```

### `elevated-instagram-feed/reregister-feed-translations`

Re-registers every saved feed's editable labels with the active translation plugin, clearing the marker that otherwise makes registration run only once. Use when labels are missing from the translation screen. Does nothing when no translation plugin is active. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "provider": {
   "type": [
    "string",
    "null"
   ],
   "enum": [
    "polylang",
    "wpml",
    null
   ]
  },
  "feeds_registered": {
   "type": "integer"
  },
  "message": {
   "type": "string"
  }
 },
 "additionalProperties": false,
 "required": [
  "provider",
  "feeds_registered",
  "message"
 ]
}
```

**Example: with no translation plugin active**

Input:

```json
{}
```

Response:

```json
{
 "provider": null,
 "feeds_registered": 0,
 "message": "No translation plugin is active, so there is nothing to register with."
}
```

### `elevated-instagram-feed/get-plugin-update-status`

Reports whether a newer plugin version is available. NOT a read: it contacts the Elevated Extensions update server (never Instagram or Meta) and caches the signed answer for twelve hours. Annotations: write, idempotent. REST method: POST.

Input schema:

```json
{
 "type": "object",
 "properties": [],
 "additionalProperties": false,
 "default": {}
}
```

Output schema:

```json
{
 "type": "object",
 "properties": {
  "installed_version": {
   "type": "string"
  },
  "available_version": {
   "type": [
    "string",
    "null"
   ]
  },
  "update_available": {
   "type": "boolean"
  },
  "checked": {
   "type": "boolean"
  },
  "message": {
   "type": "string"
  }
 },
 "additionalProperties": false,
 "required": [
  "installed_version",
  "available_version",
  "update_available",
  "checked",
  "message"
 ]
}
```

**Example:**

Input:

```json
{}
```

Response:

```json
{
 "installed_version": "1.1.0",
 "available_version": "1.1.0",
 "update_available": false,
 "checked": true,
 "message": "The installed version is up to date."
}
```

## Error catalog

Every schema failure is a `WP_Error` with code `ability_invalid_input`; handler-level failures carry their own codes; the REST surface adds HTTP-level rejections. The messages:

- `Ability "elevated-instagram-feed/create-feed" has invalid input. Reason: settings is a required property of input.`
- `Ability "elevated-instagram-feed/create-feed" has invalid input. Reason: nope is not a valid property of Object.`
- `Ability "elevated-instagram-feed/create-feed" has invalid input. Reason: input[settings][template][id] is not one of grid-header, grid-clean, grid-slider-header, grid-slider-clean, mosaic-header, and mosaic-clean.`
- `Ability "elevated-instagram-feed/set-feed-update-schedule" has invalid input. Reason: input[interval] is not one of elex_30mins, hourly, twicedaily, elex_12hours, and daily.`
- `Ability "elevated-instagram-feed/cleanup-orphaned-media" has invalid input. Reason: confirm is a required property of input.`
- `Ability "elevated-instagram-feed/delete-feed" has invalid input. Reason: confirm is a required property of input.`
- `feed_not_found`: `No saved feed with the id 999999.`
- `405` `Read-only abilities require GET method.`, `Abilities that perform updates require POST method.`, `Abilities that perform destructive actions require DELETE method.` (REST method mapping)
- `401` `Sorry, you are not allowed to execute this ability.` (unauthenticated)
- `404` `Ability not found.` (agent access switched off by the site owner)
