add-on $30/mo gem "avo-api"

API

Expose your Avo resources as a JSON API for integrations, mobile apps, and headless front-ends.

What it does

avo-api

An AI agent, a partner integration, a mobile client, a headless front-end: each one needs the same thing before it can do anything useful, a way to read and write your data without handing over the keys to everything. You get that on day one. Run the install generator and every Avo resource becomes a documented REST API over plain JSON, with a full set of endpoints, GET, POST, PATCH, PUT, and DELETE under /api/resources/v1/<resource>. Each endpoint reuses your existing resource definition, so the fields, the pagination, and the sorting all match the admin you already built. No serializers to write, no routes to wire up.

What makes it safe to point an LLM tool or an outside client at your database is that the API answers to the rules you already wrote. Your Pundit policies run on every request, so a caller can only read and change what its user is allowed to, and field visibility follows the same :index, :show, :new, and :edit rules your resources declare. Authentication is yours to set: a generated setup_authentication hook lets you check an API key, HTTP Basic credentials, or whatever your app already uses, and anything that fails comes back as a clean 401. Every client goes through the same authorization layer as the UI, so what a role cannot see in Avo it cannot read through the API either.

It also works with the Avo CLI, so you, your scripts, and your coding agents can query and update records from the terminal without writing a single HTTP request.

What it looks like

Add the gem and run one generator. It creates a controller per resource, inheriting a BaseResourcesController you own:

# Gemfile
gem "avo-api", source: "https://packager.dev/avo-hq/"

$ bundle install
$ rails generate avo_api:install

The API exposes exactly the fields your resource already shows, per view. hide_on and only_on carry straight over, so an internal note stays out of the index payload:

class Avo::Resources::Team < Avo::BaseResource
  def fields
    field :id, as: :id
    field :name, as: :text
    field :url, as: :text
    field :internal_notes, as: :text, hide_on: :index
    field :logo, as: :external_image, only_on: :show
  end
end

Authorization is your existing Pundit policy, enforced on every request, the same one guarding your admin. Authentication is a hook you fill in, here a shared API key:

class Avo::Api::Resources::V1::UsersController < BaseResourcesController
  def setup_authentication
    expected = ENV.fetch("API_KEY")
    provided = request.headers["Authorization"]&.sub(/^ApiKey /, "")

    unless ActiveSupport::SecurityUtils.secure_compare(provided.to_s, expected)
      raise Avo::Api::AuthenticationError
    end
  end
end

From the caller's side it is plain JSON over the verbs you expect:

$ curl -X POST http://localhost:3000/api/resources/v1/teams \
    -H "Authorization: ApiKey $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "team": { "name": "Platform", "url": "https://platform.dev" } }'

# 201 Created
# { "record": { "id": 3, "name": "Platform", "url": "https://platform.dev" } }

Work with your data from the terminal

Once the API is running, you and your agents can read and change records from any terminal with the Avo CLI, the API's command-line client, free with this add-on. It talks to your app over HTTP, so nothing extra gets installed in the app, and every call goes through the same policies as the UI. Install it once and log in with an API token:

$ gem install avo-cli
$ avo login --host https://admin.example.com/api --token avo_xxxx

# List your resources, then inspect one's fields
$ avo schema
$ avo schema users

List, read, create, update, and delete records with one command each. Results print as a readable table by default:

$ avo list users --sort name --dir desc --fields id,name,email --per-page 10
$ avo create users --data '{"name": "Ada Lovelace", "email": "ada@example.com"}'
$ avo update users 5 --data '{"name": "Ada King"}'
$ avo delete users 5

Add --format json to script it. Exit codes tell a refused request (1) apart from a malformed command (2), so a CI job or an agent knows what went wrong:

$ avo get users 5 --format json | jq .record.email
"ada@example.com"

# Or read the connection from the environment in CI
$ AVO_API_HOST=https://admin.example.com/api AVO_API_TOKEN=$TOKEN avo list orders

What you get

  • Automatic REST endpoints for every Avo resource, with index, show, create, update, and destroy
  • Field visibility that mirrors your resource views, so the API exposes exactly what :index and :show already show
  • Your Pundit policies enforced on every request, the same authorization that guards your Avo admin
  • A generated setup_authentication hook for an API key, HTTP Basic, or your own scheme, with failures returned as 401
  • A BaseResourcesController in your app that you can override per resource when you need to
  • JSON request and response shapes that match your records, with validation errors returned as 422s
  • A command-line client, avo-cli, to list, read, create, update, and delete records from any terminal, as tables or JSON

Why it pays off

  • Give an AI agent, a partner, or a new client a documented API to your whole admin in an afternoon, instead of writing serializers and routes resource by resource.
  • One authorization layer, every surface: the policy that scopes records, hides attributes, and gates actions in the UI does the same for every API caller, so there is no second permission model to write.
  • Your data never leaves your Rails app. The API runs inside your codebase, so there is no third-party service sitting between an integration and your database.
  • Every Avo release makes it better: the endpoints, serialization, and field handling stay aligned with your resource definitions and keep working through upgrades, and fixes ship to every app at once.
  • Your agent writes the authentication hook; the endpoints, serialization, and access control come with the foundation. No per-seat pricing as the clients calling it grow.

Questions

How do API clients authenticate?

By default with API tokens you create in your Avo app, sent as a bearer token in the Authorization header over HTTPS. Tokens can expire and be revoked, and each one acts as the user who owns it. For HTTP Basic, your own tokens or a shared key, override the setup_authentication hook.

Do my Pundit policies apply to API requests?

Yes, through the Authorization add-on. Index results go through the resource's policy scope, a record outside it returns 404, and a denied policy method returns 403. Without the Authorization add-on configured, API queries aren't scoped, so set it up before you hand out tokens.

Is there an OpenAPI spec?

Yes. GET /api/resources/v1/_openapi returns an OpenAPI 3.1 document built on each request from your resources and the caller's token, so every client sees only what it can reach. Point a client generator or an LLM tool at it.

ready to ship?

You ship it this afternoon. We keep it solid for years.