> ## 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 update links

> Apply one shared partial update to up to 100 links.

Apply the same partial update to between 1 and 100 links. Identify targets with
either their Biqli public IDs or your workspace-unique external IDs.

## Authentication and permission

This endpoint requires **Links: Write** (`links.update`). Fields that reference
domains, folders, pixels, or tags additionally require that resource's read
permission, exactly as described by [Update a link](/docs/api-reference/links/update).

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

## Update by public link ID

Send `link_ids` and a non-empty `data` object. Only fields in `data` are changed.

```bash theme={null}
curl --request PATCH \
  --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 '{
    "link_ids": [
      "biq_lnk_01M17YFAR0FEN7R66T99JH820N",
      "biq_lnk_01M17Y6XGP07PR11S3DRFCX6Y9"
    ],
    "data": {
      "active": false,
      "tag_ids": ["biq_tag_01M14CC1TW7AQ6DWZG9TMRH0PQ"]
    }
  }'
```

## Update by external ID

Use `external_ids` instead of `link_ids` when your integration owns the IDs:

```json theme={null}
{
  "external_ids": ["catalog-blue", "catalog-red"],
  "data": {
    "utm": "source=catalog&medium=api&campaign=autumn"
  }
}
```

`link_ids` and `external_ids` are mutually exclusive. Each list accepts 1 to
100 distinct strings. External IDs match exactly and are unique within the
workspace.

## Fields you can update

`data` accepts the mutable fields documented by the single
[Update a link](/docs/api-reference/links/update) endpoint: destination, name,
domain, active state, password, schedule, expiration rule, UTM data, dynamic
routing, resource attachments, conversion tracking, indexing, and custom
preview fields.

`alias` and `external_id` are intentionally excluded from a shared bulk patch
because they are per-link unique identities. Change either one surgically with
`PATCH /v1/link/{link}`. To clear a nullable value, send `null`; to clear a
collection such as tags or geo rules, send `[]`.

Every target goes through the same plan, URL safety, reference, schedule, and
activity flow as an individual PATCH. Updates run in request order and are
independent.

## Response and partial success

Complete success returns `200 OK`. Any missing or rejected target produces
`207 Multi-Status`; successful targets remain updated.

```json theme={null}
{
  "results": [
    {
      "index": 0,
      "identifier": "catalog-blue",
      "status": "success",
      "link": {
        "id": "biq_lnk_01M17YFAR0FEN7R66T99JH820N",
        "external_id": "catalog-blue",
        "active": false,
        "safety_status": "clear"
      }
    },
    {
      "index": 1,
      "identifier": "catalog-red",
      "status": "error",
      "error": {
        "code": "resource_not_found",
        "message": "The link was not found in this workspace."
      }
    }
  ],
  "summary": {
    "requested_count": 2,
    "updated_count": 1,
    "failed_count": 1
  },
  "status": "partial_success"
}
```

The full response link contains every field from
[Retrieve a link](/docs/api-reference/links/get). Valid-looking identifiers outside
the key's workspace are reported as not found, preventing workspace discovery.
Always inspect each result and retry only failures.

## Request-level errors

| HTTP status | Meaning                                                             |
| ----------- | ------------------------------------------------------------------- |
| `401`       | Invalid or revoked workspace API key.                               |
| `403`       | Missing `links.update`, lost workspace access, or plan restriction. |
| `422`       | Invalid envelope or shared `data`; no targets are updated.          |
| `429`       | Workspace API rate limit exceeded.                                  |
| `500`       | Unexpected server error.                                            |

Item-specific `404`, `409`, and `422` outcomes appear inside a `207` response.
Every top-level API error contains a traceable `request_id`.

