openapi: 3.0.0 info: title: Gojiberry AI - External AppExternal Campaigns API description: "\n# Gojiberry AI External API\n\nThis API allows you to programmatically access your Gojiberry AI data and integrate it with your applications.\n\n## Authentication\n\nAll API requests require authentication using a Bearer token. To get your API key:\n\n1. **Log in to your Gojiberry AI account** at [https://app.gojiberry.ai](https://app.gojiberry.ai)\n2. **Navigate to Settings** → **API** section\n3. **Click \"Create API Key\"** to generate a new token\n4. **Copy the API key** when it's displayed (you won't be able to see it again)\n5. **Use the token** in your requests by adding the header: `Authorization: Bearer YOUR_API_KEY`\n\n## Impersonation (organization owners)\n\nIf your API key belongs to the **owner of an organization**, you can perform any API call on behalf of another member of your organization by adding the `x-impersonate-user-id` header with the member's user ID:\n\n```bash\n# Get the contacts of the organization member with user ID 123\ncurl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"x-impersonate-user-id: 123\" \\\n https://ext.gojiberry.ai/v1/contact\n```\n\nWhen impersonating, the request behaves exactly as if it was made by that member: you read and write their data (contacts, campaigns, lists, unibox, etc.).\n\nRules:\n- Your API key must belong to the **organization owner**; other members cannot impersonate.\n- The impersonated user must belong to the **same organization** as the API key user.\n- Requests that don't meet these rules are rejected with a `401 Unauthorized`.\n\nTip: use `GET /v1/organization/members` to list the members of your organization and their user IDs, and `GET /v1/user/me` to verify which user the current request acts as.\n\n## Rate Limits\n\n- **100 requests per minute** per API key\n\n## Base URL\n- **Production**: `https://ext.gojiberry.ai`\n\n## Endpoints\n\n### Contacts\n- `GET /v1/contact` - Get all contacts with filtering and pagination\n- `GET /v1/contact/{id}` - Get a specific contact\n- `GET /v1/contact/health` - Health check endpoint\n\n## Example Usage\n\n```bash\n# Get all contacts\ncurl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n https://ext.gojiberry.ai/v1/contact\n\n# Get contacts with filtering\ncurl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n \"https://ext.gojiberry.ai/v1/contact?search=john&agent=1&dateFrom=2024-01-01\"\n\n# Get a specific contact\ncurl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n https://ext.gojiberry.ai/v1/contact/123\n```\n\n## Webhooks\n\nGojiberry allows you to receive real-time notifications when new contacts are created or updated by configuring a webhook URL.\n\n### How to Configure Webhooks\n\n1. **Log in to your Gojiberry AI account** at [https://app.gojiberry.ai](https://app.gojiberry.ai)\n2. **Navigate to the Integrations page** at [https://app.gojiberry.ai/integrations](https://app.gojiberry.ai/integrations)\n3. **Add a Webhook integration** by clicking the Webhook option\n4. **Enter your webhook URL** where you want to receive notifications\n5. **Save the configuration**\n\nOnce configured, Gojiberry will send POST requests to your webhook URL whenever:\n- A new contact is created\n- A contact is updated\n- Other relevant events occur in your account\n\nThe webhook payload will include the full contact data in JSON format. Each webhook request includes a custom header `x-gojiberry-user-id` containing your user ID for verification purposes.\n\n## Support\n\nFor API support, please contact us at [hello@gojiberry.ai](mailto:hello@gojiberry.ai)\n " version: '1.0' contact: {} servers: [] tags: - name: Campaigns paths: /v1/campaign: get: description: Retrieve all campaigns with optional filtering by active status operationId: CampaignExternalController_findAll parameters: - name: x-impersonate-user-id in: header description: ID of an organization member to act on behalf of. The API key user must be the owner of the organization and the target user must belong to the same organization. required: false schema: type: string - name: activeOnly required: false in: query description: Filter by active status (true/false) schema: type: boolean responses: '200': description: List of campaigns content: application/json: schema: type: array items: $ref: '#/components/schemas/Campaign' security: - bearer: [] summary: Get all campaigns tags: - Campaigns /v1/campaign/{id}: get: operationId: CampaignExternalController_findOne parameters: - name: x-impersonate-user-id in: header description: ID of an organization member to act on behalf of. The API key user must be the owner of the organization and the target user must belong to the same organization. required: false schema: type: string - name: id required: true in: path schema: type: number responses: '200': description: Get one campaign content: application/json: schema: $ref: '#/components/schemas/Campaign' security: - bearer: [] summary: Get one campaign tags: - Campaigns patch: description: Update campaign name, associated list IDs, and existing step messages or same/AI mode. **Steps must keep the same length and type order; only the message content and mode can be edited in the steps.** operationId: CampaignExternalController_update parameters: - name: x-impersonate-user-id in: header description: ID of an organization member to act on behalf of. The API key user must be the owner of the organization and the target user must belong to the same organization. required: false schema: type: string - name: id required: true in: path schema: type: number requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateCampaignExternalDto' responses: '200': description: Campaign updated content: application/json: schema: $ref: '#/components/schemas/Campaign' '400': description: Invalid step update or list assignment '404': description: Campaign or list not found security: - bearer: [] summary: Update one campaign tags: - Campaigns components: schemas: Campaign: type: object properties: id: type: number description: Unique identifier for the campaign name: type: string description: Name of the campaign steps: type: array description: Campaign steps userId: type: number description: User ID who owns this campaign active: type: boolean description: Whether the campaign is active default: true excludeFirstDegreeFromCampaigns: type: boolean description: Exclude first degree connections from campaigns default: true isManual: type: boolean description: Whether the campaign is manual default: false skipInvitationAfterDays: type: number description: Number of days after which a pending invitation is skipped and only email steps are sent language: type: string description: Campaign language nullable: true tone: type: string description: Campaign tone enum: - professional - direct - conversational goal: type: string description: Campaign goal enum: - conversations - demos linkedinSeatId: type: number description: LinkedIn seat ID for this campaign createdAt: format: date-time type: string description: Creation timestamp updatedAt: format: date-time type: string description: Last update timestamp required: - id - name - userId - active - excludeFirstDegreeFromCampaigns - isManual - createdAt - updatedAt UpdateCampaignExternalDto: type: object properties: name: type: string description: Campaign name example: Q1 Sales Campaign listIds: description: List IDs to associate with the campaign example: - 1 - 2 - 3 type: array items: type: string steps: type: array description: Campaign steps. Must have the same length and step type order as the existing campaign; only message and messageMode are updated. securitySchemes: API-Key: scheme: bearer bearerFormat: JWT type: http name: JWT description: Enter API Key in: header