A Go client for the YNAB API. Supports full access to all published YNAB API endpoints. Requires a YNAB account and a Personal Access Token.
go get github.com/smythg4/go-ynab
All API access requires a Personal Access Token. Pass it to NewClient:
client := ynab.NewClient(os.Getenv("YNAB_TOKEN"))package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/smythg4/go-ynab/ynab"
)
func main() {
client := ynab.NewClient(os.Getenv("YNAB_TOKEN")).WithTimeout(2 * time.Second)
plans, err := client.GetPlans(context.Background(), true)
if err != nil {
log.Fatal(err)
}
for _, plan := range plans {
fmt.Println(plan.Name)
for _, acct := range plan.Accounts {
fmt.Printf(" %s\n", acct.Name)
}
}
}All methods accept a context.Context as their first argument, enabling callers to cancel in-flight requests, enforce deadlines, and propagate request-scoped values through the call chain.
The YNAB API allows 200 requests per hour. WithRateLimit enables a token bucket limiter that automatically spaces requests to stay within that limit:
client := ynab.NewClient(os.Getenv("YNAB_TOKEN")).WithRateLimit(200, 10)The first argument is the request budget per hour; the second is the burst size — the number of requests that can be made immediately before throttling begins. To keep total consumption within YNAB's limit, the sustained rate is reduced by the burst size: WithRateLimit(200, 10) allows 10 immediate requests, then throttles to 190 per hour. Calls block until a token is available rather than returning an error, so no retry logic is needed on the caller's side.
Rate limiting is opt-in. Omit WithRateLimit for scripts or one-off tools where request volume is not a concern.
The default request timeout is 10 seconds. Use WithTimeout to override it:
client := ynab.NewClient(os.Getenv("YNAB_TOKEN")).WithTimeout(30 * time.Second)Both methods return the client, so they can be chained:
client := ynab.NewClient(os.Getenv("YNAB_TOKEN")).
WithRateLimit(200, 10).
WithTimeout(30 * time.Second)Errors from the API are returned as typed errors that can be inspected with errors.As:
plan, err := client.GetPlan(ctx, id, nil)
if err != nil {
var notFound ynab.ErrNotFound
if errors.As(err, ¬Found) {
// handle missing plan
}
return err
}Available error types: ErrBadRequest, ErrUnauthorized, ErrForbidden, ErrNotFound, ErrConflict, ErrRateLimit, ErrServerError, ErrServiceUnavailable.
- List plans
- Get plan month
- Get category balance
- List transactions
- Create transaction
- Create multiple transactions
- Update transaction
- Update multiple transactions
- Update category budget
- Delete transaction
- Split transaction
- Delta request
| Method | Endpoint |
|---|---|
GetPlans |
GET /plans |
GetPlan † |
GET /plans/{plan_id} |
GetLastUsedPlan |
GET /plans/last-used |
GetPlanSettings |
GET /plans/{plan_id}/settings |
| Method | Endpoint |
|---|---|
GetAccounts † |
GET /plans/{plan_id}/accounts |
GetAccount |
GET /plans/{plan_id}/accounts/{account_id} |
CreateAccount |
POST /plans/{plan_id}/accounts |
| Method | Endpoint |
|---|---|
GetCategories † |
GET /plans/{plan_id}/categories |
GetCategory |
GET /plans/{plan_id}/categories/{category_id} |
GetCategoryForMonth |
GET /plans/{plan_id}/months/{month}/categories/{category_id} |
CreateCategory † |
POST /plans/{plan_id}/categories |
CreateCategoryGroup † |
POST /plans/{plan_id}/category_groups |
UpdateCategory † |
PATCH /plans/{plan_id}/categories/{category_id} |
UpdateCategoryForMonth † |
PATCH /plans/{plan_id}/months/{month}/categories/{category_id} |
UpdateCategoryGroup † |
PATCH /plans/{plan_id}/category_groups/{category_group_id} |
| Method | Endpoint |
|---|---|
GetMonths † |
GET /plans/{plan_id}/months |
GetMonth |
GET /plans/{plan_id}/months/{month} |
| Method | Endpoint |
|---|---|
GetPayees † |
GET /plans/{plan_id}/payees |
GetPayee |
GET /plans/{plan_id}/payees/{payee_id} |
GetPayeeLocations |
GET /plans/{plan_id}/payee_locations |
GetPayeeLocation |
GET /plans/{plan_id}/payee_locations/{payee_location_id} |
GetPayeeLocationsByPayee |
GET /plans/{plan_id}/payees/{payee_id}/payee_locations |
CreatePayee † |
POST /plans/{plan_id}/payees |
UpdatePayee † |
PATCH /plans/{plan_id}/payees/{payee_id} |
| Method | Endpoint |
|---|---|
GetTransactions † |
GET /plans/{plan_id}/transactions |
GetTransaction † |
GET /plans/{plan_id}/transactions/{transaction_id} |
GetTransactionsByAccount † |
GET /plans/{plan_id}/accounts/{account_id}/transactions |
GetTransactionsByCategory † |
GET /plans/{plan_id}/categories/{category_id}/transactions |
GetTransactionsByPayee † |
GET /plans/{plan_id}/payees/{payee_id}/transactions |
GetTransactionsByMonth † |
GET /plans/{plan_id}/months/{month}/transactions |
CreateTransaction |
POST /plans/{plan_id}/transactions |
CreateTransactions |
POST /plans/{plan_id}/transactions |
UpdateTransaction |
PUT /plans/{plan_id}/transactions/{transaction_id} |
UpdateTransactions |
PATCH /plans/{plan_id}/transactions |
DeleteTransaction † |
DELETE /plans/{plan_id}/transactions/{transaction_id} |
ImportTransactions |
POST /plans/{plan_id}/transactions/import |
| Method | Endpoint |
|---|---|
GetScheduledTransactions † |
GET /plans/{plan_id}/scheduled_transactions |
GetScheduledTransaction |
GET /plans/{plan_id}/scheduled_transactions/{scheduled_transaction_id} |
CreateScheduledTransaction |
POST /plans/{plan_id}/scheduled_transactions |
UpdateScheduledTransaction |
PUT /plans/{plan_id}/scheduled_transactions/{scheduled_transaction_id} |
DeleteScheduledTransaction |
DELETE /plans/{plan_id}/scheduled_transactions/{scheduled_transaction_id} |
| Method | Endpoint |
|---|---|
GetMoneyMovements † |
GET /plans/{plan_id}/money_movements |
GetMoneyMovementsByMonth † |
GET /plans/{plan_id}/months/{month}/money_movements |
GetMoneyMovementGroups † |
GET /plans/{plan_id}/money_movement_groups |
GetMoneyMovementGroupsByMonth † |
GET /plans/{plan_id}/months/{month}/money_movement_groups |
| Method | Endpoint |
|---|---|
GetUser |
GET /user |
† Returns server knowledge as a second return value for use with delta requests.
Unit tests cover all endpoints (GET, POST, PATCH, PUT, DELETE), client configuration, error type dispatch, and auth header injection. Write operation tests verify the HTTP method and request body serialization.
go test ./ynab/...
Integration tests exercise the live API against a real plan and require YNAB_TOKEN and YNAB_TEST_PLAN_ID environment variables. They are opt-in via a build tag:
YNAB_TOKEN=... YNAB_TEST_PLAN_ID=... go test -tags integration -v ./integration/
I am not affiliated, associated, or in any way officially connected with YNAB or any of its subsidiaries or affiliates. The official YNAB website can be found at https://www.ynab.com. The names YNAB and You Need A Budget, as well as related names, tradenames, marks, trademarks, emblems, and images are registered trademarks of YNAB. YNAB API Terms of Service.