Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,3 @@ target/

# Ipython Notebook
.ipynb_checkpoints
.socket-scans/
.socket.facts.json
2 changes: 2 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

1. Run `scripts/generate.sh`. This will generate the API client from the latest OpenAPI spec. Once generated, you should open a PR and merge the changes.

Alternatively, run `scripts/generate-and-pr.sh` to do the above and automate the PR. It wraps `generate.sh`, detects the old → new spec version, and (after you confirm) ensures you're on a `gen-<version>` branch, then commits, pushes, and opens a PR against `main` via `git`/`gh`, printing the PR URL. The [`claude`](https://docs.claude.com/en/docs/claude-code/overview) CLI is used only to draft the PR description from the spec diff. Requires the `gh` and `claude` CLIs to be installed and authenticated.

## Publishing

Run the "Publish" GitHub Actions workflow.
3 changes: 2 additions & 1 deletion docs/ExistingCategory.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ Name | Type | Description | Notes
**name** | **str** | | [optional]
**note** | **str** | | [optional]
**category_group_id** | **UUID** | The id of the category group to which this category belongs. An internal category group may not be specified. | [optional]
**goal_target** | **int** | The goal target amount in milliunits format. If value is specified and goal has not already been configured for category, a monthly goal will be created for the category with this target amount. If goal_type is not specified, it will default to &#39;NEED&#39; or &#39;MF&#39; for Credit Card Payment categories. | [optional]
**goal_target** | **int** | The goal target amount in milliunits format. If value is specified and goal has not already been configured for category, a monthly goal will be created for the category with this target amount. If goal_type is not specified, it will default to &#39;NEED&#39; or &#39;MF&#39; for Credit Card Payment categories. When updating a category, passing null removes any existing target. | [optional]
**goal_target_date** | **date** | The goal target date in ISO format (e.g. 2016-12-01). | [optional]
**goal_needs_whole_amount** | **bool** | Whether the goal requires the full target amount each period. Only supported for &#39;NEED&#39; goals. When true, the goal is configured as &#39;Set aside another...&#39;. When false, the goal is configured as &#39;Refill up to...&#39;. | [optional]
**goal_frequency** | **str** | When specified, configures a recurring &#39;NEED&#39; target of goal_target that repeats at this frequency, replacing any existing target. Requires goal_target. Cannot be combined with goal_target_date and is not supported for Credit Card Payment categories. Omit to leave an existing target&#39;s cadence unchanged. | [optional]

## Example

Expand Down
3 changes: 2 additions & 1 deletion docs/NewCategory.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ Name | Type | Description | Notes
**name** | **str** | | [optional]
**note** | **str** | | [optional]
**category_group_id** | **UUID** | The id of the category group to which this category belongs. An internal category group may not be specified. | [optional]
**goal_target** | **int** | The goal target amount in milliunits format. If value is specified and goal has not already been configured for category, a monthly goal will be created for the category with this target amount. If goal_type is not specified, it will default to &#39;NEED&#39; or &#39;MF&#39; for Credit Card Payment categories. | [optional]
**goal_target** | **int** | The goal target amount in milliunits format. If value is specified and goal has not already been configured for category, a monthly goal will be created for the category with this target amount. If goal_type is not specified, it will default to &#39;NEED&#39; or &#39;MF&#39; for Credit Card Payment categories. When updating a category, passing null removes any existing target. | [optional]
**goal_target_date** | **date** | The goal target date in ISO format (e.g. 2016-12-01). | [optional]
**goal_needs_whole_amount** | **bool** | Whether the goal requires the full target amount each period. Only supported for &#39;NEED&#39; goals. When true, the goal is configured as &#39;Set aside another...&#39;. When false, the goal is configured as &#39;Refill up to...&#39;. | [optional]
**goal_frequency** | **str** | When specified, configures a recurring &#39;NEED&#39; target of goal_target that repeats at this frequency, replacing any existing target. Requires goal_target. Cannot be combined with goal_target_date and is not supported for Credit Card Payment categories. Omit to leave an existing target&#39;s cadence unchanged. | [optional]

