Skip to content

API

What is the AppsFolio API

The AppsFolio API provides programmatic access to your application portfolio data. It enables integrations with external tools and AI coding agents, allowing you to query, export, create, update, and delete apps and metadata outside the AppsFolio web interface.

The API uses API Key authentication via request headers, and all data access respects tenant isolation — you can only access data belonging to your organization.

Interactive API Documentation

Full interactive API documentation is available at:

https://yourorg.appsfol.io/app/api/docs

This Swagger UI lets you explore all endpoints, view request/response schemas, and try out API calls directly in your browser. Use the Authorize button in Swagger to enter your API key headers before making requests.

Base URL

All API endpoints use the following base URL, where yourorg is your organization's tenant ID:

https://yourorg.appsfol.io/app/api

For example, to call the schema endpoint: GET https://yourorg.appsfol.io/app/api/apps/schema

Authentication

The API supports two authentication methods: User API Keys for individual access, and Organization API Keys for shared or automated access.

Personal API Keys

Authenticate with your personal email and API key:

Header Description
X-User-Id Your email address
X-API-Key Your personal API key

Where to find your personal API key

  1. Click on your profile picture in the top navigation
  2. Select Profile from the dropdown menu
  3. Your API key is displayed in the API Key section, along with the required headers
  4. Click Show to reveal the key, then use the copy button to copy it to your clipboard

Warning

Your API key is a secret. Do not share it or commit it to source control. If you believe your key has been compromised, click the regenerate button on your profile page to create a new one.

Organization API Keys

Organization API keys provide access at the organization level, without being tied to a specific user. They are ideal for CI/CD pipelines, automated integrations, and shared tooling.

Header Description
X-Org-Id Your organization's tenant ID
X-API-Key An organization API key

Organization API keys have full read and write access to all apps in the organization. They bypass individual user permission checks.

Organization admins can create and manage org API keys from the Organization Settings page under the API Keys section. The X-Org-Id header value (your tenant ID) is also displayed on that page.

Where to find organization API keys

  1. Go to Organization Settings from the sidebar
  2. Scroll to the API Keys section
  3. Your Tenant ID is displayed at the top of the settings page — use this as the X-Org-Id header value
  4. Click Create API Key and enter a descriptive name (e.g., "CI/CD Pipeline", "External Integration")
  5. Copy the generated key immediately — it will only be shown once

Warning

Organization API keys are shown only once when created or rotated. Store them securely. If you lose a key, rotate it to generate a new one.

From the API Keys table you can:

  • Rotate — generate a new key value (the old key stops working immediately)
  • Deactivate / Activate — temporarily disable a key without deleting it
  • Delete — permanently remove a key

Rate limiting

The API is rate limited to 100 requests per minute per user or organization key. If you exceed this limit, requests will return a 429 Too Many Requests response.

Read Endpoints

Get Application Schema

Returns a JSONSchema document describing the expected shape of application payloads for your organization. The schema reflects your tenant's configured content types (definitions) and their validation rules.

GET /app/api/apps/schema

Response: A JSONSchema object.

curl -H "X-User-Id: you@company.com" -H "X-API-Key: your-api-key" \
  "https://yourorg.appsfol.io/app/api/apps/schema"

Use this endpoint to understand what metadata fields are available and what values they accept before creating or updating apps. The schema includes validation constraints such as allowed choices, required fields, and value formats.

Tip

The schema is cached for performance and automatically invalidated when your organization's content type definitions change.

Export Portfolio as Markdown

Returns your entire application portfolio as a Markdown document optimized for AI agents and LLMs. This is the recommended way to provide your portfolio data to AI coding assistants.

GET /app/api/apps/export/markdown

Response: Plain text Markdown document (Content-Type: text/markdown).

curl -H "X-User-Id: you@company.com" -H "X-API-Key: your-api-key" \
  "https://yourorg.appsfol.io/app/api/apps/export/markdown"

Filtering

You can filter the export using query parameters:

Parameter Description Example
app Comma-separated app shortnames ?app=salesforce,slack
section Comma-separated section names ?section=Security,Compliance
# Export only specific apps
curl -H "X-User-Id: you@company.com" -H "X-API-Key: your-api-key" \
  "https://yourorg.appsfol.io/app/api/apps/export/markdown?app=salesforce,jira"

# Export only specific sections
curl -H "X-User-Id: you@company.com" -H "X-API-Key: your-api-key" \
  "https://yourorg.appsfol.io/app/api/apps/export/markdown?section=Compliance"

# Combine both filters
curl -H "X-User-Id: you@company.com" -H "X-API-Key: your-api-key" \
  "https://yourorg.appsfol.io/app/api/apps/export/markdown?app=salesforce&section=Compliance"

Output format

The Markdown export is structured for easy LLM consumption:

  • H1 — Portfolio title with tenant name
  • H2 — One heading per application (with shortname)
  • H3 — One heading per section
  • H4 — One heading per metadata field
  • App-level details (summary, owner, editors, dates) appear as bullet points under each app heading
  • Empty metadata entries are omitted to reduce noise
  • Horizontal rules separate applications for clear boundaries

All metadata types are rendered in a readable format — choices appear as bulleted lists, contacts as key-value pairs, links as Markdown links, notes with HTML stripped to plain text, and so on.

Write Endpoints

Write endpoints allow you to create, update, and delete applications and their metadata via the API.

Permissions

Operation User API Key Organization API Key
Create Requires app manager role Full access
Update Must be owner, editor, or tenant admin of the app Full access
Delete Must be owner or tenant admin Full access

Create Application

Creates a new application in your organization.

POST /app/api/apps

