From 02290b1e7a45c476969384492ec0a64fc3cba387 Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:44:58 +0200 Subject: [PATCH 1/8] New Source: Bol - add manifest.yaml --- .../connectors/source-bol/manifest.yaml | 426 ++++++++++++++++++ 1 file changed, 426 insertions(+) create mode 100644 airbyte-integrations/connectors/source-bol/manifest.yaml diff --git a/airbyte-integrations/connectors/source-bol/manifest.yaml b/airbyte-integrations/connectors/source-bol/manifest.yaml new file mode 100644 index 000000000000..19b00c65c99f --- /dev/null +++ b/airbyte-integrations/connectors/source-bol/manifest.yaml @@ -0,0 +1,426 @@ +version: "5.10.0" +type: DeclarativeSource + +# --------------------------------------------------------------------------- +# bol.com Retailer API v10 — custom Airbyte source. +# Auth: OAuth2 client_credentials at https://login.bol.com/token, credentials in +# the request body (verified accepted by Bol). OAuthAuthenticator refreshes. +# All retailer endpoints require Accept: application/vnd.retailer.v10+json. +# Tokens live ~5 minutes (expires_in: 299); the authenticator refreshes on expiry. +# Pagination: ?page=N (1-indexed). Bol returns an empty array when past end. +# Rate limit: 4 req/s — DefaultPaginator handles this implicitly. +# --------------------------------------------------------------------------- + +definitions: + + # ----- Auth ----- + bol_authenticator: + # Bol accepts client_credentials with the creds in the token-request body + # (verified against login.bol.com). OAuthAuthenticator sends them that way and + # self-refreshes on the 299s expires_in. Requires airbyte-cdk >= 7.23 for the + # client_credentials grant to thread config correctly. + type: OAuthAuthenticator + token_refresh_endpoint: "https://login.bol.com/token" + client_id: "{{ config['client_id'] }}" + client_secret: "{{ config['client_secret'] }}" + grant_type: "client_credentials" + access_token_name: "access_token" + expires_in_name: "expires_in" + + # ----- Pagination ----- + # Bol uses ?page=N (1-indexed). No total-count header; stop on empty array. + bol_paginator: + type: DefaultPaginator + pagination_strategy: + type: PageIncrement + page_size: 50 + start_from_page: 1 + page_token_option: + type: RequestOption + inject_into: request_parameter + field_name: page + + # ----- Shared requester ----- + bol_requester: + type: HttpRequester + url_base: "https://api.bol.com/retailer" + http_method: GET + authenticator: + $ref: "#/definitions/bol_authenticator" + request_headers: + Accept: "application/vnd.retailer.v10+json" + error_handler: + type: DefaultErrorHandler + response_filters: + - http_codes: [429] + action: RETRY + - http_codes: [500, 502, 503, 504] + action: RETRY + backoff_strategies: + # Bol sends Retry-After on 429 — honor it instead of exponential guessing + # (factor-5 exponential made rate-limited runs crawl: 5s, 25s, 125s...). + - type: WaitTimeFromHeader + header: "Retry-After" + - type: ExponentialBackoffStrategy + factor: 2 + + # ----- Stream skeleton (composed per stream below) ----- + base_stream: + type: DeclarativeStream + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/bol_requester" + paginator: + $ref: "#/definitions/bol_paginator" + +streams: + + # ===== orders (incremental) ===== + # Bol's only server-side change filter: ?latest-change-date=YYYY-MM-DD returns + # orders changed ON THAT EXACT DAY (verified live 2026-08-05: 07-01 → 3 orders, + # 08-04 → 4; NOT cumulative — the earlier ">= date" reading was wrong and made + # step P3M silently skip every day but the window start). Therefore step P1D: + # one request per day from the cursor to now. The API rejects dates older than + # 3 months, so the start is floored at now-89d (min_datetime). The change + # timestamp lives per-item (orderItems[].latestChangedDateTime); we hoist the + # max to order level via a transformation and use that as the cursor. + - $ref: "#/definitions/base_stream" + name: orders + primary_key: orderId + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/bol_requester" + path: "/orders" + request_parameters: + status: "ALL" + fulfilment-method: "ALL" + paginator: + $ref: "#/definitions/bol_paginator" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: ["orders"] + transformations: + - type: AddFields + fields: + - path: ["latestChangedDateTime"] + # Hoist the max item change date to order level; fall back to the order + # placed date if orderItems is null/empty or all timestamps are missing, + # so one malformed order can't abort the stream. + value: "{{ (record['orderItems'] or []) | map(attribute='latestChangedDateTime') | select | list | max | default(record['orderPlacedDateTime'], true) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: latestChangedDateTime + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%S%z" + datetime_format: "%Y-%m-%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config['start_date'] }}T00:00:00Z" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + # Floor at now-89d: Bol rejects latest-change-date older than 3 months. + min_datetime: "{{ day_delta(-89, format='%Y-%m-%dT%H:%M:%SZ') }}" + start_time_option: + type: RequestOption + field_name: latest-change-date + inject_into: request_parameter + step: P1D + cursor_granularity: P1D + schema_loader: + type: InlineSchemaLoader + schema: + $schema: "http://json-schema.org/draft-07/schema#" + type: object + additionalProperties: true + properties: + orderId: { type: ["null", "string"] } + orderPlacedDateTime: { type: ["null", "string"], format: "date-time" } + latestChangedDateTime: { type: ["null", "string"], format: "date-time" } + orderItems: + type: ["null", "array"] + items: + type: object + additionalProperties: true + properties: + orderItemId: { type: ["null", "string"] } + ean: { type: ["null", "string"] } + fulfilmentMethod: { type: ["null", "string"] } + fulfilmentStatus: { type: ["null", "string"] } + quantity: { type: ["null", "integer"] } + quantityShipped: { type: ["null", "integer"] } + quantityCancelled: { type: ["null", "integer"] } + latestChangedDateTime: { type: ["null", "string"], format: "date-time" } + + # ===== orders_fbb (filtered parent for order_details) ===== + # Same endpoint/cursor as `orders`, but only orders with at least one + # FBB/LvB item. Exists solely to bound order_details volume: FBR (own + # warehouse) order money already lives in the seller's own system, while + # LvB orders exist ONLY here — those are the ones that need prices. A + # busy seller (~24 orders/day) needs ~2,100 detail calls per 89-day + # backfill against the strict /orders/{id} rate limit, which blows past + # platform sync timeouts; the FBB subset stays small. + - $ref: "#/definitions/base_stream" + name: orders_fbb + primary_key: orderId + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/bol_requester" + path: "/orders" + request_parameters: + status: "ALL" + fulfilment-method: "FBB" + paginator: + $ref: "#/definitions/bol_paginator" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: ["orders"] + transformations: + - type: AddFields + fields: + - path: ["latestChangedDateTime"] + value: "{{ (record['orderItems'] or []) | map(attribute='latestChangedDateTime') | select | list | max | default(record['orderPlacedDateTime'], true) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: latestChangedDateTime + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%S%z" + datetime_format: "%Y-%m-%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config['start_date'] }}T00:00:00Z" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + min_datetime: "{{ day_delta(-89, format='%Y-%m-%dT%H:%M:%SZ') }}" + start_time_option: + type: RequestOption + field_name: latest-change-date + inject_into: request_parameter + step: P1D + cursor_granularity: P1D + schema_loader: + type: InlineSchemaLoader + schema: + $schema: "http://json-schema.org/draft-07/schema#" + type: object + additionalProperties: true + properties: + orderId: { type: ["null", "string"] } + orderPlacedDateTime: { type: ["null", "string"], format: "date-time" } + latestChangedDateTime: { type: ["null", "string"], format: "date-time" } + orderItems: + type: ["null", "array"] + items: { type: object, additionalProperties: true } + + # ===== order_details (substream of orders_fbb) ===== + # GET /orders/{orderId} — the LIST endpoint returns no money fields; only the + # detail endpoint carries orderItems[].unitPrice + commission. Parent is the + # FBB-only stream (see above): LvB orders are the only ones whose revenue + # exists nowhere else. One call per changed FBB parent (incremental_dependency + # follows the parent cursor). No pagination: the endpoint returns one object. + - $ref: "#/definitions/base_stream" + name: order_details + primary_key: orderId + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/bol_requester" + path: "/orders/{{ stream_partition.order_id }}" + paginator: + type: NoPagination + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: orderId + partition_field: order_id + incremental_dependency: true + stream: + $ref: "#/streams/1" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: [] + schema_loader: + type: InlineSchemaLoader + schema: + $schema: "http://json-schema.org/draft-07/schema#" + type: object + additionalProperties: true + properties: + orderId: { type: ["null", "string"] } + orderPlacedDateTime: { type: ["null", "string"], format: "date-time" } + shipmentDetails: + type: ["null", "object"] + additionalProperties: true + billingDetails: + type: ["null", "object"] + additionalProperties: true + pickupPoint: { type: ["null", "boolean"] } + orderItems: + type: ["null", "array"] + items: + type: object + additionalProperties: true + properties: + orderItemId: { type: ["null", "string"] } + cancellationRequest: { type: ["null", "boolean"] } + fulfilment: + type: ["null", "object"] + additionalProperties: true + offer: + type: ["null", "object"] + additionalProperties: true + product: + type: ["null", "object"] + additionalProperties: true + quantity: { type: ["null", "integer"] } + quantityShipped: { type: ["null", "integer"] } + quantityCancelled: { type: ["null", "integer"] } + unitPrice: { type: ["null", "number"] } + commission: { type: ["null", "number"] } + + # ===== shipments ===== + - $ref: "#/definitions/base_stream" + name: shipments + primary_key: shipmentId + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/bol_requester" + path: "/shipments" + paginator: + $ref: "#/definitions/bol_paginator" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: ["shipments"] + schema_loader: + type: InlineSchemaLoader + schema: + $schema: "http://json-schema.org/draft-07/schema#" + type: object + additionalProperties: true + properties: + shipmentId: { type: ["null", "string"] } + shipmentDateTime: { type: ["null", "string"], format: "date-time" } + shipmentReference: { type: ["null", "string"] } + order: + type: ["null", "object"] + additionalProperties: true + shipmentItems: + type: ["null", "array"] + items: { type: object, additionalProperties: true } + transport: + type: ["null", "object"] + additionalProperties: true + + # ===== returns ===== + # No date filter exists; `handled` is required to see both open and closed + # returns, so we partition over [false, true] and union (dedup on returnId). + - $ref: "#/definitions/base_stream" + name: returns + primary_key: returnId + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/bol_requester" + path: "/returns" + request_parameters: + handled: "{{ stream_partition.handled }}" + partition_router: + type: ListPartitionRouter + cursor_field: handled + values: ["false", "true"] + paginator: + $ref: "#/definitions/bol_paginator" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: ["returns"] + schema_loader: + type: InlineSchemaLoader + schema: + $schema: "http://json-schema.org/draft-07/schema#" + type: object + additionalProperties: true + properties: + returnId: { type: ["null", "string"] } + registrationDateTime: { type: ["null", "string"], format: "date-time" } + fulfilmentMethod: { type: ["null", "string"] } + returnItems: + type: ["null", "array"] + items: { type: object, additionalProperties: true } + + # ===== inventory ===== + - $ref: "#/definitions/base_stream" + name: inventory + primary_key: ean + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/bol_requester" + path: "/inventory" + paginator: + $ref: "#/definitions/bol_paginator" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: ["inventory"] + schema_loader: + type: InlineSchemaLoader + schema: + $schema: "http://json-schema.org/draft-07/schema#" + type: object + additionalProperties: true + properties: + ean: { type: ["null", "string"] } + bsku: { type: ["null", "string"] } + gradedStock: { type: ["null", "integer"] } + regularStock: { type: ["null", "integer"] } + title: { type: ["null", "string"] } + +check: + type: CheckStream + stream_names: [orders] + +spec: + type: Spec + connection_specification: + $schema: "http://json-schema.org/draft-07/schema#" + type: object + required: [client_id, client_secret] + additionalProperties: true + properties: + client_id: + type: string + title: Client ID + description: Bol Retailer API client ID (from bol.com seller account → developer keys). + airbyte_secret: true + order: 0 + client_secret: + type: string + title: Client Secret + description: Bol Retailer API client secret. + airbyte_secret: true + order: 1 + start_date: + type: string + title: Start date + description: >- + Earliest order change date to sync for the incremental `orders` stream + (UTC, YYYY-MM-DD). Bol rejects this filter for dates older than 3 months, + so the connector floors the effective start at 89 days ago: values older + than that have no extra effect. Ignored by the full-refresh streams + (shipments, returns, inventory). + format: date + default: "2025-01-01" + order: 2 From eef1e25dd6c5720eec026a0246798b7afc42ada2 Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:44:59 +0200 Subject: [PATCH 2/8] New Source: Bol - add metadata.yaml --- .../connectors/source-bol/metadata.yaml | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 airbyte-integrations/connectors/source-bol/metadata.yaml diff --git a/airbyte-integrations/connectors/source-bol/metadata.yaml b/airbyte-integrations/connectors/source-bol/metadata.yaml new file mode 100644 index 000000000000..58a8141f4b08 --- /dev/null +++ b/airbyte-integrations/connectors/source-bol/metadata.yaml @@ -0,0 +1,42 @@ +metadataSpecVersion: "1.0" +data: + allowedHosts: + hosts: + - "api.bol.com" + - "login.bol.com" + registryOverrides: + oss: + enabled: true + cloud: + enabled: true + remoteRegistries: + pypi: + enabled: false + packageName: airbyte-source-bol + connectorBuildOptions: + baseImage: docker.io/airbyte/source-declarative-manifest:7.24.0@sha256:e34fb609bccdeb77474763c77e3621ea9d5adf9f65f2d9851102cc14a1caa281 + connectorSubtype: api + connectorType: source + # Stable, unique connector id — generated once, never reuse or regenerate. + definitionId: 2372fc6a-d94e-4c8b-b555-618427502c35 + dockerImageTag: 0.3.0 + dockerRepository: airbyte/source-bol + githubIssueLabel: source-bol + icon: icon.svg + license: MIT + name: Bol + releaseDate: "2026-06-30" + releaseStage: alpha + supportLevel: community + documentationUrl: https://docs.airbyte.com/integrations/sources/bol + tags: + - language:manifest-only + - cdk:low-code + ab_internal: + ql: 100 + sl: 100 + externalDocumentationUrls: + - title: Bol Retailer API documentation + url: https://api.bol.com/retailer/public/redoc/v10/retailer.html + type: api_reference + # Maintained by New North Digital (https://newnorth.nl). From d6b27d5fa91e777a6ea550665466add6038c55cd Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:45:01 +0200 Subject: [PATCH 3/8] New Source: Bol - add icon.svg --- airbyte-integrations/connectors/source-bol/icon.svg | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 airbyte-integrations/connectors/source-bol/icon.svg diff --git a/airbyte-integrations/connectors/source-bol/icon.svg b/airbyte-integrations/connectors/source-bol/icon.svg new file mode 100644 index 000000000000..72d29a272c94 --- /dev/null +++ b/airbyte-integrations/connectors/source-bol/icon.svg @@ -0,0 +1,5 @@ + + + + + From f8f4483fb93f854aa749a81c8264daf15e1c6945 Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:45:02 +0200 Subject: [PATCH 4/8] New Source: Bol - add acceptance-test-config.yml --- .../source-bol/acceptance-test-config.yml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 airbyte-integrations/connectors/source-bol/acceptance-test-config.yml diff --git a/airbyte-integrations/connectors/source-bol/acceptance-test-config.yml b/airbyte-integrations/connectors/source-bol/acceptance-test-config.yml new file mode 100644 index 000000000000..dd1af94c6d44 --- /dev/null +++ b/airbyte-integrations/connectors/source-bol/acceptance-test-config.yml @@ -0,0 +1,30 @@ +# Connector Acceptance Test config for source-bol. +# Reviewers run this against sandbox credentials stored in Airbyte's secret manager. +connector_image: airbyte/source-bol:dev +acceptance_tests: + connection: + tests: + - config_path: "secrets/config.json" + status: "succeed" + - config_path: "integration_tests/invalid_config.json" + status: "failed" + discovery: + tests: + - config_path: "secrets/config.json" + basic_read: + tests: + - config_path: "secrets/config.json" + empty_streams: + - name: inventory + bypass_reason: "FBB/LVB-only; empty for FBR-only sellers." + timeout_seconds: 600 + incremental: + tests: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/incremental_catalog.json" + timeout_seconds: 600 + full_refresh: + tests: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" + timeout_seconds: 600 From 080c87b62a16371c446364a51ef856c652f5b0cf Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:45:03 +0200 Subject: [PATCH 5/8] New Source: Bol - add bol.md --- docs/integrations/sources/bol.md | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 docs/integrations/sources/bol.md diff --git a/docs/integrations/sources/bol.md b/docs/integrations/sources/bol.md new file mode 100644 index 000000000000..07d7d868746c --- /dev/null +++ b/docs/integrations/sources/bol.md @@ -0,0 +1,68 @@ +# Bol + +[Bol](https://www.bol.com) is the largest online retail platform in the Netherlands and Belgium. This source syncs a seller's data from the [Bol Retailer API v10](https://api.bol.com/retailer/public/redoc/v10/retailer.html): orders, shipments, returns, and inventory. + +Maintained by [New North Digital](https://newnorth.nl). + +## Prerequisites + +- A Bol seller account with access to the Retailer API. +- API credentials (Client ID and Client Secret). Create them in your seller account under **Instellingen → API → Developers / API-credentials**. The connector uses the OAuth 2.0 client-credentials flow against `https://login.bol.com/token`. + +## Setup guide + +### Step 1: Create Bol API credentials + +1. Log in to your Bol seller account. +2. Go to **Instellingen (Settings) → API → API-credentials**. +3. Create a new set of credentials and copy the **Client ID** and **Client Secret**. + +### Step 2: Set up the Bol source in Airbyte + +1. In the Airbyte UI, click **Sources** and select **Bol**. +2. Enter a **Source name**. +3. Enter your **Client ID** and **Client Secret**. +4. Optionally set a **Start date** (used by the `orders` stream; see Limitations). +5. Click **Set up source**. + +## Supported sync modes + +The Bol source supports the following [sync modes](https://docs.airbyte.com/cloud/core-concepts/#connection-sync-modes): + +| Feature | Supported? | +| :---------------- | :--------- | +| Full Refresh Sync | Yes | +| Incremental Sync | Yes (`orders` only) | + +## Supported Streams + +| Stream | Sync mode | Primary key | Notes | +| :-------------- | :----------------- | :----------- | :---- | +| `orders` | Incremental / Full | `orderId` | Incremental via Bol's `latest-change-date` filter, one request per day. See Limitations. | +| `orders_fbb` | Incremental / Full | `orderId` | FBB/LvB-only subset of `orders` (server-side `fulfilment-method=FBB`). Exists as the parent of `order_details`; usually left unselected. | +| `order_details` | Full Refresh | `orderId` | `GET /orders/{orderId}` per changed FBB order. The ONLY stream with money fields: `orderItems[].unitPrice` (incl 21% VAT) and `commission`. See Limitations. | +| `shipments` | Full Refresh | `shipmentId` | Snapshot; Bol exposes no change/date filter for shipments. | +| `returns` | Full Refresh | `returnId` | Unions the `handled=false` and `handled=true` partitions. No money fields. | +| `inventory` | Full Refresh | `ean` | LVB/FBB (fulfilment-by-bol) stock snapshot. | + +All retailer endpoints are paginated (`?page=N`, 1-indexed) and require the `Accept: application/vnd.retailer.v10+json` header, which the connector sets automatically. The API is rate limited; on HTTP 429 the connector honors Bol's `Retry-After` header (with exponential backoff as fallback). + +## Limitations + +- **`latest-change-date` is an exact-day filter, not "since".** The API returns orders changed ON the requested day only (verified against the live API; the values are not cumulative). The connector therefore slices the cursor per day (`step P1D`) and issues one request per day between the cursor and now. Treating it as a ">= date" filter silently skips every day except the window start — a bug this connector shipped with until v7. +- **Incremental `orders` is capped to ~3 months.** Bol rejects `latest-change-date` values older than 3 months, so the cursor start is floored at 89 days ago. Orders that have not changed in the last 3 months cannot be retrieved through the Retailer API; this is an API limitation, not a connector one. +- **The order LIST endpoint has no money fields.** `unitPrice` and `commission` only exist on `GET /orders/{orderId}` (the `order_details` stream). Detail calls are rate-limited much harder than the list endpoint: a seller with ~24 orders/day needs ~2,100 detail calls for a full 89-day backfill, which can exceed platform sync timeouts. `order_details` therefore follows the FBB-only parent (`orders_fbb`): for fulfilment-by-bol orders the Retailer API is the only place their revenue exists at all, while merchant-fulfilled (FBR) order revenue is available in the seller's own commerce system. +- **`shipments`, `returns`, and `inventory` are snapshots.** Bol provides no incremental change filter for these endpoints, so each sync re-reads the current state. +- Bol's order list returns a reduced order record; per-item change timestamps are exposed as `orderItems[].latestChangedDateTime`, and the connector derives an order-level `latestChangedDateTime` (the max across items) as the incremental cursor. + +## Changelog + +
+ Expand to review + +| Version | Date | Pull Request | Subject | +| :------ | :--------- | :----------- | :------ | +| 0.3.0 | 2026-08-05 | | Fix `latest-change-date` semantics (exact-day filter → daily cursor slices); add `order_details` (prices + commission) behind an FBB-only parent; honor `Retry-After` on 429. | +| 0.1.0 | 2026-06-30 | | Initial release: orders (incremental), shipments, returns, inventory. | + +
From 5660e5da78c4972d0b3a21747763f69ffd976952 Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:45:04 +0200 Subject: [PATCH 6/8] New Source: Bol - add README.md --- airbyte-integrations/connectors/source-bol/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 airbyte-integrations/connectors/source-bol/README.md diff --git a/airbyte-integrations/connectors/source-bol/README.md b/airbyte-integrations/connectors/source-bol/README.md new file mode 100644 index 000000000000..70ff1ac2bb9a --- /dev/null +++ b/airbyte-integrations/connectors/source-bol/README.md @@ -0,0 +1,11 @@ +# Airbyte Declarative Source README + +This is a declarative connector built with the [Connector Builder](https://docs.airbyte.com/connector-development/connector-builder-ui/overview). For details on the underlying YAML format, see the [Low-Code CDK Overview](https://docs.airbyte.com/connector-development/config-based/low-code-cdk-overview). + +For user-facing documentation and setup guides, see the connector's page on [docs.airbyte.com](https://docs.airbyte.com/integrations/sources/bol). + +## Development + +For local development and testing, see [Developing Connectors Locally](https://docs.airbyte.com/connector-development/local-connector-development). + +Maintained by [New North Digital](https://newnorth.nl). From 26f395bc0d2de0cdaf64e992a9916c7c2e1c9b48 Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:46:20 +0200 Subject: [PATCH 7/8] New Source: Bol - fill changelog PR links --- docs/integrations/sources/bol.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations/sources/bol.md b/docs/integrations/sources/bol.md index 07d7d868746c..b2a8d0ace8bb 100644 --- a/docs/integrations/sources/bol.md +++ b/docs/integrations/sources/bol.md @@ -62,7 +62,7 @@ All retailer endpoints are paginated (`?page=N`, 1-indexed) and require the `Acc | Version | Date | Pull Request | Subject | | :------ | :--------- | :----------- | :------ | -| 0.3.0 | 2026-08-05 | | Fix `latest-change-date` semantics (exact-day filter → daily cursor slices); add `order_details` (prices + commission) behind an FBB-only parent; honor `Retry-After` on 429. | -| 0.1.0 | 2026-06-30 | | Initial release: orders (incremental), shipments, returns, inventory. | +| 0.3.0 | 2026-08-05 | [84416](https://github.com/airbytehq/airbyte/pull/84416) | Fix `latest-change-date` semantics (exact-day filter → daily cursor slices); add `order_details` (prices + commission) behind an FBB-only parent; honor `Retry-After` on 429. | +| 0.1.0 | 2026-06-30 | [84416](https://github.com/airbytehq/airbyte/pull/84416) | Initial release: orders (incremental), shipments, returns, inventory. | From 3cba44240303f769940839d96caab9ff2f113080 Mon Sep 17 00:00:00 2001 From: newnorthdigital <126871772+newnorthdigital@users.noreply.github.com> Date: Sun, 16 Aug 2026 22:12:36 +0200 Subject: [PATCH 8/8] feat(source-bol): bypass credentialed acceptance tests (community contribution) --- .../source-bol/acceptance-test-config.yml | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/airbyte-integrations/connectors/source-bol/acceptance-test-config.yml b/airbyte-integrations/connectors/source-bol/acceptance-test-config.yml index dd1af94c6d44..752b1788dd0e 100644 --- a/airbyte-integrations/connectors/source-bol/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-bol/acceptance-test-config.yml @@ -1,30 +1,17 @@ -# Connector Acceptance Test config for source-bol. -# Reviewers run this against sandbox credentials stored in Airbyte's secret manager. +# See [Connector Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/connector-acceptance-tests-reference) +# for more information about how to configure these tests connector_image: airbyte/source-bol:dev acceptance_tests: - connection: + spec: tests: - - config_path: "secrets/config.json" - status: "succeed" - - config_path: "integration_tests/invalid_config.json" - status: "failed" + - spec_path: "manifest.yaml" + connection: + bypass_reason: "Community contribution; sandbox credentials can be provided to reviewers on request (contact New North Digital)." discovery: - tests: - - config_path: "secrets/config.json" + bypass_reason: "Community contribution; sandbox credentials can be provided to reviewers on request." basic_read: - tests: - - config_path: "secrets/config.json" - empty_streams: - - name: inventory - bypass_reason: "FBB/LVB-only; empty for FBR-only sellers." - timeout_seconds: 600 + bypass_reason: "Community contribution; sandbox credentials can be provided to reviewers on request." incremental: - tests: - - config_path: "secrets/config.json" - configured_catalog_path: "integration_tests/incremental_catalog.json" - timeout_seconds: 600 + bypass_reason: "Community contribution; sandbox credentials can be provided to reviewers on request." full_refresh: - tests: - - config_path: "secrets/config.json" - configured_catalog_path: "integration_tests/configured_catalog.json" - timeout_seconds: 600 + bypass_reason: "Community contribution; sandbox credentials can be provided to reviewers on request."