---
updatedAt: 2026-08-24T09:14:57.000Z
agentTools:
  projectIndex: https://developers.vibe.co/llms.txt
---

# Create and start an audience sync from an uploaded CSV

Provide the file_id returned by the upload URL endpoint. audience-ingester creates the sync and streams the CSV into internal batches. Reuse idempotency_key to safely retry this request.
**Scopes:**
`audiences:write`
<br>*Rate limits*:<br>Burst: `1/s`<br>Steady: `20/m`


# OpenAPI definition

```json
{
  "openapi": "3.1.0",
  "paths": {
    "/audiences/{audience_id}/syncs/upload": {
      "post": {
        "description": "Provide the file_id returned by the upload URL endpoint. audience-ingester creates the sync and streams the CSV into internal batches. Reuse idempotency_key to safely retry this request.\n**Scopes:**\n`audiences:write`\n<br>*Rate limits*:<br>Burst: `1/s`<br>Steady: `20/m`\n",
        "operationId": "uploadAudienceSync",
        "parameters": [
          {
            "name": "audience_id",
            "required": true,
            "in": "path",
            "description": "Stable identifier of the audience",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AudienceSyncFromFileCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created audience sync",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudienceSync"
                }
              }
            }
          },
          "400": {
            "description": "Bad request error response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "missingApiKey": {
                    "summary": "Missing API key",
                    "value": {
                      "error": {
                        "type": "validation",
                        "message": "Missing API Key",
                        "status": 400,
                        "detail": null,
                        "request_id": "req_8f3a4b2c",
                        "doc_url": null
                      }
                    }
                  },
                  "validationError": {
                    "summary": "Validation error",
                    "value": {
                      "error": {
                        "type": "validation",
                        "message": "Validation error",
                        "status": 400,
                        "detail": {
                          "validation": [
                            "id must be a string"
                          ]
                        },
                        "request_id": "req_8f3a4b2c",
                        "doc_url": null
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized error response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalidApiKey": {
                    "summary": "Invalid API key",
                    "value": {
                      "error": {
                        "type": "invalid_token",
                        "message": "Unauthorized",
                        "status": 401,
                        "detail": null,
                        "request_id": "req_8f3a4b2c",
                        "doc_url": "https://developers.vibe.co/errors/invalid-token"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Insufficient scope error response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "insufficientScope": {
                    "summary": "Missing required scope",
                    "value": {
                      "error": {
                        "type": "insufficient_scope",
                        "message": "Missing required scope",
                        "status": 403,
                        "detail": {
                          "required": "audiences:write",
                          "granted": [
                            "test"
                          ]
                        },
                        "request_id": "req_8f3a4b2c",
                        "doc_url": "https://developers.vibe.co/reference/oauth2token"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Create and start an audience sync from an uploaded CSV",
        "tags": [
          "Audiences"
        ],
        "x-rate-limit": {
          "rps": 1,
          "rpm": 20
        },
        "x-scopes": [
          "audiences:write"
        ]
      }
    }
  },
  "info": {
    "title": "Vibe Public API",
    "description": "Vibe Public API revision 2026-06-01",
    "version": "2026-06-01",
    "contact": {}
  },
  "tags": [
    {
      "name": "Audiences",
      "description": "An Audience is a list of user identifiers Vibe can target or exclude. You populate an audience by opening a **sync**, uploading one or more **batches** of identifiers, then marking the final batch with `last_batch_flag: true`.\n\nConcurrency: only one non-terminal sync may exist per audience at a time. Syncs expire after 24 hours of inactivity.\n\n> ⚠️ **Gotcha — silent zero-match failures**\n>\n> If your identifiers are hashed with the wrong algorithm or normalization, the sync will succeed and the audience will show as Active, but it will match zero CTV profiles. There is no error signal. See the [HEM format specification](https://developers.vibe.co/docs/hem-format) for the exact requirements."
    }
  ],
  "servers": [
    {
      "url": "https://api.vibe.co",
      "description": "Production API"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http"
      }
    },
    "schemas": {
      "ErrorDetail": {
        "type": "object",
        "properties": {
          "required": {
            "type": "string",
            "example": "audiences:write"
          },
          "granted": {
            "example": [
              "audiences:read",
              "reporting:read"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "required",
          "granted"
        ]
      },
      "ApiError": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "insufficient_scope",
              "invalid_token",
              "validation",
              "internal_error"
            ]
          },
          "message": {
            "type": "string"
          },
          "status": {
            "type": "number",
            "example": 403
          },
          "detail": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/ErrorDetail"
              }
            ]
          },
          "request_id": {
            "type": "string",
            "example": "req_8f3a4b2c"
          },
          "doc_url": {
            "type": "string",
            "example": "https://developers.vibe.co/reference/oauth2token",
            "nullable": true
          }
        },
        "required": [
          "type",
          "message",
          "status",
          "request_id"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ApiError"
          }
        },
        "required": [
          "error"
        ]
      },
      "SyncFailureReason": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code"
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation"
          },
          "details": {
            "type": "object",
            "nullable": true,
            "description": "Additional context specific to the failure code"
          }
        },
        "required": [
          "code",
          "message"
        ]
      },
      "AudienceSync": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable identifier of the sync operation"
          },
          "audience_id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable identifier of the audience"
          },
          "state": {
            "type": "string",
            "description": "Current sync state",
            "enum": [
              "BUILDING",
              "UPDATING",
              "READY",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ]
          },
          "matched_count": {
            "type": "number",
            "nullable": true,
            "minimum": 0,
            "description": "Matched audience member count. Populated once the sync reaches a terminal state."
          },
          "audience_size": {
            "type": "number",
            "nullable": true,
            "minimum": 0,
            "description": "Targetable audience size after eligibility filtering. Populated once the sync reaches a terminal state."
          },
          "failure_reason": {
            "nullable": true,
            "description": "Machine-readable failure reason when the sync reaches FAILED.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SyncFailureReason"
              }
            ]
          },
          "expires_at": {
            "type": "object",
            "nullable": true,
            "description": "ISO 8601 timestamp after which an inactive sync transitions to EXPIRED.",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "audience_id",
          "state"
        ]
      },
      "AudienceSyncFromFileCreate": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "description": "Identifier returned by the audience CSV upload URL endpoint"
          },
          "idempotency_key": {
            "type": "string",
            "description": "Idempotency key for safe file-sync retries"
          }
        },
        "required": [
          "file_id",
          "idempotency_key"
        ]
      }
    }
  },
  "security": [
    {
      "bearer": []
    }
  ]
}
```