> ## Documentation Index
> Fetch the complete documentation index at: https://learn.biq.li/llms.txt
> Use this file to discover all available pages before exploring further.

# Bulk create links

> Create up to 100 complete links in one ordered request.

Create between 1 and 100 links in one request. Each entry supports the complete
payload documented by [Create a link](/docs/api-reference/links/create), including
external IDs, dynamic routing, attachments, custom previews, and attached QR
codes.

## Authentication and permissions

The key needs **Links: Write** (`links.create`). An item that attaches a domain,
folder, pixel, or tag also requires the corresponding read permission described
in [Create a link](/docs/api-reference/links/create#authentication-and-permissions).

```http theme={null}
Authorization: Bearer biqli_your_workspace_api_key
Content-Type: application/json
Accept: application/json
```

The key determines the workspace. Do not include a workspace or internal
numeric ID.

## Request

Wrap the ordered link payloads in `links`:

```bash theme={null}
curl --request POST \
  --url 'https://biq.li/api/v1/link/bulk' \
  --header 'Authorization: Bearer biqli_your_workspace_api_key' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "links": [
      {
        "long_url": "https://example.com/products/blue",
        "name": "Blue product",
        "external_id": "catalog-blue"
      },
      {
        "long_url": "https://example.com/products/red",
        "name": "Red product",
        "external_id": "catalog-red",
        "tag_ids": ["biq_tag_01M14CC1TW7AQ6DWZG9TMRH0PQ"]
      }
    ]
  }'
```

Every item is validated and created through the same flow as the single Create
endpoint. That includes URL normalization and safety checks, plan features,
quota usage, alias and external-ID uniqueness, workspace references, QR file
cleanup, activity history, and the complete safe link response.

The response preserves request order. `index` is the zero-based position of the
corresponding request item.

## Complete success

If all items are created, the endpoint returns `201 Created`:

```json theme={null}
{
  "results": [
    {
      "index": 0,
      "status": "success",
      "link": {
        "id": "biq_lnk_01M17YFAR0FEN7R66T99JH820N",
        "external_id": "catalog-blue",
        "short_url": "https://biq.li/vYdheWL",
        "long_url": "https://example.com/products/blue",
        "name": "Blue product",
        "active": true,
        "clicks_count": 0,
        "leads_count": 0,
        "sales_count": 0,
        "revenue": 0,
        "revenue_currency": "USD",
        "safety_status": "clear"
      }
    }
  ],
  "summary": {
    "requested_count": 1,
    "created_count": 1,
    "failed_count": 0
  },
  "status": "success"
}
```

The actual `link` object contains every field documented by
[Retrieve a link](/docs/api-reference/links/get). An item whose URL needs an
asynchronous check has `status: "pending"`; the link exists but cannot redirect
until its `safety_status` becomes `clear`.

## Partial success

Items are independent. A bad item does not roll back successful items. If any
item fails, the endpoint returns `207 Multi-Status` with an error beside that
item:

```json theme={null}
{
  "results": [
    {
      "index": 0,
      "status": "success",
      "link": {"id": "biq_lnk_01M17YFAR0FEN7R66T99JH820N"}
    },
    {
      "index": 1,
      "status": "error",
      "error": {
        "code": "external_id_taken",
        "message": "The external ID is already in use in this workspace.",
        "details": {"field": "external_id"}
      }
    }
  ],
  "summary": {
    "requested_count": 2,
    "created_count": 1,
    "failed_count": 1
  },
  "status": "partial_success"
}
```

Always inspect every result; do not treat `207` as a total failure. Retry only
failed items. Supplying stable, unique `external_id` values makes reconciliation
and safe retries straightforward.

## Request-level errors

The whole request fails before item processing when `links` is missing, empty,
larger than 100, not an array, or when an unsupported top-level field is sent.

| HTTP status | Meaning                                                                                |
| ----------- | -------------------------------------------------------------------------------------- |
| `401`       | Invalid or revoked workspace API key.                                                  |
| `403`       | Missing `links.create`, lost workspace access, or request-level plan/rate restriction. |
| `422`       | Invalid bulk envelope. Item validation failures normally appear in `207` results.      |
| `429`       | Workspace API rate limit exceeded.                                                     |
| `500`       | Unexpected server error; use `request_id` when contacting support.                     |

## Shared API behavior

Authentication is workspace-scoped; see [Authentication](/docs/api-reference/authentication). Errors use the standard envelope and request IDs described in [Errors](/docs/api-reference/errors), and requests are subject to [Rate limits](/docs/api-reference/rate-limits).


## OpenAPI

````yaml POST /v1/link/bulk
openapi: 3.1.0
info:
  title: Biqli API
  version: 1.0.0
  description: Workspace-scoped REST API for Biqli.
servers:
  - url: https://biq.li/api
security:
  - bearerAuth: []
paths:
  /v1/link/bulk:
    post:
      tags:
        - Links
      summary: Bulk create links
      description: Creates 1 to 100 complete links in request order. Requires links.create.
      operationId: link.bulkStore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkCreateLinksRequest'
      responses:
        '201':
          description: Every link was created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkCreateLinksResponse'
        '207':
          description: One or more items failed. Inspect every ordered result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkCreateLinksResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    BulkCreateLinksRequest:
      type: object
      additionalProperties: false
      required:
        - links
      properties:
        links:
          type: array
          minItems: 1
          maxItems: 100
          items:
            $ref: '#/components/schemas/CreateLinkRequest'
    BulkCreateLinksResponse:
      type: object
      additionalProperties: false
      required:
        - results
        - summary
        - status
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/BulkCreateLinkResult'
        summary:
          type: object
          additionalProperties: false
          required:
            - requested_count
            - created_count
            - failed_count
          properties:
            requested_count:
              type: integer
              minimum: 1
              maximum: 100
            created_count:
              type: integer
              minimum: 0
              maximum: 100
            failed_count:
              type: integer
              minimum: 0
              maximum: 100
        status:
          type: string
          enum:
            - success
            - partial_success
            - failed
    CreateLinkRequest:
      type: object
      additionalProperties: false
      required:
        - long_url
      properties:
        long_url:
          type: string
          description: Destination URL. Biqli normalizes a missing scheme to HTTPS.
          minLength: 3
          maxLength: 1000
          examples:
            - https://example.com/product
        name:
          type:
            - string
            - 'null'
          description: Internal label for the link.
          maxLength: 150
        external_id:
          type:
            - string
            - 'null'
          description: Caller-controlled identifier, unique within the API key's workspace.
          maxLength: 255
        domain_id:
          type:
            - string
            - 'null'
          description: >-
            Public ID of a custom domain available to this workspace. Omit it to
            use the Biqli default domain.
          pattern: ^biq_dom_[0-9A-HJKMNP-TV-Z]{26}$
        alias:
          type:
            - string
            - 'null'
          description: >-
            Requested short-link alias. The configured alias character and
            length rules apply.
          maxLength: 50
        active:
          type: boolean
          description: Whether the link can redirect after it passes safety checks.
          default: true
        password:
          type:
            - string
            - 'null'
          description: Password visitors must enter before redirecting.
          maxLength: 250
        activates_at:
          type:
            - string
            - 'null'
          format: date-time
          description: ISO 8601 date and time when the link becomes active.
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Future ISO 8601 expiration date and time. It must be later than
            activates_at.
        exp_clicks_rule:
          oneOf:
            - $ref: '#/components/schemas/ClickExpirationRule'
            - type: 'null'
        utm:
          type:
            - string
            - 'null'
          description: >-
            Ampersand-separated UTM parameters without a leading question mark.
            Biqli prefixes keys with utm_ when needed.
          maxLength: 2000
          examples:
            - source=newsletter&medium=email&campaign=summer
        geo_rules:
          $ref: '#/components/schemas/TargetingRules'
        device_rules:
          $ref: '#/components/schemas/TargetingRules'
        platform_rules:
          $ref: '#/components/schemas/TargetingRules'
        folder_ids:
          type:
            - array
            - 'null'
          description: Unique public IDs of folders in this workspace.
          maxItems: 100
          uniqueItems: true
          items:
            type: string
            pattern: ^biq_fld_[0-9A-HJKMNP-TV-Z]{26}$
        pixel_ids:
          type:
            - array
            - 'null'
          description: Unique public IDs of tracking pixels in this workspace.
          maxItems: 100
          uniqueItems: true
          items:
            type: string
            pattern: ^biq_pxl_[0-9A-HJKMNP-TV-Z]{26}$
        tag_ids:
          type:
            - array
            - 'null'
          description: Unique public IDs of tags in this workspace.
          maxItems: 100
          uniqueItems: true
          items:
            type: string
            pattern: ^biq_tag_[0-9A-HJKMNP-TV-Z]{26}$
        conversion_tracking_enabled:
          type: boolean
          description: Append a Biqli click ID for conversion attribution.
          default: false
        allow_search_engine_indexing:
          type: boolean
          description: Allow search engines to index the short-link page.
          default: false
        proxy:
          type: boolean
          description: >-
            Enable the custom social preview supplied by title, description, and
            image.
          default: false
        title:
          type:
            - string
            - 'null'
          description: Custom social preview title. Requires proxy=true.
          maxLength: 255
        description:
          type:
            - string
            - 'null'
          description: Custom social preview description. Requires proxy=true.
          maxLength: 1000
        image:
          type:
            - string
            - 'null'
          format: uri
          description: >-
            Public HTTPS URL for the custom social preview image. Requires
            proxy=true. Private and local hosts are rejected.
          maxLength: 2048
        create_qr_code:
          type: boolean
          description: Generate and attach an SVG QR code for this short link.
          default: false
        qr_logo:
          type:
            - string
            - 'null'
          description: >-
            Use the Biqli app logo or no center logo. Requires
            create_qr_code=true. The none option is plan-gated.
          enum:
            - app
            - none
            - null
          default: app
    BulkCreateLinkResult:
      type: object
      additionalProperties: false
      required:
        - index
        - status
      properties:
        index:
          type: integer
          minimum: 0
        status:
          type: string
          enum:
            - success
            - pending
            - error
        link:
          $ref: '#/components/schemas/CreatedLink'
        error:
          $ref: '#/components/schemas/BatchItemError'
    ApiError:
      type: object
      required:
        - error
        - request_id
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - invalid_token
                - insufficient_scope
                - upgrade_required
                - quota_exceeded
                - resource_not_found
                - domain_taken
                - alias_taken
                - external_id_taken
                - folder_name_taken
                - tag_name_taken
                - pixel_name_taken
                - biolink_name_taken
                - method_not_allowed
                - url_blocked
                - dns_verification_failed
                - validation_error
                - rate_limit_exceeded
                - internal_server_error
            message:
              type: string
            details:
              type: object
              additionalProperties: true
        request_id:
          type: string
          description: Request identifier to include when contacting support.
    ClickExpirationRule:
      type: object
      additionalProperties: false
      required:
        - key
      properties:
        key:
          type: integer
          minimum: 1
          description: Number of clicks after which the link expires.
        value:
          type:
            - string
            - 'null'
          description: Optional URL to use after the click threshold is reached.
          maxLength: 1000
    TargetingRules:
      type:
        - array
        - 'null'
      description: Destination overrides evaluated for matching visitors.
      maxItems: 100
      items:
        $ref: '#/components/schemas/TargetingRule'
    CreatedLink:
      type: object
      required:
        - id
        - external_id
        - short_url
        - long_url
        - name
        - domain_id
        - alias
        - active
        - has_password
        - activates_at
        - expires_at
        - exp_clicks_rule
        - utm
        - folder_ids
        - pixel_ids
        - tag_ids
        - conversion_tracking_enabled
        - allow_search_engine_indexing
        - proxy
        - title
        - description
        - image
        - qr_code
        - geo_rules
        - device_rules
        - platform_rules
        - clicks_count
        - leads_count
        - sales_count
        - revenue
        - revenue_currency
        - clicked_at
        - safety_status
        - created_at
        - updated_at
      properties:
        id:
          type: string
          description: Public link ID. Internal numeric IDs are never returned.
          pattern: ^biq_lnk_[0-9A-HJKMNP-TV-Z]{26}$
        external_id:
          type:
            - string
            - 'null'
          description: Caller-controlled identifier, unique within the workspace.
        short_url:
          type: string
          format: uri
        long_url:
          type: string
        name:
          type:
            - string
            - 'null'
        domain_id:
          type:
            - string
            - 'null'
          pattern: ^biq_dom_[0-9A-HJKMNP-TV-Z]{26}$
        alias:
          type:
            - string
            - 'null'
        active:
          type: boolean
        has_password:
          type: boolean
        activates_at:
          type:
            - string
            - 'null'
          format: date-time
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
        exp_clicks_rule:
          oneOf:
            - $ref: '#/components/schemas/ClickExpirationRule'
            - type: 'null'
        utm:
          type:
            - string
            - 'null'
        geo_rules:
          type: array
          items:
            $ref: '#/components/schemas/TargetingRule'
        device_rules:
          type: array
          items:
            $ref: '#/components/schemas/TargetingRule'
        platform_rules:
          type: array
          items:
            $ref: '#/components/schemas/TargetingRule'
        folder_ids:
          type: array
          items:
            type: string
        pixel_ids:
          type: array
          items:
            type: string
        tag_ids:
          type: array
          items:
            type: string
        conversion_tracking_enabled:
          type: boolean
        allow_search_engine_indexing:
          type: boolean
        proxy:
          type: boolean
        title:
          type:
            - string
            - 'null'
        description:
          type:
            - string
            - 'null'
        image:
          type:
            - string
            - 'null'
        qr_code:
          oneOf:
            - $ref: '#/components/schemas/AttachedQrCode'
            - type: 'null'
        clicks_count:
          type: integer
          minimum: 0
          description: Total recorded clicks.
        leads_count:
          type: integer
          minimum: 0
          description: Total attributed lead events.
        sales_count:
          type: integer
          minimum: 0
          description: Total attributed sale events.
        revenue:
          type: number
          minimum: 0
          description: Attributed sales amount normalized to USD.
        revenue_currency:
          type: string
          const: USD
        clicked_at:
          type:
            - string
            - 'null'
          format: date-time
          description: Time of the most recent recorded click.
        safety_status:
          type: string
          enum:
            - clear
            - pending
            - quarantined
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    BatchItemError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string
        details:
          type: object
          additionalProperties: true
    TargetingRule:
      type: object
      additionalProperties: false
      required:
        - key
        - value
      properties:
        key:
          type: string
          description: Match value, such as a country code, device, or platform.
          maxLength: 250
        value:
          type: string
          description: Destination URL used when the rule matches.
          maxLength: 1000
    AttachedQrCode:
      type: object
      required:
        - url
        - format
        - logo
      properties:
        url:
          type: string
          format: uri
        format:
          type: string
          const: svg
        logo:
          type: string
          enum:
            - app
            - none
  responses:
    Unauthorized:
      $ref: '#/components/responses/ApiErrorResponse'
      description: The workspace API key is missing, invalid, or revoked.
    Forbidden:
      $ref: '#/components/responses/ApiErrorResponse'
      description: >-
        The key lacks a required scope, the workspace must upgrade, or its quota
        is exhausted.
    UnprocessableEntity:
      $ref: '#/components/responses/ApiErrorResponse'
      description: >-
        The payload is invalid, a destination was blocked, or domain DNS
        verification is not ready.
    RateLimited:
      description: The workspace exceeded its plan's API rate limit.
      headers:
        RateLimit-Policy:
          description: Current IETF HTTPAPI quota policy as a structured field.
          schema:
            type: string
            example: '"workspace-api";q=1000;w=60'
        RateLimit:
          description: Current IETF HTTPAPI service limit as a structured field.
          schema:
            type: string
            example: '"workspace-api";r=0;t=17'
        Retry-After:
          description: Seconds to wait before retrying the request.
          schema:
            type: integer
            minimum: 0
            example: 17
        X-RateLimit-Limit:
          description: Legacy maximum request count for the current window.
          schema:
            type: integer
            minimum: 1
            example: 1000
        X-RateLimit-Remaining:
          description: Legacy remaining request count.
          schema:
            type: integer
            minimum: 0
            example: 0
        X-RateLimit-Reset:
          description: Legacy reset time as a UTC Unix timestamp.
          schema:
            type: integer
            format: int64
            example: 1788126519
        X-Biq-Request-Id:
          description: Request identifier for support and tracing.
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    InternalError:
      $ref: '#/components/responses/ApiErrorResponse'
      description: The request failed unexpectedly.
    ApiErrorResponse:
      description: API error.
      headers:
        X-Biq-Request-Id:
          description: Request identifier for support and tracing.
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Workspace API key
      description: A workspace API key beginning with biqli_.

````