## Example

Expand Down
3 changes: 2 additions & 1 deletion docs/SaveCategory.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ Name | Type | Description | Notes
**name** | **str** | | [optional]
**note** | **str** | | [optional]
**category_group_id** | **UUID** | The id of the category group to which this category belongs. An internal category group may not be specified. | [optional]
**goal_target** | **int** | The goal target amount in milliunits format. If value is specified and goal has not already been configured for category, a monthly goal will be created for the category with this target amount. If goal_type is not specified, it will default to &#39;NEED&#39; or &#39;MF&#39; for Credit Card Payment categories. | [optional]
**goal_target** | **int** | The goal target amount in milliunits format. If value is specified and goal has not already been configured for category, a monthly goal will be created for the category with this target amount. If goal_type is not specified, it will default to &#39;NEED&#39; or &#39;MF&#39; for Credit Card Payment categories. When updating a category, passing null removes any existing target. | [optional]
**goal_target_date** | **date** | The goal target date in ISO format (e.g. 2016-12-01). | [optional]
**goal_needs_whole_amount** | **bool** | Whether the goal requires the full target amount each period. Only supported for &#39;NEED&#39; goals. When true, the goal is configured as &#39;Set aside another...&#39;. When false, the goal is configured as &#39;Refill up to...&#39;. | [optional]
**goal_frequency** | **str** | When specified, configures a recurring &#39;NEED&#39; target of goal_target that repeats at this frequency, replacing any existing target. Requires goal_target. Cannot be combined with goal_target_date and is not supported for Credit Card Payment categories. Omit to leave an existing target&#39;s cadence unchanged. | [optional]

## Example

Expand Down
55 changes: 44 additions & 11 deletions open_api_spec.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
openapi: 3.1.1
info:
title: YNAB API Endpoints
description: Our API uses a REST based design, leverages the JSON data format,
and relies upon HTTPS for transport. We respond with meaningful HTTP
response codes and if an error occurs, we include error details in the
response body. API Documentation is at https://api.ynab.com
version: 1.85.0
description: |-
Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body.

