ReferenceAvo Public APIImport Tracking Plan

Import Tracking Plan

Import tracking plan using Avo API

The Import API allows you to import a tracking plan from a CSV file or JSON Schema payload into a specific branch in your Avo workspace.

Endpoint

https://api.avo.app/workspaces/:workspaceId/branches/:branchId/import/v1

:workspaceId is the ID of your workspace. You’ll find it in the URL of your avo tab after /schemas/. :branchId is the ID of the branch you want to import into. If you open a branch in Avo you can find it in the URL after /branches/. For the main branch simply use main. Note that the branch id is not the same as the branch name.

Important Restrictions:

  • You cannot import directly to the main branch if the “Protected main branch” setting is enabled in your workspace
  • You cannot import to a branch that is closed or merged

Authentication

This endpoint requires an authorization header containing a Base64 encoded service account name and secret.

Rate Limit

We currently soft-enforce 1/req/s rate limit per service account for this endpoint. Please reach out to us if you have a use case in mind that requires a higher rate limit.

Parameters

- workspaceId

Locate your workspaceId in the URL avo.app/schemas/:workspaceId

- branchId

Locate your branchId by switching onto the branch and checking the URL

  • avo.app/schemas/:workspaceId/branches/:branchId
  • For the main branch, use main as the ID (if “Protected main branch” is disabled)

- importMethod (optional)

Controls how the import interacts with existing items in your tracking plan. Pass as a query parameter.

ValueDescription
addOnly (default)Only performs additive changes. Existing items are never overwritten or removed, but new properties and metadata (sources, tags, etc.) can be appended to existing events.
addAndUpdateAdds new items and updates existing items to match the imported data. Does not remove any items.
addUpdateAndRemoveAdds new items, updates existing items, and removes properties from events when they are absent from the imported file. Removals are event-scoped only — events not included in the import are left untouched, and properties are unlinked from events (not permanently deleted from the tracking plan).

- Base64 encoding secret header

The base64 encoded token expects name:secret

See more on authorization

Request Body

The Content-Type header determines the import format:

  • Content-Type: text/csv — CSV import
  • Content-Type: application/json — JSON Schema import
  • Any other value returns 400 with "Invalid Content-Type. Accepted: text/csv, application/json"

CSV Format

The request body should be the CSV content as a string.

Your CSV content following the format described in the [importing documentation](/publishing/import/importing)

JSON Schema Format

The request body should be a JSON object. Two JSON formats are supported and auto-detected based on top-level keys.

Standard JSON Schema

Standard JSON Schema format where each event is a schema object with properties. This is the recommended format for importing from external tracking plan tools.

{
  "schema": {
    "events": {
      "Event Name": {
        "type": "object",
        "description": "Event description",
        "properties": {
          "propertyName": {
            "type": "string",
            "description": "Property description",
            "enum": ["value1", "value2"]
          }
        },
        "required": ["propertyName"]
      }
    }
  }
}

Detection: Presence of schema.events as an object (keys = event names).

Note: Avo-specific fields (tags, sources, stakeholder domains, etc.) are not supported in this format. Events are imported with empty defaults for those fields.

Avo JSON Schema Export

The format produced by Avo’s JSON Schema export. Events are in an array with Avo-specific metadata, making this format ideal for re-importing previously exported tracking plans.

{
  "name": "Exported Tracking Plan: branch-name",
  "events": [
    {
      "id": "evt-id",
      "name": "Event Name",
      "description": "Event description",
      "eventType": "event",
      "tags": ["tag1", "tag2"],
      "categories": ["goal-id-1"],
      "sources": [
        {
          "id": "src-id",
          "name": "Source Name",
          "implementWithCodegen": true,
          "destinations": []
        }
      ],
      "stakeholderDomains": [
        { "id": "dom-id", "name": "Domain Name", "isOwner": true }
      ],
      "rules": {
        "nameMapping": [
          { "name": "mapped_name", "destinationId": "dest-id" }
        ],
        "properties": {
          "properties": {
            "type": "object",
            "properties": {
              "myProp": {
                "id": "prop-id",
                "type": "string",
                "description": "Property description",
                "isSystemProperty": false,
                "nameMapping": [
                  { "name": "mapped_name", "destinationId": "dest-id" }
                ],
                "tags": ["tag1"]
              }
            },
            "required": ["myProp"]
          },
          "userProperties": {
            "type": "object",
            "properties": {}
          }
        }
      }
    }
  ]
}

