Stuart Horgan
08/18/2026, 3:52 PM/loans:search and the POST method. When trying to test it, i get the following error:
Traceback (most recent call last):
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/abstract_source.py", line 152, in read
yield from self._read_stream(
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/abstract_source.py", line 276, in _read_stream
for record_data_or_message in record_iterator:
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/streams/core.py", line 196, in read
for record_data_or_message in records:
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/declarative_stream.py", line 154, in read_records
yield from self.retriever.read_records(self.get_json_schema(), stream_slice) # type: ignore # records are of the correct type
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py", line 446, in read_records
for stream_data in self._read_pages(record_generator, self.state, _slice):
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py", line 343, in _read_pages
response = self._fetch_next_page(stream_state, stream_slice, next_page_token)
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py", line 574, in _fetch_next_page
return self.requester.send_request(
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/requesters/http_requester.py", line 342, in send_request
request, response = self._http_client.send_request(
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/http_client.py", line 524, in send_request
response: requests.Response = self._send_with_retry(
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/http_client.py", line 270, in _send_with_retry
response = backoff_handler(rate_limit_backoff_handler(user_backoff_handler))(
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/backoff/_sync.py", line 105, in retry
ret = target(*args, **kwargs)
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/backoff/_sync.py", line 105, in retry
ret = target(*args, **kwargs)
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/backoff/_sync.py", line 105, in retry
ret = target(*args, **kwargs)
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/http_client.py", line 340, in _send
self._handle_error_resolution(
File "/home/airbyte/.pyenv/versions/3.10.15/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/http_client.py", line 427, in _handle_error_resolution
raise MessageRepresentationAirbyteTracedErrors(
airbyte_cdk.sources.streams.http.http_client.MessageRepresentationAirbyteTracedErrors: Invalid Protocol Schema: The endpoint that data is being requested from is using an invalid or insecure. Exception: requests.exceptions.InvalidSchema
what does this mean? and in which logs can i view the exact text of the request that was run during the test to produce this error?kapa.ai
08/18/2026, 3:52 PMairbyte_cdk.sources.streams.http.http_client.MessageRepresentationAirbyteTracedErrors:
Invalid Protocol Schema: The endpoint that data is being requested from is using an invalid
or insecure. Exception: requests.exceptions.InvalidSchema
This is a requests.exceptions.InvalidSchema error, which means the URL being constructed for the request is malformed — specifically, the protocol/schema part of the URL is invalid or missing. This is not an API authentication or rate-limit issue.
A likely cause with your setup is the URL path /loans:search. The colon (:) in the path segment could be causing the URL to be misinterpreted. Depending on how the base URL and path are being concatenated in the Connector Builder, the resulting URL might end up malformed (e.g., loans:search being parsed as a protocol scheme instead of a path).
Things to check:
• Verify your Base URL is correctly set (e.g., https://api.example.com) and does not have a trailing slash issue when combined with /loans:search.
• Try URL-encoding the colon if the API allows it: /loans%3Asearch (though this may change the API behavior).
• Double-check that the full constructed URL would be something like https://api.example.com/loans:search and not something broken like loans:search being treated as a scheme.
Where to Find Request Logs The knowledge sources do not explicitly document where to view the exact HTTP request text in the Connector Builder test UI. Generally in Airbyte, you would look at:
• The connector logs tab in the Connector Builder test panel.
• The sync logs in the Airbyte UI if running a full sync.
For more detailed request/response logging, you may need to check the Airbyte documentation directly or the Airbyte community forum or GitHub issues for guidance specific to your version. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/18/2026, 4:00 PM{
"filterCriteria": [
{
"field": "lastModifiedDate",
"operator": "AFTER",
"value": "{{ config['start_date'] }}"
}
],
"sortingCriteria": {
"field": "lastModifiedDate",
"order": "ASC"
}
}
In my incremental sync options, i want to inject start time into the Body JSON Payload to replace filterCriteria.value . What do i enter in field path to set this up?kapa.ai
08/18/2026, 4:00 PMfield_path for nested body_json injection. For your structure, you need to navigate into the filterCriteria array and then to value.
However, there is an important limitation here: filterCriteria is an array, and the knowledge sources do not explicitly document how field_path handles array indexing. What is documented is that field_path works for nested JSON objects.
For a straightforward nested object case, the field_path in your YAML would look like this:
start_time_option:
type: RequestOption
inject_into: body_json
field_path:
- filterCriteria
- "0" # array index - not confirmed to work
- value
A real-world example from the source-linear connector shows field_path used for nested objects like this: [Linear manifest]
start_time_option:
type: RequestOption
inject_into: body_json
field_path:
- variables
- filter
- updatedAt
- gte
This works cleanly because those are all object keys. [Request Options docs]
Recommended Workaround Since your filterCriteria is an array (which may not be supported by field_path), the safer approach is to disable the built-in start/end time injection in the incremental sync form and instead use custom parameter injection directly in your request body JSON, referencing stream_interval variables: [Custom parameter injection]
requester:
type: HttpRequester
http_method: POST
request_body_json:
filterCriteria:
- field: "lastModifiedDate"
operator: "AFTER"
value: "{{ stream_interval.start_time }}"
sortingCriteria:
field: "lastModifiedDate"
order: "ASC"
This approach gives you full control over the body structure, including arrays, and avoids the uncertainty around array indexing in field_path. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/18/2026, 4:02 PM2026-08-10T10:26:11+01:00kapa.ai
08/18/2026, 4:02 PM2026-08-10T10:26:11+01:00 is in ISO 8601 format with a UTC offset, which corresponds to the format code:
%Y-%m-%dT%H:%M:%S%z
Where:
• %Y = 2026 (4-digit year)
• %m = 08 (month)
• %d = 10 (day)
• %H = 10 (hour, 24h)
• %M = 26 (minute)
• %S = 11 (second)
• %z = +01:00 (UTC offset)
This is confirmed by the supported format placeholders in the Airbyte DatetimeBasedCursor documentation, where %z is described as "UTC offset" with examples like +0000 and -04:00. [DatetimeBasedCursor reference]
So in your incremental sync configuration, you would set:
cursor_datetime_formats:
- "%Y-%m-%dT%H:%M:%S%z" 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 10:20 AMkapa.ai
08/20/2026, 10:20 AMincremental_dependency: true on the parent stream config with global_substream_cursor: true on the child stream. The knowledge sources actually show this pattern explicitly in the Stripe connector for streams that have no meaningful child-level cursor. [Stripe manifest]
The idea is:
• incremental_dependency: true — makes the parent re-execution use its persisted cursor state, so only updated parent records are returned as partitions on subsequent syncs.
• global_substream_cursor: true — since the child has no real incremental field, a single global cursor is used just to satisfy the incremental sync configuration requirement. The real filtering happens at the parent level.
Here's how your YAML would look:
loan_schedule:
type: DeclarativeStream
retriever:
type: SimpleRetriever
requester:
path: "/loans/{{ stream_partition.parentKey }}/schedule"
http_method: GET
partition_router:
type: SubstreamPartitionRouter
parent_stream_configs:
- type: ParentStreamConfig
stream: "#/definitions/streams/loans"
parent_key: id
partition_field: parentKey
incremental_dependency: true # only fetch updated parent records
incremental_sync:
type: DatetimeBasedCursor
cursor_field: lastModifiedDate # use the parent's cursor field if available on child records, or any date field
global_substream_cursor: true # single global cursor since child has no meaningful incremental field
The Stripe connector comments explain this pattern well:
> "This stream is not truly incremental on the child level. We're configuring it this way to support incremental syncs on the parent only, which helps reduce the size of the state." [Stripe manifest]
Key requirement This only works correctly if the parent loan record's cursor field (e.g. lastModifiedDate) is updated whenever its schedule changes. From the docs:
> "The API must ensure that the parent record's cursor is updated whenever child records are added or updated. If this requirement is not met, child records added to older parent records will be lost." [Incremental sync docs]
If the parent's cursor is not reliably updated when the schedule changes, you would need to fall back to a lookback_window on the parent stream to re-check recently modified records. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 10:32 AMloan_schedule:
type: DeclarativeStream
name: loan_schedule
primary_key:
- encodedKey
retriever:
type: SimpleRetriever
requester:
$ref: "#/definitions/base_requester"
path: /loans/{{ stream_partition.parentKey }}/schedule
http_method: GET
request_parameters:
detailsLevel: FULL
request_headers:
Accept: application/vnd.mambu.v2+json
record_selector:
type: RecordSelector
extractor:
type: DpathExtractor
field_path:
- installments
partition_router:
type: SubstreamPartitionRouter
parent_stream_configs:
- type: ParentStreamConfig
parent_key: encodedKey
partition_field: parentKey
stream:
$ref: "#/definitions/streams/accounts"
incremental_dependency: true
incremental_sync:
type: DatetimeBasedCursor
cursor_field: lastModifiedDate
cursor_datetime_formats:
- "%Y-%m-%dT%H:%M:%S%z"
datetime_format: "%Y-%m-%dT%H:%M:%S%z"
start_datetime:
type: MinMaxDatetime
datetime: "{{ config[\"start_date\"] }}"
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
global_substream_cursor: true
schema_loader:
type: InlineSchemaLoader
schema:
$ref: "#/schemas/loan_schedule"
does that seem right?kapa.ai
08/20/2026, 10:33 AMincremental_dependency: true on the parent stream config — correct placement and will ensure only updated parent records generate partitions.
• global_substream_cursor: true on the incremental_sync — correct for a child stream with no meaningful child-level cursor.
• cursor_datetime_formats with %Y-%m-%dT%H:%M:%S%z — correct for the format we identified earlier.
• DpathExtractor with field_path: [installments] — correct if the schedule response wraps records in an installments array.
One Thing to Check ⚠️ The cursor_field: lastModifiedDate — since this is the schedule/installment endpoint, you need to confirm that the individual records extracted from the installments array actually contain a lastModifiedDate field. If installment records don't have this field, the cursor won't advance correctly.
If installment records don't have their own lastModifiedDate, a common workaround is to use a transformation to inject the parent's cursor value onto each child record:
transformations:
- type: AddFields
fields:
- type: AddedFieldDefinition
path:
- lastModifiedDate
value: "{{ stream_partition.parentKey }}" # or a parent record field if available
Though the knowledge sources don't explicitly confirm this pattern for your exact case, so treat this with some caution. [Incremental sync docs]
Summary The overall structure is correct. The main thing to verify before testing is whether lastModifiedDate actually exists on the extracted installments records from the API response. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 10:39 AMkapa.ai
08/20/2026, 10:39 AMlastModifiedDate value onto each child installment record, you need to use extra_fields in the ParentStreamConfig to pass it through the stream slice, then reference it via stream_slice.extra_fields in the transformation.
Update your config like this:
partition_router:
type: SubstreamPartitionRouter
parent_stream_configs:
- type: ParentStreamConfig
parent_key: encodedKey
partition_field: parentKey
stream:
$ref: "#/definitions/streams/accounts"
incremental_dependency: true
extra_fields:
- ["lastModifiedDate"] # pull this field from the parent record into the slice
Then in your transformations:
transformations:
- type: AddFields
fields:
- type: AddedFieldDefinition
path:
- lastModifiedDate
value: "{{ stream_slice.extra_fields['lastModifiedDate'] }}"
This pattern is used in the Stripe connector, for example with the updated field on `payout_balance_transactions`: [Stripe manifest]
extra_fields:
- ["updated"]
# ...
transformations:
- type: AddFields
fields:
- path:
- updated
value: "{{ stream_slice.extra_fields['updated'] }}"
value_type: integer
The extra_fields property is also documented in the ParentStreamConfig reference as: "Array of field paths to include as additional fields in the stream slice... Accessible via stream_slice.extra_fields. Missing fields are set to None." [ParentStreamConfig reference] 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 10:43 AMkapa.ai
08/20/2026, 10:43 AMParentStreamConfig documentation notes that "Missing fields are set to `None`". [ParentStreamConfig reference]
So first, temporarily add a transformation to output the entire extra_fields object to confirm it's being populated at all:
transformations:
- type: AddFields
fields:
- path:
- debug_extra_fields
value: "{{ stream_slice.extra_fields }}"
If debug_extra_fields shows None or {}, then lastModifiedDate is not being found on the parent record — check that the field name matches exactly (case-sensitive) what the parent accounts stream returns.
2. Check if the field is nested in the parent record extra_fields paths are arrays to support nested access. If lastModifiedDate is nested inside the parent record (e.g. under a sub-object), you'd need to specify the full path:
extra_fields:
- ["someObject", "lastModifiedDate"]
3. Known bug with stream_partition in transformations There is a known bug reported where stream_partition values are not correctly resolved inside transformations. [GitHub issue] While this was reported for stream_partition directly rather than stream_slice.extra_fields, it's worth noting as a potential related issue depending on your Airbyte version.
4. Check your schema Make sure lastModifiedDate is defined in your loan_schedule schema (#/schemas/loan_schedule), otherwise it may be stripped from output records even if the transformation adds it correctly.
Debugging Steps in Order 1. Add the debug_extra_fields transformation above and re-test to confirm the value is present in the slice.
2. Verify the exact field name on the parent accounts stream records.
3. Confirm lastModifiedDate is in your inline schema. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 10:59 AMlastModifiedDate in the schema and hence can't be marked as required.kapa.ai
08/20/2026, 10:59 AMPath [] does not have field 'lastModifiedDate' in the schema and hence can't be marked as required is telling you that lastModifiedDate is missing from your loan_schedule schema definition.
This confirms what was mentioned in the previous debugging step — even if the AddFields transformation is correctly injecting the value, Airbyte validates fields against the schema and the field won't appear in output records if it isn't declared there.
Fix Add lastModifiedDate to your #/schemas/loan_schedule inline schema. Based on the datetime format we identified earlier (%Y-%m-%dT%H:%M:%S%z), it should be declared as a string with a datetime format:
loan_schedule:
type: object
$schema: http://json-schema.org/draft-07/schema#
additionalProperties: true
properties:
encodedKey:
type:
- string
lastModifiedDate:
type:
- "null"
- string
format: date-time
airbyte_type: timestamp_with_timezone
# ... rest of your existing fields
The key points:
• Allow null as a type since extra_fields sets missing fields to None per the docs. [ParentStreamConfig reference]
• Use format: date-time and airbyte_type: timestamp_with_timezone to match the ISO 8601 format with UTC offset that this field contains.
After adding this to the schema, re-run the test and lastModifiedDate should appear in the output records. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 11:00 AMtransformations:
- type: AddFields
fields:
- path:
- debug_extra_fields
value: "{{ stream_slice.extra_fields }}"
no field called debug_extra_fields appeared in the outputkapa.ai
08/20/2026, 11:01 AMextra_fields specifically but with the transformations not being applied at all to the output records.
The knowledge sources do not explicitly document why this would happen, but based on what they do contain, here are the most likely causes:
Things to Check 1. Verify debug_extra_fields is in your schema As we just established, fields not declared in the schema won't appear in output records. Make sure you temporarily add it to your schema:
debug_extra_fields:
type:
- "null"
- string
2. Try a fully static value first To isolate whether transformations are working at all, try the simplest possible case:
transformations:
- type: AddFields
fields:
- path:
- test_field
value: "hello"
If test_field: "hello" does not appear in output records, then transformations are not being applied to this stream at all, which points to a configuration issue with where transformations is placed in your YAML — it must be a direct property of the DeclarativeStream, not nested inside retriever or elsewhere. [Record Selector docs]
The correct placement is:
loan_schedule:
type: DeclarativeStream
name: loan_schedule
primary_key:
- encodedKey
retriever:
...
incremental_sync:
...
transformations: # must be at this level, sibling to retriever
- type: AddFields
fields:
- path:
- test_field
value: "hello"
schema_loader:
...
Can you confirm where transformations is currently placed in your full stream config? 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 11:03 AMloan_schedule:
type: DeclarativeStream
name: loan_schedule
primary_key:
- encodedKey
retriever:
type: SimpleRetriever
requester:
$ref: "#/definitions/base_requester"
path: /loans/{{ stream_partition.parentKey }}/schedule
http_method: GET
request_parameters:
detailsLevel: FULL
request_headers:
Accept: application/vnd.mambu.v2+json
record_selector:
type: RecordSelector
extractor:
type: DpathExtractor
field_path:
- installments
partition_router:
type: SubstreamPartitionRouter
parent_stream_configs:
- type: ParentStreamConfig
parent_key: encodedKey
partition_field: parentKey
stream:
$ref: "#/definitions/streams/accounts"
incremental_dependency: true
extra_fields:
- - lastModifiedDate
incremental_sync:
type: DatetimeBasedCursor
cursor_field: lastModifiedDate
cursor_datetime_formats:
- "%Y-%m-%dT%H:%M:%S%z"
datetime_format: "%Y-%m-%d"
start_datetime:
type: MinMaxDatetime
datetime: "{{ config[\"start_date\"] }}"
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
global_substream_cursor: true
transformations:
- type: AddFields
fields:
- path:
- parent_key
value: "{{ stream_slice.parentKey }}"
- path:
- debug_extra_fields
value: "{{ stream_slice.extra_fields }}"
schema_loader:
type: InlineSchemaLoader
schema:
$ref: "#/schemas/loan_schedule"
The parent_key field in the AddFields transformation DOES appear in the output, but debug_extra_fields doe snotkapa.ai
08/20/2026, 11:03 AMparent_key appears but debug_extra_fields does not, we can confirm that:
1. ✅ Transformations are being applied correctly
2. ✅ The transformation placement is correct
3. ❌ stream_slice.extra_fields is specifically not resolving
The most likely cause is that lastModifiedDate is not being found on the parent accounts stream records, and since the ParentStreamConfig docs state "Missing fields are set to `None`", the field is None and not rendering. [ParentStreamConfig reference]
Debugging Steps 1. Verify the exact field name on the parent stream Go to your accounts stream in the Connector Builder and run a test. Look at the raw output records and confirm:
• Is the field called exactly lastModifiedDate (case-sensitive)?
• Or is it something like lastModifiedDate, last_modified_date, updatedAt etc.?
2. Try outputting the full stream_slice to see what's available transformations:
- type: AddFields
fields:
- path:
- debug_slice
value: "{{ stream_slice }}"
This will show you the entire slice object including what extra_fields actually contains, which will confirm whether the field is being passed through at all.
Once you confirm the exact field name from the parent records, update extra_fields accordingly:
extra_fields:
- ["exactFieldNameHere"] 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 11:04 AM"debug_slice": {
"parentKey": "8a19af999d8fbc13019d90de87ab46a7",
"start_time": "2026-08-10",
"end_time": "2026-08-20"
}kapa.ai
08/20/2026, 11:04 AMdebug_slice output reveals the problem clearly — extra_fields is not present in the slice at all. The slice only contains parentKey, start_time, and end_time, which means the extra_fields mechanism is not picking up lastModifiedDate from the parent records.
This confirms that lastModifiedDate is not a top-level field on the parent accounts stream records as returned, or the field name doesn't match exactly.
Next Step Go to your accounts stream in the Connector Builder, run a test, and inspect a raw output record carefully. You are looking for:
1. The exact field name (case-sensitive) for the last modified date
2. Whether it is nested inside a sub-object rather than at the top level
If it is nested, for example:
{
"_lastModifiedDate": "2026-08-10T10:26:11+01:00",
"someObject": {
"lastModifiedDate": "2026-08-10T10:26:11+01:00"
}
}
Then your extra_fields path needs to reflect that nesting:
extra_fields:
- ["someObject", "lastModifiedDate"]
The ParentStreamConfig docs confirm that extra_fields paths are arrays of strings to support nested field access. [ParentStreamConfig reference]
Once you find the correct field name/path in the parent records, share it here and we can update the config accordingly. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 11:08 AM{
"encodedKey": "8a19af999d8fbc13019d90de87ab46a7",
"id": "DJBC713",
"accountHolderType": "CLIENT",
"accountHolderKey": "8a19af999d8fbc13019d90dec8ad473a",
"creationDate": "2026-04-15T15:51:51+01:00",
"approvedDate": "2026-04-15T15:51:59+01:00",
"lastModifiedDate": "2026-08-10T10:26:11+01:00",
"activationTransactionKey": "8a19dab89d8fb261019d91a0b6287476",
"closedDate": "2026-06-15T15:18:10+01:00",
"lastAccountAppraisalDate": "2026-06-15T00:54:32+01:00",
"accountState": "CLOSED",
"accountSubState": "REPAID",
"productTypeKey": "8a1924ca9d66fd3e019d677f02d80a1c",
"loanName": "Unsecured Lending",
"loanAmount": 120000,
"paymentMethod": "HORIZONTAL",
"accruedInterest": 0,
"interestFromArrearsAccrued": 0,
"lastInterestAppliedDate": "2026-06-15T15:17:59+01:00",
"accruedPenalty": 0,
"allowOffset": false,
"arrearsTolerancePeriod": 0,
"accountArrearsSettings": {
"encodedKey": "8a19af999d8fbc13019d919bd21e62a1",
"toleranceCalculationMethod": "ARREARS_TOLERANCE_PERIOD",
"dateCalculationMethod": "ACCOUNT_FIRST_WENT_TO_ARREARS",
"nonWorkingDaysMethod": "INCLUDED",
"tolerancePeriod": 0
},
"latePaymentsRecalculationMethod": "OVERDUE_INSTALLMENTS_INCREASE",
"balances": {
"redrawBalance": 0,
"principalDue": 0,
"principalPaid": 120000,
"principalBalance": 0,
"interestDue": 0,
"interestPaid": 1843.96,
"interestBalance": 0,
"interestFromArrearsBalance": 0,
"interestFromArrearsDue": 0,
"interestFromArrearsPaid": 27.87,
"feesDue": 0,
"feesPaid": 0,
"feesBalance": 0,
"penaltyDue": 0,
"penaltyPaid": 0,
"penaltyBalance": 0,
"holdBalance": 0
},
"disbursementDetails": {
"encodedKey": "8a19af999d8fbc13019d919bd21e62a0",
"expectedDisbursementDate": "2026-03-11T00:00:00Z",
"disbursementDate": "2026-03-11T00:00:00Z",
"firstRepaymentDate": "2026-04-11T00:00:00+01:00",
"transactionDetails": {
"encodedKey": "8a19af999d8fbc13019d90de87ab46a8",
"transactionChannelKey": "8a19596d9d369739019d3eea893435b3",
"transactionChannelId": "DISB-US",
"internalTransfer": false
}
},
"prepaymentSettings": {
"prepaymentRecalculationMethod": "REDUCE_AMOUNT_PER_INSTALLMENT",
"principalPaidInstallmentStatus": "PAID",
"applyInterestOnPrepaymentMethod": "AUTOMATIC"
},
"penaltySettings": {
"loanPenaltyCalculationMethod": "NONE"
},
"scheduleSettings": {
"hasCustomSchedule": true,
"principalRepaymentInterval": 1,
"gracePeriod": 0,
"gracePeriodType": "NONE",
"repaymentInstallments": 24,
"shortMonthHandlingMethod": "LAST_DAY_IN_MONTH",
"fixedDaysOfMonth": [
11
],
"repaymentPeriodCount": 0,
"scheduleDueDatesMethod": "FIXED_DAYS_OF_MONTH",
"periodicPayment": 0,
"repaymentPeriodUnit": "DAYS",
"repaymentScheduleMethod": "DYNAMIC"
},
"interestSettings": {
"interestRateSource": "FIXED_INTEREST_RATE",
"accrueInterestAfterMaturity": false,
"interestApplicationMethod": "REPAYMENT_DUE_DATE",
"interestBalanceCalculationMethod": "ONLY_PRINCIPAL",
"interestCalculationMethod": "DECLINING_BALANCE_DISCOUNTED",
"interestChargeFrequency": "ANNUALIZED",
"interestRate": 6,
"interestType": "SIMPLE_INTEREST",
"accrueLateInterest": true
},
"futurePaymentsAcceptance": "NO_FUTURE_PAYMENTS",
"currency": {
"currencyCode": "GBP",
"code": "GBP"
},
"allowAdvanceRepayment": false,
"_selinaCollectionBankAccount": {
"collectionAccountNumber": "987665433",
"collectionSortCode": "11-22-34",
"collectionAccountName": "Collection Account"
},
"_selinaApplication": {
"reference": "US123456",
"appId": "hello1234"
},
"_selinaCustomerBankAccount": {
"customerSortCode": "11-22-33",
"customerAccountHolderName": "Elle Woods",
"customerAccountNumber": "123456"
}
}kapa.ai
08/20/2026, 11:09 AMlastModifiedDate is a top-level field on the parent record, so the field name and path are correct. The issue must be elsewhere.
Looking at the raw record, I notice that your accounts stream likely has transformations applied that restructure the raw API response into this clean output. The key question is: does lastModifiedDate exist at the top level of the raw API response, or is it added by a transformation?
extra_fields pulls fields from the raw parent record before transformations are applied. So if lastModifiedDate is added to the accounts stream via an AddFields transformation, it won't be available to extra_fields.
Check Your accounts Stream Config Look at your accounts stream definition and check:
1. Is lastModifiedDate returned directly by the API, or is it added via a transformation like:
transformations:
- type: AddFields
fields:
- path:
- lastModifiedDate
value: '{{ record["lastModifiedDate"] }}'
2. Is there a DpathExtractor with a field_path that unwraps the record from a nested object? If so, lastModifiedDate may live at a different path in the raw response.
Workaround if Transformations are the Issue If lastModifiedDate is indeed added by a transformation on the parent stream, the knowledge sources do not explicitly document a solution for this. The safest workaround would be to not rely on extra_fields and instead make a note of the parent's cursor value differently — for example, by checking whether the raw API response for the /loans/{id}/schedule endpoint itself contains a lastModifiedDate field on the installment records directly.
Can you share what the raw API response looks like for the /loans/{id}/schedule endpoint? That would help determine if the field is available on the child records themselves, removing the need for extra_fields entirely. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 11:12 AM{
"status": 200,
"body": [
{
"encodedKey": "8a19af999d8fbc13019d90de87ab46a7",
"id": "DJBC713",
"accountHolderType": "CLIENT",
"accountHolderKey": "8a19af999d8fbc13019d90dec8ad473a",
"creationDate": "2026-04-15T15:51:51+01:00",
"approvedDate": "2026-04-15T15:51:59+01:00",
"lastModifiedDate": "2026-08-10T10:26:11+01:00",
"activationTransactionKey": "8a19dab89d8fb261019d91a0b6287476",
"closedDate": "2026-06-15T15:18:10+01:00",
"lastAccountAppraisalDate": "2026-06-15T00:54:32+01:00",
"accountState": "CLOSED",
"accountSubState": "REPAID",
"productTypeKey": "8a1924ca9d66fd3e019d677f02d80a1c",
"loanName": "Unsecured Lending",
"loanAmount": 120000,
"paymentMethod": "HORIZONTAL",
"notes": "",
"accruedInterest": 0,
"interestFromArrearsAccrued": 0,
"lastInterestAppliedDate": "2026-06-15T15:17:59+01:00",
"accruedPenalty": 0,
"allowOffset": false,
"arrearsTolerancePeriod": 0,
"accountArrearsSettings": {
"encodedKey": "8a19af999d8fbc13019d919bd21e62a1",
"toleranceCalculationMethod": "ARREARS_TOLERANCE_PERIOD",
"dateCalculationMethod": "ACCOUNT_FIRST_WENT_TO_ARREARS",
"nonWorkingDaysMethod": "INCLUDED",
"tolerancePeriod": 0
},
"latePaymentsRecalculationMethod": "OVERDUE_INSTALLMENTS_INCREASE",
"balances": {
"redrawBalance": 0,
"principalDue": 0,
"principalPaid": 120000,
"principalBalance": 0,
"interestDue": 0,
"interestPaid": 1843.96,
"interestBalance": 0,
"interestFromArrearsBalance": 0,
"interestFromArrearsDue": 0,
"interestFromArrearsPaid": 27.87,
"feesDue": 0,
"feesPaid": 0,
"feesBalance": 0,
"penaltyDue": 0,
"penaltyPaid": 0,
"penaltyBalance": 0,
"holdBalance": 0
},
"disbursementDetails": {
"encodedKey": "8a19af999d8fbc13019d919bd21e62a0",
"expectedDisbursementDate": "2026-03-11T00:00:00Z",
"disbursementDate": "2026-03-11T00:00:00Z",
"firstRepaymentDate": "2026-04-11T00:00:00+01:00",
"transactionDetails": {
"encodedKey": "8a19af999d8fbc13019d90de87ab46a8",
"transactionChannelKey": "8a19596d9d369739019d3eea893435b3",
"transactionChannelId": "DISB-US",
"internalTransfer": false
},
"fees": []
},
"prepaymentSettings": {
"prepaymentRecalculationMethod": "REDUCE_AMOUNT_PER_INSTALLMENT",
"principalPaidInstallmentStatus": "PAID",
"applyInterestOnPrepaymentMethod": "AUTOMATIC"
},
"penaltySettings": {
"loanPenaltyCalculationMethod": "NONE"
},
"scheduleSettings": {
"hasCustomSchedule": true,
"principalRepaymentInterval": 1,
"gracePeriod": 0,
"gracePeriodType": "NONE",
"repaymentInstallments": 24,
"shortMonthHandlingMethod": "LAST_DAY_IN_MONTH",
"fixedDaysOfMonth": [
11
],
"repaymentPeriodCount": 0,
"scheduleDueDatesMethod": "FIXED_DAYS_OF_MONTH",
"periodicPayment": 0,
"repaymentPeriodUnit": "DAYS",
"repaymentScheduleMethod": "DYNAMIC",
"paymentPlan": []
},
"interestSettings": {
"interestRateSource": "FIXED_INTEREST_RATE",
"accrueInterestAfterMaturity": false,
"interestApplicationMethod": "REPAYMENT_DUE_DATE",
"interestBalanceCalculationMethod": "ONLY_PRINCIPAL",
"interestCalculationMethod": "DECLINING_BALANCE_DISCOUNTED",
"interestChargeFrequency": "ANNUALIZED",
"interestRate": 6,
"interestType": "SIMPLE_INTEREST",
"accrueLateInterest": true
},
"feesSettings": {},
"assets": [],
"guarantors": [],
"fundingSources": [],
"tranches": [],
"futurePaymentsAcceptance": "NO_FUTURE_PAYMENTS",
"currency": {
"currencyCode": "GBP",
"code": "GBP"
},
"plannedInstallmentFees": [],
"allowAdvanceRepayment": false,
"_selinaCollectionBankAccount": {
"collectionAccountNumber": "987665433",
"collectionSortCode": "11-22-34",
"collectionAccountName": "Collection Account"
},
"_selinaApplication": {
"reference": "US123456",
"appId": "hello1234"
},
"_selinaCustomerBankAccount": {
"customerSortCode": "11-22-33",
"customerAccountHolderName": "Elle Woods",
"customerAccountNumber": "123456"
}
}kapa.ai
08/20/2026, 11:12 AMlastModifiedDate is definitely a top-level field in the raw response, so the extra_fields path is correct. This is puzzling.
Looking at your debug_slice output again:
{
"parentKey": "8a19af999d8fbc13019d90de87ab46a7",
"start_time": "2026-08-10",
"end_time": "2026-08-20"
}
Notice there is no extra_fields key at all in the slice. This suggests the extra_fields feature may not be functioning as expected in your version of the CDK.
Check Your accounts Stream's record_selector The most likely remaining cause is your accounts stream's DpathExtractor. Looking at the raw response, the records are wrapped in an array at the root:
{
"status": 200,
"body": [{ ... }]
}
Can you check what field_path your accounts stream's extractor uses? If it is extracting from a nested path like ["body"], the extra_fields mechanism should still work on the extracted record. But if there is any mismatch, it could explain why the field isn't found.
Pragmatic Workaround Since stream_slice.parentKey is working correctly, and parentKey is the encodedKey of the parent record, you could work around the extra_fields issue entirely by making a separate API call to fetch the parent's lastModifiedDate — but that would be inefficient.
A simpler workaround given the knowledge sources don't explain why extra_fields isn't populating, is to raise this as a bug on the Airbyte GitHub with your manifest and the debug_slice output as evidence, since the expected behaviour per the docs is that extra_fields should appear under stream_slice.extra_fields. [ParentStreamConfig reference]
In the meantime, could you share your accounts stream config, specifically the record_selector section? That would help narrow down whether the extractor path is causing extra_fields to fail to locate the field. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 11:14 AMaccounts:
type: DeclarativeStream
name: accounts
primary_key:
- encodedKey
retriever:
type: SimpleRetriever
requester:
$ref: "#/definitions/base_requester"
path: /loans%3Asearch
http_method: POST
request_parameters:
detailsLevel: FULL
request_headers:
Accept: application/vnd.mambu.v2+json
Content-Type: application/json
request_body_json:
filterCriteria:
- field: lastModifiedDate
value: "{{ stream_interval.start_time }}"
operator: AFTER_INCLUSIVE
sortingCriteria:
field: lastModifiedDate
order: ASC
record_selector:
type: RecordSelector
extractor:
type: DpathExtractor
field_path: []
incremental_sync:
type: DatetimeBasedCursor
cursor_field: lastModifiedDate
cursor_datetime_formats:
- "%Y-%m-%dT%H:%M:%S%z"
datetime_format: "%Y-%m-%d"
start_datetime:
type: MinMaxDatetime
datetime: "{{ config[\"start_date\"] }}"
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
schema_loader:
type: InlineSchemaLoader
schema:
$ref: "#/schemas/accounts"kapa.ai
08/20/2026, 11:14 AMaccounts stream uses:
field_path: []
This means the extractor treats the entire response body as the record array with no unwrapping. This is fine for record extraction, but it may be the reason extra_fields isn't working — the CDK may not be correctly locating fields when field_path is empty ([]).
However, I want to be honest: the knowledge sources do not explicitly document how extra_fields interacts with an empty field_path, so I cannot say this with full certainty.
Most Pragmatic Workaround Since you can't get extra_fields working right now, and given that stream_slice.parentKey does work, you could use the parentKey (which is the encodedKey) as a proxy cursor for the child stream instead of lastModifiedDate. The logic being: if a parent record appeared in the incremental sync, it was modified after the last cursor, so its schedule needs refreshing.
Update your loan_schedule incremental sync to use encodedKey as the cursor field:
incremental_sync:
type: DatetimeBasedCursor
cursor_field: lastModifiedDate
cursor_datetime_formats:
- "%Y-%m-%dT%H:%M:%S%z"
datetime_format: "%Y-%m-%dT%H:%M:%S%z"
start_datetime:
type: MinMaxDatetime
datetime: "{{ config[\"start_date\"] }}"
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
global_substream_cursor: true
And inject the parent's lastModifiedDate via the transformation using stream_slice.parentKey to look it up — except that's circular.
Recommended Next Step Given the uncertainty, I'd suggest raising this as a bug on the Airbyte CDK GitHub with:
• Your loan_schedule stream config
• Your accounts stream config
• The debug_slice output showing extra_fields is absent
The extra_fields feature should work per the docs [ParentStreamConfig reference], and the empty field_path: [] interaction is the most suspicious difference between your setup and the expected behaviour. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.Stuart Horgan
08/20/2026, 11:29 AMkapa.ai
08/20/2026, 11:29 AMextra_fields support, so I cannot give you a reliable version number to check against.
What I can suggest is:
1. Check the Airbyte CDK changelog at github.com/airbytehq/airbyte-python-cdk/releases and search for extra_fields to find when it was introduced.
2. Check your current CDK version — in the Connector Builder, the manifest has a version field at the top. You can compare this against the CDK changelog to see if extra_fields was available at that version.
3. Check your Airbyte platform version — if you are self-hosting with abctl, run:abctl local statusto see your current platform version, then check the Airbyte releases page to see if an update is available.
Given that your debug_slice shows no extra_fields key at all rather than a None value, a version gap is a plausible explanation. Updating both the platform and the CDK version declared in your manifest would be a reasonable thing to try. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.