Read the [API Documentation](https://api.ynab.com) for more information about the API, including how to obtain an access token and how to use it to make requests.
version: 1.86.0
servers:
- url: https://api.ynab.com/v1
security:
- bearer: []
tags:
- name: User
description: The currently authenticated user
- name: Plans
description: Plans are the top-level container for your YNAB data; accounts,
categories, payees, and transactions all belong to a plan. Most endpoints
require a plan_id, which can be obtained from "Get all plans".
Alternatively, "last-used" can be used in place of a plan_id to specify
the most recently used plan, and "default" can be used if [default plan
selection](https://api.ynab.com/#oauth-default-plan) is enabled.
- name: Accounts
description: The accounts for a plan
description: The accounts for a plan. Every transaction belongs to an account,
and an account is either "on budget", where its activity is categorized
and planned, or a tracking account, where only its balance is tracked
(see the on_budget flag).
- name: Categories
description: The categories for a plan
description: The categories for a plan, organized into category groups.
Category amounts (assigned, activity, available) are specific to a month,
and can be read and updated through the month-scoped category endpoints.
- name: Payees
description: The payees for a plan
description: The payees for a plan. Transfers between accounts are represented
with special transfer payees; a payee with transfer_account_id set is the
transfer payee for that account.
- name: Payee Locations
description: When you enter a transaction and specify a payee on the YNAB mobile
apps, the GPS coordinates for that location are stored, with your
Expand All @@ -31,11 +45,20 @@ tags:
Assign, Age of Money and category (assigned / activity / available)
amounts are available.
- name: Money Movements
description: The money movements for a plan
description: Money movements record money moved between two categories, or
between a category and Ready to Assign, within a plan month. Movements
performed together as a single action are linked by a money movement
group.
- name: Transactions
description: The transactions for a plan
description: The transactions for a plan. Transaction amounts are specified in
[milliunits format](https://api.ynab.com/#formats). Split transactions
are represented with subtransactions, and transfers between accounts are
represented with transfer payees.
- name: Scheduled Transactions
description: The scheduled transactions for a plan
description: The scheduled transactions for a plan; upcoming and recurring
transactions that have not yet been entered into an account. Each has a
frequency along with the first and next dates it will occur (date_first
and date_next).
paths:
/user:
get:
Expand Down Expand Up @@ -3247,6 +3270,7 @@ components:
and goal has not already been configured for category, a monthly goal
will be created for the category with this target amount. If goal_type is
not specified, it will default to 'NEED' or 'MF' for Credit Card Payment categories.
When updating a category, passing null removes any existing target.
format: int64
goal_target_date:
type:
Expand All @@ -3261,6 +3285,15 @@ components:
description: Whether the goal requires the full target amount each period. Only supported for 'NEED' goals.
When true, the goal is configured as 'Set aside another...'.
When false, the goal is configured as 'Refill up to...'.
goal_frequency:
type: string
enum:
- monthly
- weekly
- yearly
description: When specified, configures a recurring 'NEED' target of goal_target that repeats at this
frequency, replacing any existing target. Requires goal_target. Cannot be combined with goal_target_date
and is not supported for Credit Card Payment categories. Omit to leave an existing target's cadence unchanged.
ExistingCategory:
allOf:
- $ref: "#/components/schemas/SaveCategory"
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "ynab"
version = "4.2.0"
description = "Official Python client for the YNAB API. API documentation available at https://api.ynab.com. Generated from server specification version 1.85.0"
description = "Official Python client for the YNAB API. API documentation available at https://api.ynab.com. Generated from server specification version 1.86.0"
authors = ["YNAB"]
license = "Apache-2.0"
readme = "README.md"
Expand Down
111 changes: 111 additions & 0 deletions scripts/generate-and-pr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env bash
#
# Regenerate the SDK from the latest YNAB API spec, then optionally open a PR.
#
# Wraps scripts/generate.sh. After regenerating it detects the old -> new spec
# version and, if you confirm, ensures you're on a gen-<version> branch, then
# commits, pushes, and opens a PR via git/gh. The `claude` CLI is used only to
# draft the PR description from the spec diff. Requires the `gh` and `claude`
# CLIs to be installed and authenticated.

set -euo pipefail

REPO_ROOT="$(git rev-parse --show-toplevel)"
SCRIPT_DIR="$REPO_ROOT/scripts"
SPEC="$REPO_ROOT/open_api_spec.yaml"

cd "$REPO_ROOT"

# Extract info.version from an OpenAPI spec on stdin (the 2-space-indented
# `version:` inside the top-level `info:` block, not `openapi:` or nested ones).
spec_version() {
awk '/^info:/{f=1} f && /^ version:/{print $2; exit}'
}

OLD_VERSION="$(git show HEAD:open_api_spec.yaml 2>/dev/null | spec_version || true)"

# Regenerate: downloads the latest spec and runs openapi-generator.
bash "$SCRIPT_DIR/generate.sh"

NEW_VERSION="$(spec_version < "$SPEC")"

if [[ -z "$(git status --porcelain)" ]]; then
echo
echo "No changes after regeneration — spec ${NEW_VERSION:-unknown} is already up to date. Nothing to do."
exit 0
fi

echo
echo "Regeneration produced changes. Spec version: ${OLD_VERSION:-unknown} -> ${NEW_VERSION:-unknown}"
git status --short
echo

read -r -p "Create a pull request for these changes? [y/N] " reply
case "$reply" in
[yY] | [yY][eE][sS]) ;;
*)
echo "Leaving the regenerated changes uncommitted in the working tree. Done."
exit 0
;;
esac

# Never commit on a protected branch: if we're on one, create a fresh
# gen-<version> branch (the uncommitted regen changes carry over). Otherwise
# stay on the current feature branch.
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
DESIRED="gen-${NEW_VERSION//./-}"
case "$BRANCH" in
main | master | develop)
target="$DESIRED"
if git show-ref --verify --quiet "refs/heads/$target"; then
n=2
while git show-ref --verify --quiet "refs/heads/${DESIRED}-${n}"; do n=$((n + 1)); done
target="${DESIRED}-${n}"
fi
echo "On protected branch '$BRANCH'; creating and switching to '$target'."
git switch -c "$target"
BRANCH="$target"
;;
*)
echo "Committing on current branch: '$BRANCH'."
;;
esac