Detection: Presence of events as an array.

Priority: If both schema and events keys exist, the Standard JSON Schema format takes precedence.

Event-Level Fields (Avo JSON Schema Export only)

FieldTypeImported AsNotes
namestringEvent nameRequired; events with empty names are skipped
descriptionstringEvent description
eventTypestringEvents with type "variant" are skipped with a warning
tagsstring[]Event tags
sources{ name: string }[]Source namesOnly the name field is extracted
stakeholderDomains{ name: string, isOwner: bool }[]Domain names + ownerThe domain with isOwner: true becomes the event owner
categoriesstring[]Not importedExport contains goal IDs, not names — left empty to avoid phantom categories
rules.nameMapping{ name, destinationId }[]Event name mapping
rules.properties.propertiesobjectEvent propertiesStandard JSON Schema format
rules.properties.userPropertiesobjectUser propertiesMerged with event properties; sendAs overridden to UserProperty
rules.properties.groupPropertiesobjectNot importedWarning generated

Type Mapping

JSON Schema TypeAvo TypeNotes
"string"string
"integer"int
"number"floatBecomes int if "multipleOf": 1 is present
"boolean"bool
"object"object
"array"list of <items.type>Element type from items.type; defaults to any
"null"any
unknownanyWarning generated
["string", "null"]stringNullable types: the non-null type is extracted
["type1", "type2"]anyMultiple non-null types collapse to any

Supported Property Features

FeatureJSON Schema FieldNotes
DescriptiondescriptionString
Required / Optionalrequired array on parentDetermines presence (AlwaysSent vs SometimesSent)
Enum / Matchesenum arrayNumeric and boolean values are coerced to strings with a warning. For array properties, also checks items.enum
Pinned ValueconstSupports string, int, float, and boolean literals
Regex PatternpatternRegex validation string
Send Asx-avo-sendAs"EventProperty", "UserProperty", or "SystemProperty"
System Property (fallback)isSystemPropertyBoolean; used when x-avo-sendAs is absent
Name MappingnameMappingArray of { "name": "...", "destinationId": "..." }
Property IDidPreserved from Avo exports for re-import deduplication

Composition Keywords

Both formats support the following JSON Schema composition keywords:

KeywordBehavior
allOfAll branches merged; top-level properties included as base schema
oneOfAll branches merged with warning: “results may be imprecise”
anyOfSame as oneOf

Note: Duplicate properties across branches are resolved with last-definition-wins semantics and a warning is generated.

Unsupported Features

The following features are skipped with warnings:

  • patternProperties, if/then/else, not at event level
  • oneOf / anyOf at property level — defaults to type any
  • groupProperties in Avo export

The following will cause a parse error:

  • Unresolved $ref — only inline schemas are supported

Import Methods

Add Only (default)

Events:

  • New events are created (matched by name)
  • Existing events receive new properties that aren’t already on the event
  • Existing event fields are NOT overwritten (e.g. description and owner remain unchanged)
  • New sources, tags, stakeholder domains, and name mappings are added to existing events

Properties:

  • New properties are created
  • Existing properties are NOT modified (type, description, matches, presence, regex remain unchanged)

Only additive operations are performed. Nothing already in the tracking plan is changed.

Add and Update

Everything from Add Only, plus:

Events:

  • Event description is updated if the import provides a different non-empty value
  • Owner is updated if the import specifies a different owner domain

Properties are updated when the import value differs from the existing value:

FieldUpdate Condition
DescriptionNon-empty and different
TypeImport type is not any and differs from existing
List flagDiffers from existing
Enum values (matches)Import has values not present in existing
Presence (required/optional)Import required/optional status differs. Exception: Properties with Mixed presence are skipped to avoid false positives (Mixed has per-event/per-source granularity that import formats can’t represent)
Regex patternEvent-specific regex differs
Pinned value (const)Import pinned value differs

How presence works:

  • In required array in JSON Schema → AlwaysSent (required)
  • Not in required array → SometimesSent (optional)
  • If all events agree on the same presence → a single global update is applied
  • If events disagree (mixed) → per-event presence actions are generated