Request body:

{
  "app": {
    "name": "Salesforce",
    "shortname": "salesforce",
    "summary": "CRM platform",
    "description": "Our primary CRM for sales and customer management"
  },
  "metadata": [
    {
      "definition": {"shortname": "vendor_contact"},
      "payload": {
        "name": "Salesforce Support",
        "email": "support@salesforce.com"
      }
    },
    {
      "definition": {"shortname": "app_category"},
      "payload": {
        "selections": ["CRM", "Sales"]
      }
    }
  ]
}
Field Required Description
app.name Yes Application display name
app.shortname Yes Unique identifier (alphanumerics, underscores, dashes only)
app.summary No Short summary (max 80 characters)
app.description No Detailed description
metadata No List of metadata entries (same shape as GET response)

Response: 201 Created with the app and its metadata.

curl -X POST \
  -H "X-Org-Id: your-tenant-id" -H "X-API-Key: your-org-key" \
  -H "Content-Type: application/json" \
  -d '{"app": {"name": "Salesforce", "shortname": "salesforce"}}' \
  "https://yourorg.appsfol.io/app/api/apps"

Update Application (Full)

Updates an application's fields and upserts provided metadata entries. Metadata entries not included in the request are left unchanged.

PUT /app/api/apps/{app_id}

Request body:

{
  "app": {
    "name": "Salesforce CRM",
    "summary": "Updated CRM platform"
  },
  "metadata": [
    {
      "definition": {"shortname": "vendor_contact"},
      "payload": {
        "name": "Salesforce Enterprise Support",
        "email": "enterprise@salesforce.com"
      }
    }
  ]
}

Response: 200 OK with the updated app and all its metadata.

Update Application (Partial)

Updates only the provided fields. Use metadata to upsert specific entries and remove_metadata to soft-delete entries by definition shortname.

PATCH /app/api/apps/{app_id}

Request body:

{
  "app": {
    "summary": "Updated summary only"
  },
  "metadata": [
    {
      "definition": {"shortname": "app_category"},
      "payload": {
        "selections": ["CRM"]
      }
    }
  ],
  "remove_metadata": ["deprecated_field"]
}
Field Description
app.name Update the app name
app.summary Update the summary
app.description Update the description
metadata List of metadata entries to upsert (same shape as GET response)
remove_metadata List of definition shortnames to remove

Response: 200 OK with the updated app and all its metadata.

Delete Application

Soft-deletes an application and all its associated metadata.

DELETE /app/api/apps/{app_id}

Response: 200 OK with a confirmation message.

curl -X DELETE \
  -H "X-Org-Id: your-tenant-id" -H "X-API-Key: your-org-key" \
  "https://yourorg.appsfol.io/app/api/apps/APP_UUID_HERE"

Working with metadata

The metadata field in create and update requests is a list of entries matching the same shape returned by GET /app/api/apps/{app_id}. Each entry has a definition object (with at least a shortname) and a payload object. This makes the API roundtrip-friendly — you can GET an app, modify values, and PUT/POST it back.

Use the schema endpoint to discover available definitions and their expected payload formats.

Example: If your organization has a "vendor_contact" definition of type contact, the metadata entry would look like:

{
  "metadata": [
    {
      "definition": {"shortname": "vendor_contact"},
      "payload": {
        "name": "Jane Smith",
        "email": "jane@vendor.com",
        "phone": "+1-555-0100"
      }
    }
  ]
}

Extra fields in the definition object (like id, name, metadata_type) are accepted but ignored — this allows you to pass the full definition object from a GET response without stripping fields.

Payloads are validated against the definition's type. Invalid payloads return a 422 response with per-field error details.

Error Handling

The API returns standard HTTP status codes with JSON error bodies.

Status Meaning
400 Bad request (malformed input)
401 Authentication failed or insufficient permissions
404 Resource not found
409 Conflict (e.g., duplicate shortname)
422 Validation failed (with detailed error messages)
429 Rate limit exceeded

Validation errors

When a write request fails validation, the response includes detailed error information:

{
  "error": "Validation failed",
  "details": [
    {"field": "app", "message": "Shortname must contain only alphanumerics, underscores, and dashes"}
  ],
  "metadata_errors": {
    "vendor_contact": ["email: Not a valid email address"]
  }
}
  • details — app-level validation errors
  • metadata_errors — per-definition errors, keyed by definition shortname

Using the API with AI Agents

The Markdown export endpoint is designed specifically for feeding portfolio data to AI coding agents like Claude, ChatGPT, Copilot, or similar tools.

Example: Providing context to an AI agent

Save the export to a file and reference it in your AI agent's context:

# Download your portfolio as Markdown
curl -H "X-User-Id: you@company.com" -H "X-API-Key: your-api-key" \
  "https://yourorg.appsfol.io/app/api/apps/export/markdown" \
  -o portfolio.md

# Use the file as context for an AI agent
# (varies by tool — check your AI agent's documentation)

Example: Asking questions about your portfolio

Once an AI agent has your portfolio Markdown, you can ask questions like:

  • "Who owns Salesforce?"
  • "What apps are in the Finance category?"
  • "Which applications have contracts expiring this year?"
  • "List all apps with their vendor contact information"

Why Markdown instead of JSON?

The JSON API endpoints (/app/api/apps) are ideal for programmatic integrations. The Markdown export is optimized for a different use case — providing context to large language models:

  • Structured headings make it easy for LLMs to locate specific apps and sections
  • Plain text is more token-efficient than nested JSON
  • Human-readable formatting means LLMs can reason about the data naturally
  • Filtering lets you provide only relevant context, staying within token limits