diff --git a/airbyte-config/init/src/main/resources/icons/everhour.svg b/airbyte-config/init/src/main/resources/icons/everhour.svg
new file mode 100644
index 000000000000..f3ecad7f052f
--- /dev/null
+++ b/airbyte-config/init/src/main/resources/icons/everhour.svg
@@ -0,0 +1,37 @@
+
+
+
diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml
index 5f584c9ca32a..fcc40eef4842 100644
--- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml
+++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml
@@ -539,6 +539,17 @@
hosts:
- "${subdomain}.apilayer.com"
- apilayer.com
+- name: Everhour
+ sourceDefinitionId: 6babfc42-c734-4ef6-a817-6eca15f0f9b7
+ dockerRepository: airbyte/source-everhour
+ dockerImageTag: 0.1.0
+ documentationUrl: https://docs.airbyte.com/integrations/sources/everhour
+ icon: everhour.svg
+ sourceType: api
+ releaseStage: alpha
+ allowedHosts:
+ hosts:
+ - api.everhour.com
- name: Facebook Marketing
sourceDefinitionId: e7778cfc-e97c-4458-9ecb-b4f2bba8946c
dockerRepository: airbyte/source-facebook-marketing
diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml
index cca5cc592a01..ad8dd71805a7 100644
--- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml
+++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml
@@ -3789,6 +3789,25 @@
supportsNormalization: false
supportsDBT: false
supported_destination_sync_modes: []
+- dockerImage: "airbyte/source-everhour:0.1.0"
+ spec:
+ documentationUrl: "https://docs.airbyte.io/integrations/sources/everhour"
+ connectionSpecification:
+ title: "Everhour Spec"
+ type: "object"
+ required:
+ - "api_key"
+ additionalProperties: true
+ properties:
+ api_key:
+ type: "string"
+ title: "API Key"
+ description: "Everhour API Key. See the docs for information on how to generate this key."
+ airbyte_secret: true
+ supportsNormalization: false
+ supportsDBT: false
+ supported_destination_sync_modes: []
- dockerImage: "airbyte/source-facebook-marketing:0.3.0"
spec:
documentationUrl: "https://docs.airbyte.com/integrations/sources/facebook-marketing"
diff --git a/airbyte-integrations/builds.md b/airbyte-integrations/builds.md
index 69e25e8c74eb..2aa233fd3d4d 100644
--- a/airbyte-integrations/builds.md
+++ b/airbyte-integrations/builds.md
@@ -189,4 +189,4 @@
| S3 | [![destination-s3](https://img.shields.io/endpoint?url=https%3A%2F%2Fdnsgjos7lj2fu.cloudfront.net%2Ftests%2Fsummary%2Fdestination-s3%2Fbadge.json)](https://dnsgjos7lj2fu.cloudfront.net/tests/summary/connectors/destination-s3) |
| Scylla | [![destination-scylla](https://img.shields.io/endpoint?url=https%3A%2F%2Fdnsgjos7lj2fu.cloudfront.net%2Ftests%2Fsummary%2Fdestination-s3%2Fbadge.json)](https://dnsgjos7lj2fu.cloudfront.net/tests/summary/connectors/destination-scylla) |
| SFTP-JSON | [![destination-sftp-json](https://img.shields.io/endpoint?url=https%3A%2F%2Fdnsgjos7lj2fu.cloudfront.net%2Ftests%2Fsummary%2Fdestination-sftp-json%2Fbadge.json)](https://dnsgjos7lj2fu.cloudfront.net/tests/summary/connectors/destination-sftp-json) |
-| Snowflake | [![destination-snowflake](https://img.shields.io/endpoint?url=https%3A%2F%2Fdnsgjos7lj2fu.cloudfront.net%2Ftests%2Fsummary%2Fdestination-snowflake%2Fbadge.json)](https://dnsgjos7lj2fu.cloudfront.net/tests/summary/connectors/destination-snowflake) |\
+| Snowflake | [![destination-snowflake](https://img.shields.io/endpoint?url=https%3A%2F%2Fdnsgjos7lj2fu.cloudfront.net%2Ftests%2Fsummary%2Fdestination-snowflake%2Fbadge.json)](https://dnsgjos7lj2fu.cloudfront.net/tests/summary/connectors/destination-snowflake) |\
\ No newline at end of file
diff --git a/airbyte-integrations/connectors/source-everhour/.dockerignore b/airbyte-integrations/connectors/source-everhour/.dockerignore
new file mode 100644
index 000000000000..97e5496eb23b
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/.dockerignore
@@ -0,0 +1,6 @@
+*
+!Dockerfile
+!main.py
+!source_everhour
+!setup.py
+!secrets
diff --git a/airbyte-integrations/connectors/source-everhour/Dockerfile b/airbyte-integrations/connectors/source-everhour/Dockerfile
new file mode 100644
index 000000000000..63279a56c257
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/Dockerfile
@@ -0,0 +1,38 @@
+FROM python:3.9.11-alpine3.15 as base
+
+# build and load all requirements
+FROM base as builder
+WORKDIR /airbyte/integration_code
+
+# upgrade pip to the latest version
+RUN apk --no-cache upgrade \
+ && pip install --upgrade pip \
+ && apk --no-cache add tzdata build-base
+
+
+COPY setup.py ./
+# install necessary packages to a temporary folder
+RUN pip install --prefix=/install .
+
+# build a clean environment
+FROM base
+WORKDIR /airbyte/integration_code
+
+# copy all loaded and built libraries to a pure basic image
+COPY --from=builder /install /usr/local
+# add default timezone settings
+COPY --from=builder /usr/share/zoneinfo/Etc/UTC /etc/localtime
+RUN echo "Etc/UTC" > /etc/timezone
+
+# bash is installed for more convenient debugging.
+RUN apk --no-cache add bash
+
+# copy payload code only
+COPY main.py ./
+COPY source_everhour ./source_everhour
+
+ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py"
+ENTRYPOINT ["python", "/airbyte/integration_code/main.py"]
+
+LABEL io.airbyte.version=0.1.0
+LABEL io.airbyte.name=airbyte/source-everhour
diff --git a/airbyte-integrations/connectors/source-everhour/README.md b/airbyte-integrations/connectors/source-everhour/README.md
new file mode 100644
index 000000000000..2a03a5f160a0
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/README.md
@@ -0,0 +1,79 @@
+# Everhour Source
+
+This is the repository for the Everhour configuration based source connector.
+For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.io/integrations/sources/everhour).
+
+## Local development
+
+#### Building via Gradle
+You can also build the connector in Gradle. This is typically used in CI and not needed for your development workflow.
+
+To build using Gradle, from the Airbyte repository root, run:
+```
+./gradlew :airbyte-integrations:connectors:source-everhour:build
+```
+
+#### Create credentials
+**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/everhour)
+to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_everhour/spec.yaml` file.
+Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information.
+See `integration_tests/sample_config.json` for a sample config file.
+
+**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source everhour test creds`
+and place them into `secrets/config.json`.
+
+### Locally running the connector docker image
+
+#### Build
+First, make sure you build the latest Docker image:
+```
+docker build . -t airbyte/source-everhour:dev
+```
+
+You can also build the connector image via Gradle:
+```
+./gradlew :airbyte-integrations:connectors:source-everhour:airbyteDocker
+```
+When building via Gradle, the docker image name and tag, respectively, are the values of the `io.airbyte.name` and `io.airbyte.version` `LABEL`s in
+the Dockerfile.
+
+#### Run
+Then run any of the connector commands as follows:
+```
+docker run --rm airbyte/source-everhour:dev spec
+docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-everhour:dev check --config /secrets/config.json
+docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-everhour:dev discover --config /secrets/config.json
+docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-everhour:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json
+```
+## Testing
+
+#### Acceptance Tests
+Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information.
+If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py.
+
+To run your integration tests with docker
+
+### Using gradle to run tests
+All commands should be run from airbyte project root.
+To run unit tests:
+```
+./gradlew :airbyte-integrations:connectors:source-everhour:unitTest
+```
+To run acceptance and custom integration tests:
+```
+./gradlew :airbyte-integrations:connectors:source-everhour:integrationTest
+```
+
+## Dependency Management
+All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development.
+We split dependencies between two groups, dependencies that are:
+* required for your connector to work need to go to `MAIN_REQUIREMENTS` list.
+* required for the testing need to go to `TEST_REQUIREMENTS` list
+
+### Publishing a new version of the connector
+You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what?
+1. Make sure your changes are passing unit and integration tests.
+1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use [SemVer](https://semver.org/)).
+1. Create a Pull Request.
+1. Pat yourself on the back for being an awesome contributor.
+1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master.
diff --git a/airbyte-integrations/connectors/source-everhour/__init__.py b/airbyte-integrations/connectors/source-everhour/__init__.py
new file mode 100644
index 000000000000..1100c1c58cf5
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/__init__.py
@@ -0,0 +1,3 @@
+#
+# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
+#
diff --git a/airbyte-integrations/connectors/source-everhour/acceptance-test-config.yml b/airbyte-integrations/connectors/source-everhour/acceptance-test-config.yml
new file mode 100644
index 000000000000..aa77e3c2697c
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/acceptance-test-config.yml
@@ -0,0 +1,27 @@
+# See [Source Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/source-acceptance-tests-reference)
+# for more information about how to configure these tests
+connector_image: airbyte/source-everhour:dev
+acceptance_tests:
+ spec:
+ tests:
+ - spec_path: "source_everhour/spec.yaml"
+ 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"
+ configured_catalog_path: "integration_tests/configured_catalog.json"
+ empty_streams: []
+ incremental:
+ bypass_reason: "This connector does not implement incremental sync"
+ full_refresh:
+ tests:
+ - config_path: "secrets/config.json"
+ configured_catalog_path: "integration_tests/configured_catalog.json"
diff --git a/airbyte-integrations/connectors/source-everhour/acceptance-test-docker.sh b/airbyte-integrations/connectors/source-everhour/acceptance-test-docker.sh
new file mode 100644
index 000000000000..c51577d10690
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/acceptance-test-docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env sh
+
+# Build latest connector image
+docker build . -t $(cat acceptance-test-config.yml | grep "connector_image" | head -n 1 | cut -d: -f2-)
+
+# Pull latest acctest image
+docker pull airbyte/source-acceptance-test:latest
+
+# Run
+docker run --rm -it \
+ -v /var/run/docker.sock:/var/run/docker.sock \
+ -v /tmp:/tmp \
+ -v $(pwd):/test_input \
+ airbyte/source-acceptance-test \
+ --acceptance-test-config /test_input
+
diff --git a/airbyte-integrations/connectors/source-everhour/build.gradle b/airbyte-integrations/connectors/source-everhour/build.gradle
new file mode 100644
index 000000000000..2698346a9377
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/build.gradle
@@ -0,0 +1,9 @@
+plugins {
+ id 'airbyte-python'
+ id 'airbyte-docker'
+ id 'airbyte-connector-acceptance-test'
+}
+
+airbytePython {
+ moduleDirectory 'source_everhour'
+}
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/__init__.py b/airbyte-integrations/connectors/source-everhour/integration_tests/__init__.py
new file mode 100644
index 000000000000..1100c1c58cf5
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/__init__.py
@@ -0,0 +1,3 @@
+#
+# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
+#
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-everhour/integration_tests/abnormal_state.json
new file mode 100644
index 000000000000..52b0f2c2118f
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/abnormal_state.json
@@ -0,0 +1,5 @@
+{
+ "todo-stream-name": {
+ "todo-field-name": "todo-abnormal-value"
+ }
+}
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/acceptance.py b/airbyte-integrations/connectors/source-everhour/integration_tests/acceptance.py
new file mode 100644
index 000000000000..9e6409236281
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/acceptance.py
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
+#
+
+
+import pytest
+
+pytest_plugins = ("connector_acceptance_test.plugin",)
+
+
+@pytest.fixture(scope="session", autouse=True)
+def connector_setup():
+ """This fixture is a placeholder for external resources that acceptance test might require."""
+ # TODO: setup test dependencies if needed. otherwise remove the TODO comments
+ yield
+ # TODO: clean up test dependencies
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/catalog.json b/airbyte-integrations/connectors/source-everhour/integration_tests/catalog.json
new file mode 100644
index 000000000000..6799946a6851
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/catalog.json
@@ -0,0 +1,39 @@
+{
+ "streams": [
+ {
+ "name": "TODO fix this file",
+ "supported_sync_modes": ["full_refresh", "incremental"],
+ "source_defined_cursor": true,
+ "default_cursor_field": "column1",
+ "json_schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "column1": {
+ "type": "string"
+ },
+ "column2": {
+ "type": "number"
+ }
+ }
+ }
+ },
+ {
+ "name": "table1",
+ "supported_sync_modes": ["full_refresh", "incremental"],
+ "source_defined_cursor": false,
+ "json_schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "column1": {
+ "type": "string"
+ },
+ "column2": {
+ "type": "number"
+ }
+ }
+ }
+ }
+ ]
+}
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-everhour/integration_tests/configured_catalog.json
new file mode 100644
index 000000000000..efa74cfa1168
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/configured_catalog.json
@@ -0,0 +1,58 @@
+{
+ "streams": [
+ {
+ "stream": {
+ "name": "projects",
+ "json_schema": {},
+ "supported_sync_modes": ["full_refresh"]
+ },
+ "sync_mode": "full_refresh",
+ "destination_sync_mode": "overwrite"
+ },
+ {
+ "stream": {
+ "name": "clients",
+ "json_schema": {},
+ "supported_sync_modes": ["full_refresh"]
+ },
+ "sync_mode": "full_refresh",
+ "destination_sync_mode": "overwrite"
+ },
+ {
+ "stream": {
+ "name": "time",
+ "json_schema": {},
+ "supported_sync_modes": ["full_refresh"]
+ },
+ "sync_mode": "full_refresh",
+ "destination_sync_mode": "overwrite"
+ },
+ {
+ "stream": {
+ "name": "users",
+ "json_schema": {},
+ "supported_sync_modes": ["full_refresh"]
+ },
+ "sync_mode": "full_refresh",
+ "destination_sync_mode": "overwrite"
+ },
+ {
+ "stream": {
+ "name": "tasks",
+ "json_schema": {},
+ "supported_sync_modes": ["full_refresh"]
+ },
+ "sync_mode": "full_refresh",
+ "destination_sync_mode": "overwrite"
+ },
+ {
+ "stream": {
+ "name": "time_records",
+ "json_schema": {},
+ "supported_sync_modes": ["full_refresh"]
+ },
+ "sync_mode": "full_refresh",
+ "destination_sync_mode": "overwrite"
+ }
+ ]
+}
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-everhour/integration_tests/invalid_config.json
new file mode 100644
index 000000000000..f3732995784f
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/invalid_config.json
@@ -0,0 +1,3 @@
+{
+ "todo-wrong-field": "this should be an incomplete config file, used in standard tests"
+}
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-everhour/integration_tests/sample_config.json
new file mode 100644
index 000000000000..c6bf4f5bca97
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/sample_config.json
@@ -0,0 +1,3 @@
+{
+ "api_key": "API_key"
+}
diff --git a/airbyte-integrations/connectors/source-everhour/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-everhour/integration_tests/sample_state.json
new file mode 100644
index 000000000000..3587e579822d
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/integration_tests/sample_state.json
@@ -0,0 +1,5 @@
+{
+ "todo-stream-name": {
+ "todo-field-name": "value"
+ }
+}
diff --git a/airbyte-integrations/connectors/source-everhour/main.py b/airbyte-integrations/connectors/source-everhour/main.py
new file mode 100644
index 000000000000..8c44913d9ddf
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/main.py
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
+#
+
+
+import sys
+
+from airbyte_cdk.entrypoint import launch
+from source_everhour import SourceEverhour
+
+if __name__ == "__main__":
+ source = SourceEverhour()
+ launch(source, sys.argv[1:])
diff --git a/airbyte-integrations/connectors/source-everhour/requirements.txt b/airbyte-integrations/connectors/source-everhour/requirements.txt
new file mode 100644
index 000000000000..cc57334ef619
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/requirements.txt
@@ -0,0 +1,2 @@
+-e ../../bases/connector-acceptance-test
+-e .
diff --git a/airbyte-integrations/connectors/source-everhour/setup.py b/airbyte-integrations/connectors/source-everhour/setup.py
new file mode 100644
index 000000000000..da7860e6ac55
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/setup.py
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
+#
+
+
+from setuptools import find_packages, setup
+
+MAIN_REQUIREMENTS = [
+ "airbyte-cdk~=0.1",
+]
+
+TEST_REQUIREMENTS = ["pytest~=6.1", "pytest-mock~=3.6.1"]
+
+setup(
+ name="source_everhour",
+ description="Source implementation for Everhour.",
+ author="Airbyte",
+ author_email="contact@airbyte.io",
+ packages=find_packages(),
+ install_requires=MAIN_REQUIREMENTS,
+ package_data={"": ["*.json", "*.yaml", "schemas/*.json", "schemas/shared/*.json"]},
+ extras_require={
+ "tests": TEST_REQUIREMENTS,
+ },
+)
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/__init__.py b/airbyte-integrations/connectors/source-everhour/source_everhour/__init__.py
new file mode 100644
index 000000000000..6cfb804a491c
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/__init__.py
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
+#
+
+
+from .source import SourceEverhour
+
+__all__ = ["SourceEverhour"]
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/everhour.yaml b/airbyte-integrations/connectors/source-everhour/source_everhour/everhour.yaml
new file mode 100644
index 000000000000..068bc7daf58a
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/everhour.yaml
@@ -0,0 +1,91 @@
+version: "0.30.0"
+
+definitions:
+ selector:
+ type: RecordSelector
+ extractor:
+ type: DpathExtractor
+ field_path: []
+ requester:
+ url_base: "https://api.everhour.com"
+ http_method: "GET"
+ authenticator:
+ type: ApiKeyAuthenticator
+ header: "X-Api-Key"
+ api_token: "{{ config['api_key'] }}"
+ retriever:
+ record_selector:
+ $ref: "#/definitions/selector"
+ paginator:
+ type: NoPagination
+ requester:
+ $ref: "#/definitions/requester"
+ base_stream:
+ retriever:
+ $ref: "#/definitions/retriever"
+ projects_stream:
+ $ref: "#/definitions/base_stream"
+ $parameters:
+ name: "projects"
+ primary_key: "id"
+ path: "/projects"
+ tasks_stream:
+ $parameters:
+ name: "tasks"
+ primary_key: "id"
+ retriever:
+ $ref: "#/definitions/retriever"
+ requester:
+ $ref: "#/definitions/requester"
+ path: "projects/{{ stream_slice.parent_id }}/tasks"
+ partition_router:
+ type: SubstreamPartitionRouter
+ parent_stream_configs:
+ - stream: "#/definitions/projects_stream"
+ parent_key: "id"
+ partition_field: "parent_id"
+ time_records_stream:
+ $parameters:
+ name: "time_records"
+ primary_key: "id"
+ retriever:
+ $ref: "#/definitions/retriever"
+ requester:
+ $ref: "#/definitions/requester"
+ path: "projects/{{ stream_slice.parent_id }}/time"
+ partition_router:
+ type: SubstreamPartitionRouter
+ parent_stream_configs:
+ - stream: "#/definitions/projects_stream"
+ parent_key: "id"
+ partition_field: "parent_id"
+ clients_stream:
+ $ref: "#/definitions/base_stream"
+ $parameters:
+ name: "clients"
+ primary_key: "id"
+ path: "/clients"
+ time_stream:
+ $ref: "#/definitions/base_stream"
+ $parameters:
+ name: "time"
+ primary_key: "id"
+ path: "/team/time"
+ users_stream:
+ $ref: "#/definitions/base_stream"
+ $parameters:
+ name: "users"
+ primary_key: "id"
+ path: "/team/users"
+
+streams:
+ - "#/definitions/projects_stream"
+ - "#/definitions/clients_stream"
+ - "#/definitions/time_stream"
+ - "#/definitions/users_stream"
+ - "#/definitions/tasks_stream"
+ - "#/definitions/time_records_stream"
+
+check:
+ stream_names:
+ - "users"
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/clients.json b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/clients.json
new file mode 100644
index 000000000000..e905f0138d7c
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/clients.json
@@ -0,0 +1,48 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "projects": {
+ "type": ["null", "array"],
+ "items": { "type": "string" }
+ },
+ "id": {
+ "type": ["null", "integer"]
+ },
+ "name": {
+ "type": ["null", "string"]
+ },
+ "createdAt": {
+ "type": ["null", "string"]
+ },
+ "lineItemMask": {
+ "type": ["null", "string"]
+ },
+ "paymentDueDays": {
+ "type": ["null", "integer"]
+ },
+ "reference": {
+ "type": ["null", "string"]
+ },
+ "businessDetails": {
+ "type": ["null", "string"]
+ },
+ "invoicePublicNotes": {
+ "type": ["null", "string"]
+ },
+ "excludedLabels": {
+ "type": ["null", "array"],
+ "items": { "type": "string" }
+ },
+ "status": {
+ "type": ["null", "string"]
+ },
+ "enableResourcePlanner": {
+ "type": ["null", "boolean"]
+ },
+ "favorite": {
+ "type": ["null", "boolean"]
+ }
+ }
+}
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/projects.json b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/projects.json
new file mode 100644
index 000000000000..c34b10ae2e85
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/projects.json
@@ -0,0 +1,59 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "canSyncTasks": {
+ "type": ["null", "boolean"]
+ },
+ "users": {
+ "type": ["null", "array"],
+ "items": { "type": "integer" }
+ },
+ "id": {
+ "type": ["null", "string"]
+ },
+ "platform": {
+ "type": ["null", "string"]
+ },
+ "name": {
+ "type": ["null", "string"]
+ },
+ "createdAt": {
+ "type": ["null", "string"]
+ },
+ "workspaceId": {
+ "type": ["null", "string"]
+ },
+ "workspaceName": {
+ "type": ["null", "string"]
+ },
+ "foreign": {
+ "type": ["null", "boolean"]
+ },
+ "favorite": {
+ "type": ["null", "boolean"]
+ },
+ "hasWebhook": {
+ "type": ["null", "boolean"]
+ },
+ "status": {
+ "type": ["null", "string"]
+ },
+ "estimatesType": {
+ "type": ["null", "string"]
+ },
+ "isTemplate": {
+ "type": ["null", "boolean"]
+ },
+ "privacy": {
+ "type": ["null", "string"]
+ },
+ "connectionStatus": {
+ "type": ["null", "string"]
+ },
+ "unarchiveDisabledBy": {
+ "type": ["null", "string"]
+ }
+ }
+}
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/tasks.json b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/tasks.json
new file mode 100644
index 000000000000..2d74aaf95067
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/tasks.json
@@ -0,0 +1,63 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "iteration": {
+ "type": "string"
+ },
+ "projects": {
+ "type": "array",
+ "items": {"type": "string"}
+ },
+ "createdAt": {
+ "type": "string"
+ },
+ "dueOn": {
+ "type": "string"
+ },
+ "labels": {
+ "type": "array",
+ "items": {"type": "string"}
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "integer"
+ },
+ "users": {
+ "type": ["null", "object"]
+ },
+ "timerTime": {
+ "type": "integer"
+ }
+ }
+ },
+ "completed": {
+ "type": "boolean"
+ },
+ "completedAt": {
+ "type": "string"
+ },
+ "assignees": {
+ "type": "array",
+ "items": {"type": "string"}
+ }
+ }
+ }
\ No newline at end of file
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/time.json b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/time.json
new file mode 100644
index 000000000000..4dff2f42bb8f
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/time.json
@@ -0,0 +1,102 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "id": {
+ "type": ["null", "integer"]
+ },
+ "date": {
+ "type": ["null", "string"]
+ },
+ "createdAt": {
+ "type": ["null", "string"]
+ },
+ "user": {
+ "type": ["null", "integer"]
+ },
+ "time": {
+ "type": ["null", "integer"]
+ },
+ "task": {
+ "type": ["null", "object"],
+ "properties": {
+ "id": {
+ "type": ["null", "string"]
+ },
+ "name": {
+ "type": ["null", "string"]
+ },
+ "type": {
+ "type": ["null", "string"]
+ },
+ "status": {
+ "type": ["null", "string"]
+ },
+ "url": {
+ "type": ["null", "string"]
+ },
+ "iteration": {
+ "type": ["null", "string"]
+ },
+ "projects": {
+ "type": ["null", "array"],
+ "items": { "type": "string" }
+ },
+ "createdAt": {
+ "type": ["null", "string"]
+ },
+ "labels": {
+ "type": ["null", "array"],
+ "items": { "type": "string" }
+ },
+ "time": {
+ "type": ["null", "object"],
+ "properties": {
+ "total": {
+ "type": ["null", "integer"]
+ },
+ "users": {
+ "type": ["null", "object"],
+ "properties": {
+ "1029023": {
+ "type": ["null", "integer"]
+ }
+ }
+ },
+ "timerTime": {
+ "type": ["null", "integer"]
+ }
+ }
+ },
+ "completed": {
+ "type": ["null", "boolean"]
+ },
+ "assignees": {
+ "type": ["null", "array"],
+ "items": { "type": "string" }
+ }
+ }
+ },
+ "history": {
+ "type": ["null", "array"],
+ "items": {
+ "type": ["null", "object"],
+ "additionalProperties": true
+ }
+ },
+ "lockReasons": {
+ "type": ["null", "array"],
+ "items": { "type": "string" }
+ },
+ "isLocked": {
+ "type": ["null", "boolean"]
+ },
+ "cost": {
+ "type": ["null", "integer"]
+ },
+ "costRate": {
+ "type": ["null", "integer"]
+ }
+ }
+}
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/time_records.json b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/time_records.json
new file mode 100644
index 000000000000..231f10a75164
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/time_records.json
@@ -0,0 +1,85 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "id": {
+ "type": ["null", "integer"]
+ },
+ "date": {
+ "type": ["null", "string"]
+ },
+ "createdAt": {
+ "type": ["null", "string"]
+ },
+ "user": {
+ "type": ["null", "integer"]
+ },
+ "time": {
+ "type": ["null", "integer"]
+ },
+ "task": {
+ "type": ["null", "object"],
+ "properties": {
+ "id": {
+ "type": ["null", "string"]
+ },
+ "name": {
+ "type": ["null", "string"]
+ },
+ "type": {
+ "type": ["null", "string"]
+ },
+ "status": {
+ "type": ["null", "string"]
+ },
+ "url": {
+ "type": ["null", "string"]
+ },
+ "iteration": {
+ "type": ["null", "string"]
+ },
+ "projects": {
+ "type": ["null", "array"],
+ "items": {}
+ },
+ "createdAt": {
+ "type": ["null", "string"]
+ },
+ "labels": {
+ "type": ["null", "array"],
+ "items": {}
+ },
+ "time": {
+ "type": ["null", "object"],
+ "properties": {
+ "total": {
+ "type": ["null", "integer"]
+ },
+ "users": {
+ "type": ["null", "object"],
+ "properties": {
+ "1029023": {
+ "type": ["null", "integer"]
+ },
+ "1163985": {
+ "type": ["null", "integer"]
+ }
+ }
+ },
+ "timerTime": {
+ "type": ["null", "integer"]
+ }
+ }
+ },
+ "completed": {
+ "type": ["null", "boolean"]
+ },
+ "assignees": {
+ "type": ["null", "array"],
+ "items": {}
+ }
+ }
+ }
+ }
+}
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/users.json b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/users.json
new file mode 100644
index 000000000000..b078ec8c169a
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/schemas/users.json
@@ -0,0 +1,103 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "isEmailVerified": {
+ "type": ["null", "boolean"]
+ },
+ "resourcePlannerAccess": {
+ "type": ["null", "object"],
+ "properties": {
+ "viewMine": {
+ "type": ["null", "boolean"]
+ },
+ "editMine": {
+ "type": ["null", "boolean"]
+ },
+ "viewAll": {
+ "type": ["null", "boolean"]
+ },
+ "editAll": {
+ "type": ["null", "boolean"]
+ }
+ }
+ },
+ "timeTrackingPolicy": {
+ "type": ["null", "object"],
+ "properties": {
+ "allowTimeWithoutTask": {
+ "type": ["null", "boolean"]
+ },
+ "allowManualTimeInput": {
+ "type": ["null", "boolean"]
+ },
+ "allowFutureTime": {
+ "type": ["null", "boolean"]
+ },
+ "allowTimeWithoutEstimate": {
+ "type": ["null", "boolean"]
+ },
+ "allowExceedEstimate": {
+ "type": ["null", "boolean"]
+ },
+ "allowManageEstimates": {
+ "type": ["null", "boolean"]
+ }
+ }
+ },
+ "avatarUrl": {
+ "type": ["null", "string"]
+ },
+ "avatarUrlLarge": {
+ "type": ["null", "string"]
+ },
+ "id": {
+ "type": ["null", "integer"]
+ },
+ "email": {
+ "type": ["null", "string"]
+ },
+ "name": {
+ "type": ["null", "string"]
+ },
+ "headline": {
+ "type": ["null", "string"]
+ },
+ "createdAt": {
+ "type": ["null", "string"]
+ },
+ "groups": {
+ "type": ["null", "array"],
+ "items": { "type": "string" }
+ },
+ "status": {
+ "type": ["null", "string"]
+ },
+ "role": {
+ "type": ["null", "string"]
+ },
+ "type": {
+ "type": ["null", "string"]
+ },
+ "costHistory": {
+ "type": ["null", "array"],
+ "items": { "type": "object" }
+ },
+ "rate": {
+ "type": ["null", "integer"]
+ },
+ "cost": {
+ "type": ["null", "integer"]
+ },
+ "budget": {
+ "type": ["null", "object"]
+ },
+ "enableResourcePlanner": {
+ "type": ["null", "boolean"]
+ },
+ "capacity": {
+ "type": ["null", "integer"]
+ }
+ }
+}
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/source.py b/airbyte-integrations/connectors/source-everhour/source_everhour/source.py
new file mode 100644
index 000000000000..6a3e77d5abe3
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/source.py
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
+#
+
+from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource
+
+"""
+This file provides the necessary constructs to interpret a provided declarative YAML configuration file into
+source connector.
+
+WARNING: Do not modify this file.
+"""
+
+
+# Declarative Source
+class SourceEverhour(YamlDeclarativeSource):
+ def __init__(self):
+ super().__init__(**{"path_to_yaml": "everhour.yaml"})
diff --git a/airbyte-integrations/connectors/source-everhour/source_everhour/spec.yaml b/airbyte-integrations/connectors/source-everhour/source_everhour/spec.yaml
new file mode 100644
index 000000000000..fa9af9ba6019
--- /dev/null
+++ b/airbyte-integrations/connectors/source-everhour/source_everhour/spec.yaml
@@ -0,0 +1,16 @@
+documentationUrl: https://docs.airbyte.io/integrations/sources/everhour
+connectionSpecification:
+ title: Everhour Spec
+ type: object
+ required:
+ - api_key
+ additionalProperties: true
+ properties:
+ api_key:
+ type: string
+ title: API Key
+ description: >-
+ Everhour API Key. See the docs
+ for information on how to generate this key.
+ airbyte_secret: true
diff --git a/connectors.md b/connectors.md
index c33daf44d90d..689f0e3b4173 100644
--- a/connectors.md
+++ b/connectors.md
@@ -66,6 +66,7 @@
| **E2E Testing** | | Source | airbyte/source-e2e-test:2.1.4 | alpha | [link](https://docs.airbyte.com/integrations/sources/e2e-test) | [code](https://github.com/airbytehq/airbyte/tree/master/airbyte-integrations/connectors/source-e2e-test) | `d53f9084-fa6b-4a5a-976c-5b8392f4ad8a` |
| **Elasticsearch** | | Source | airbyte/source-elasticsearch:0.1.1 | alpha | [link](https://docs.airbyte.com/integrations/sources/elasticsearch) | [code](https://github.com/airbytehq/airbyte/tree/master/airbyte-integrations/connectors/source-elasticsearch) | `7cf88806-25f5-4e1a-b422-b2fa9e1b0090` |
| **EmailOctopus** | | Source | airbyte/source-emailoctopus:0.1.0 | alpha | [link](https://docs.airbyte.com/integrations/sources/emailoctopus) | [code](https://github.com/airbytehq/airbyte/tree/master/airbyte-integrations/connectors/source-emailoctopus) | `46b25e70-c980-4590-a811-8deaf50ee09f` |
+| **Everhour** | | Source | airbyte/source-everhour:0.1.0 | alpha | [link](https://docs.airbyte.com/integrations/sources/everhour) | [code](https://github.com/airbytehq/airbyte/tree/master/airbyte-integrations/connectors/source-everhour) | `6babfc42-c734-4ef6-a817-6eca15f0f9b7` |
| **Exchange Rates Api** | | Source | airbyte/source-exchange-rates:1.2.8 | alpha | [link](https://docs.airbyte.com/integrations/sources/exchangeratesapi) | [code](https://github.com/airbytehq/airbyte/tree/master/airbyte-integrations/connectors/source-exchange-rates) | `e2b40e36-aa0e-4bed-b41b-bcea6fa348b1` |
| **Facebook Marketing** | | Source | airbyte/source-facebook-marketing:0.3.0 | generally_available | [link](https://docs.airbyte.com/integrations/sources/facebook-marketing) | [code](https://github.com/airbytehq/airbyte/tree/master/airbyte-integrations/connectors/source-facebook-marketing) | `e7778cfc-e97c-4458-9ecb-b4f2bba8946c` |
| **Facebook Pages** | | Source | airbyte/source-facebook-pages:0.2.3 | beta | [link](https://docs.airbyte.com/integrations/sources/facebook-pages) | [code](https://github.com/airbytehq/airbyte/tree/master/airbyte-integrations/connectors/source-facebook-pages) | `010eb12f-837b-4685-892d-0a39f76a98f5` |
diff --git a/docs/integrations/sources/everhour.md b/docs/integrations/sources/everhour.md
new file mode 100644
index 000000000000..3475806ec1f0
--- /dev/null
+++ b/docs/integrations/sources/everhour.md
@@ -0,0 +1,29 @@
+# Everhour
+
+This page contains the setup guide and reference information for the Everhour source connector.
+
+## Prerequisites
+
+- API Key from Everhour. You can follow instructions [here](https://everhour.docs.apiary.io/#) to get one.
+
+## Supported sync modes
+
+Currently, this project only supports full sync mode.
+
+## Supported Streams
+
+This project supports the following streams:
+
+- Projects Stream
+- Tasks Stream
+- Time Records Stream
+- Clients Stream
+- Time Stream
+- Users Stream
+
+## Changelog
+
+| Version | Date | Pull Request | Subject |
+|:--------|:-----------|:---------------------------------------------------------|:-------------------------------------------------------------------------------|
+
+| 0.1.0 | 2023-02-28 | [23593](https://github.com/airbytehq/airbyte/pull/23593) | Initial Release |