Response

Success (200)

On success, the API returns a JSON object with the import results:

{
  "message": "Import completed",
  "warnings": [
    "Event variant 'Login - Mobile' was skipped. Variants are not supported in import.",
    "Property 'metadata': 'oneOf' is not supported; defaulting to type 'any'."
  ],
  "result": {
    "newEvents": 5,
    "updatedEvents": 2,
    "newProperties": 12,
    "updatedProperties": 3,
    "newSources": 1,
    "newStakeholderDomains": 0
  }
}

Response Fields

  • message: A success message indicating the import completed
  • result: An object containing statistics about the import:
    • newEvents: Number of new events created
    • updatedEvents: Number of existing events that were updated
    • newProperties: Number of new properties created
    • updatedProperties: Number of existing properties that were updated
    • newSources: Number of new sources created
    • newStakeholderDomains: Number of new stakeholder domains created
  • warnings: An array of warning strings about skipped or unsupported schema features. Present in both success and error responses.

Error Responses

StatusScenario
400Invalid Content-Type, unparsable body, invalid JSON Schema structure
401Authentication failure
403Protected main branch
404Branch not found
409Branch merged/closed, or no prior actions on branch
500Unexpected error

All error responses include a warnings array for consistent shape:

{
  "message": "Error description",
  "warnings": []
}

Warnings

Warnings are non-fatal issues collected during parsing. They are included in both success and error responses. Examples:

  • "Unsupported JSON Schema type: 'foo'. Defaulting to 'any'."
  • "Numeric enum value 42 coerced to string"
  • "Boolean enum value 'true' coerced to string"
  • "Property 'x': 'oneOf' is not supported; defaulting to type 'any'."
  • "Event variant 'Login - Mobile' was skipped. Variants are not supported in import."
  • "Duplicate property 'userId': last definition wins."
  • "Event 'Checkout': 'groupProperties' is not supported in import and will be skipped."
  • "Invalid sendAs value FooBar; defaulting to EventProperty"

Example Usage

CSV Import

Request

# Add only (default)
$ curl -H "Authorization: Basic <Base64 encoded token>" \
       -H "Content-Type: text/csv" \
       -X POST https://api.avo.app/workspaces/:workspaceId/branches/main/import/v1 \
       -d 'KPI,Event Category,Event Name,Event Description,Event Property Name,Property Description,Property Value Type,Is Property Required?,Is Property Array?,Property Enumeration Options,Platforms,Status,Code Snippet\n,,Imported Event I,Event sent when a user clicks the import button. ,,,,,,,\"iOS, Android, Web\",,'
 
# Add, update, and remove
$ curl -H "Authorization: Basic <Base64 encoded token>" \
       -H "Content-Type: text/csv" \
       -X POST "https://api.avo.app/workspaces/:workspaceId/branches/main/import/v1?importMethod=addUpdateAndRemove" \
       -d 'your CSV content'

Response

{
  "message": "Import completed",
  "result": {
    "newEvents": 1,
    "updatedEvents": 0,
    "newProperties": 0,
    "updatedProperties": 0,
    "newSources": 0,
    "newStakeholderDomains": 0
  },
  "warnings": []
}

JSON Schema Import

Request

$ curl -X POST \
  "https://api.avo.app/workspaces/:workspaceId/branches/my-branch/import/v1?importMethod=addAndUpdate" \
  -H "Authorization: Basic <Base64 encoded token>" \
  -H "Content-Type: application/json" \
  -d '{
    "schema": {
      "events": {
        "Button Clicked": {
          "type": "object",
          "description": "User clicked a button",
          "properties": {
            "button_name": {
              "type": "string",
              "description": "Name of the button",
              "enum": ["signup", "login", "checkout"]
            },
            "screen": {
              "type": "string"
            }
          },
          "required": ["button_name"]
        }
      }
    }
  }'

Response

{
  "message": "Import completed",
  "result": {
    "newEvents": 1,
    "updatedEvents": 0,
    "newProperties": 2,
    "updatedProperties": 0,
    "newSources": 0,
    "newStakeholderDomains": 0
  },
  "warnings": []
}