## 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 PATCH /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:
    patch:
      tags:
        - Links
      summary: Bulk update links
      description: >-
        Applies one shared partial update to 1 to 100 public or external IDs.
        Requires links.update.
      operationId: link.bulkUpdate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkUpdateLinksRequest'
      responses:
        '200':
          description: Every link was updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkUpdateLinksResponse'
        '207':
          description: One or more targets failed. Inspect every ordered result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkUpdateLinksResponse'
        '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:
    BulkUpdateLinksRequest:
      type: object
      additionalProperties: false
      required:
        - data
      oneOf:
        - required:
            - link_ids
          not:
            required:
              - external_ids
        - required:
            - external_ids
          not:
            required:
              - link_ids
      properties:
        link_ids:
          type: array
          minItems: 1
          maxItems: 100
          uniqueItems: true
          items:
            type: string
            pattern: ^biq_lnk_[0-9A-HJKMNP-TV-Z]{26}$
        external_ids:
          type: array
          minItems: 1
          maxItems: 100
          uniqueItems: true
          items:
            type: string
            minLength: 1
            maxLength: 255
        data:
          allOf:
            - $ref: '#/components/schemas/UpdateLinkRequest'
            - not:
                anyOf:
                  - required:
                      - alias
                  - required:
                      - external_id
    BulkUpdateLinksResponse:
      type: object
      additionalProperties: false
      required:
        - results
        - summary
        - status
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/BulkUpdateLinkResult'
        summary:
          type: object
          additionalProperties: false
          required:
            - requested_count
            - updated_count
            - failed_count
          properties:
            requested_count:
              type: integer
              minimum: 1
              maximum: 100
            updated_count:
              type: integer
              minimum: 0
              maximum: 100
            failed_count:
              type: integer
              minimum: 0
              maximum: 100
        status:
          type: string
          enum:
            - success
            - partial_success
            - failed
    UpdateLinkRequest:
      type: object
      description: A partial link update. Omitted properties keep their current values.
      additionalProperties: false
      properties:
        long_url: 05436939-163d-42a1-a46b-5febe8972185
        name: 8fd3050f-54e4-43d9-a589-934210f4ad4e
        external_id: a725f1c6-2c3c-4503-84c0-08fa0758b839
        domain_id: 5fe841dd-ba54-4189-9515-5dd6e9a4c58a
        alias: 0cb4add7-52ce-4cc6-814d-647ef9bd2715
        active: 176f58cb-82e0-4f76-b6d8-9055e5ad8808
        password: 1add5038-51dd-4efc-9b7f-0176dbe88bfd
        activates_at: 711f9940-41a6-436b-b343-13c993c12d42
        expires_at: ccf4d194-8bcf-4d23-972d-8937fe827e47
        exp_clicks_rule: 59d8f321-bc32-47f2-9714-925df33fa868
        utm: e20022e1-62de-43b1-8e9f-7b05bf5ae954
        geo_rules: f190bfac-b5ee-4ac9-b260-9e205020fd08
        device_rules: feaa0c92-a9a1-4dfb-a452-a642e01da2bc
        platform_rules: ce030e0a-f823-445a-809b-37dedbfb0298
        folder_ids: 5e09847e-09c5-4e82-9c3f-b45fa680750c
        pixel_ids: ed8d8232-987c-4079-a761-5c43d796d671
        tag_ids: 2b365fd6-708a-4bbd-b26f-b5effe279779
        conversion_tracking_enabled: b17ab153-e55d-479d-998a-9a01bf2b0da6
        allow_search_engine_indexing: 0dd79ef7-3306-4a9c-8e3b-8285b8fe131e
        proxy: e47b69a2-b5c6-4c3d-9aff-06ca5421b1f9
        title: 4f148443-6b51-4c3c-953e-bab66aac6184
        description: cebf8337-babe-48dc-ba19-97ce1948eb39
        image: 4c659d58-b3c1-42e9-825e-12745be9bb77
    BulkUpdateLinkResult:
      type: object
      additionalProperties: false
      required:
        - index
        - identifier
        - status
      properties:
        index:
          type: integer
          minimum: 0
        identifier:
          type: string
        status:
          type: string
          enum:
            - success
            - 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.
    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
    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
    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_.

````