# Commit and push the regenerated client.
git add -A
git commit \
-m "Regenerate SDK from server specification version ${NEW_VERSION}" \
-m "Regenerated the client from the YNAB API spec ${NEW_VERSION} (previously ${OLD_VERSION:-unknown})."
git push -u origin "$BRANCH"

# Use claude only to draft the PR description from the meaningful diff (the spec
# and docs; the per-file churn under ynab/ is noise). Everything else is gh/git.
echo
echo "Drafting the PR description with Claude..."
DIFF="$(git diff "origin/main...HEAD" -- open_api_spec.yaml docs/; echo; git diff --stat "origin/main...HEAD")"

BODY_FILE="$(mktemp)"
trap 'rm -f "$BODY_FILE"' EXIT

claude -p "Write a GitHub pull request description for a regeneration of the YNAB Python SDK from the YNAB OpenAPI spec (version ${OLD_VERSION:-unknown} -> ${NEW_VERSION}).

Summarize the FUNCTIONAL API changes (new or changed fields, endpoints, enums, response codes) from the diff below, focusing on open_api_spec.yaml and docs/. If there are no functional changes, say it is a routine spec-generation refresh. Ignore the mechanical per-file header/version churn under ynab/.

Output ONLY the PR description as Markdown — no preamble and no surrounding code fence. Do not use any tools.

Diff:
${DIFF}" > "$BODY_FILE"

if [[ ! -s "$BODY_FILE" ]]; then
echo "Regenerated the client from the YNAB API spec ${NEW_VERSION} (previously ${OLD_VERSION:-unknown})." > "$BODY_FILE"
fi

# Open the PR (no reviewers). gh prints the PR URL.
gh pr create \
--base main \
--head "$BRANCH" \
--title "Regenerate SDK from server specification version ${NEW_VERSION}" \
--body-file "$BODY_FILE"

echo
echo "Done."
6 changes: 3 additions & 3 deletions ynab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
"""
YNAB API Endpoints

Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. API Documentation is at https://api.ynab.com
Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. Read the [API Documentation](https://api.ynab.com) for more information about the API, including how to obtain an access token and how to use it to make requests.

The version of the OpenAPI document: 1.85.0
The version of the OpenAPI document: 1.86.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
""" # noqa: E501


__version__ = "4.1.0"
__version__ = "4.2.0"

# Define package exports
__all__ = [
Expand Down
4 changes: 2 additions & 2 deletions ynab/api/accounts_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
YNAB API Endpoints

Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. API Documentation is at https://api.ynab.com
Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. Read the [API Documentation](https://api.ynab.com) for more information about the API, including how to obtain an access token and how to use it to make requests.

The version of the OpenAPI document: 1.85.0
The version of the OpenAPI document: 1.86.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
Expand Down
4 changes: 2 additions & 2 deletions ynab/api/categories_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
YNAB API Endpoints

Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. API Documentation is at https://api.ynab.com
Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. Read the [API Documentation](https://api.ynab.com) for more information about the API, including how to obtain an access token and how to use it to make requests.

The version of the OpenAPI document: 1.85.0
The version of the OpenAPI document: 1.86.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
Expand Down
4 changes: 2 additions & 2 deletions ynab/api/money_movements_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
YNAB API Endpoints

Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. API Documentation is at https://api.ynab.com
Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. Read the [API Documentation](https://api.ynab.com) for more information about the API, including how to obtain an access token and how to use it to make requests.

The version of the OpenAPI document: 1.85.0
The version of the OpenAPI document: 1.86.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
Expand Down
Loading