# Bkper LLM Knowledge Pack
> Composed context for AI agents using canonical Site, Docs, Apps, and Changelog sources.
## Site
### About Us
Source: https://bkper.com/about.md
Our mission is to make Finance & Accounting effortless, intelligent, and accessible for everyone, everywhere.
Back in the day, while working on large batch-driven financial systems, we read the first publications about natural language processing and machine learning. From then on we envisioned a totally different way how finance should be done — a reality where machines would do all the work instead of people obeying compliance-rigid systems.
We started Bkper, building towards a consistent bookkeeping platform that is the single source of truth for true accounting intelligence — where reporting happens in real-time, not through monthly batch runs, and where AI doesn't just categorize expenses but can actually understand your context.
Now, with hundreds of customers around the globe and bots recording millions of transactions, our vision is proving out.

## Our Principles
#### User-Centric Focus
Every decision starts with the user. We design solutions that truly help people manage their finances, letting real feedback guide what we build next.
#### Simplicity & Essentialism
Do less, but better. Every feature must earn its place. We remove complexity before adding new capabilities, because simple solutions scale better, cost less, and delight users more.
#### Technology-First
Technology should do the work, not people. We build intelligent systems that understand business context, provide real-time insights, and pursue transformative solutions over incremental gains.
#### Global by Default
Built for users in any country from day one. We handle multiple currencies, units of measure, and cultural contexts as first-class concerns — providing the framework, not the compliance burden.
These principles, along with our operational values and decision framework, guide every choice we make — from product to code. [Read our mission, principles & values](https://bkper.com/about/mission-principles-values.md.md)
## Our Journey
- **2014** Awarded at Stanford University Entrepreneurship Course
- **2015** Delaware Incorporated as Bkper Inc.
- **2016** Unventures Incubation Program
- **2017** Pre-Seed round by Plug and Play and Social Capital
- **2018** Became a Google Cloud SaaS Partner
- **2019** Launched on GCP Marketplace and integrated with +10k Banks
- **2020** Launched Bkper Bots
- **2021** First single customer to reach 1 million transactions
- **2022** Expanded the tech team from 1 to 3 engineers
- **2023** Expanded Bank Connections coverage to Brazil and Europe
- **2024** Launched the new Progressive Web App
- **2025** Launched the AI-powered Bkper Agent

**130K+** users in **120+** countries
**50M+** transactions recorded
## Team

#### Mael Caldas
CEO [LinkedIn](https://www.linkedin.com/in/mael-caldas-5b12ab50/)

#### Jacob van den Berg
COO [LinkedIn](https://www.linkedin.com/in/jacobvandenberg/)

#### Victor Drumond
Lead Software Engineer [LinkedIn](https://www.linkedin.com/in/victordmds/)

#### Bruno Coelho
Software Engineer [LinkedIn](https://www.linkedin.com/in/bruno-coelho-9ab0b0139/)
Backed by
[](https://www.plugandplaytechcenter.com/)[](https://www.socialcapital.com/)
### Bank Connections
Source: https://bkper.com/banks.md
# Securely Connect and Centralize Financial Data
Access over 11,000 banks and credit card institutions across the US, Europe, and Brazil with seamless integration.
Bkper connects to more than **11,000** financial institutions across the US, Europe, and Brazil.
Try it for Free
## How Bank Connections Work
#### Connect
**Transactions flow in automatically**
Connect your bank and credit card accounts — transactions are recorded in Bkper shortly after they clear at your financial institution.
[Learn more](https://help.bkper.com/en/articles/8601113-introduction-to-bkper-bank-connections)
#### Reconcile
**Consolidate in one place**
Reconcile data from multiple financial institutions and see your complete financial position in a single, organized view.
#### Report
**Analyze and report with Sheets**
Sync bank transactions to Bkper, then analyze and report on your financial data directly in Google Sheets with powerful functions.
[Explore Sheets integration](https://bkper.com/sheets.md)
## Secure by Design
No credentials stored. End customers connect directly to their own financial institutions — no need to handle sensitive banking information. Enterprise-grade security built in.
See security
### FAQ
- Which banks are supported?
Bkper connects to over 11,000 financial institutions, including major banks, credit unions, and credit card providers across the US, Europe, and Brazil. For other regions, you can import statements via the Bkper Agent.
- How do bank connections work?
Bkper uses secure, industry-standard connections to link your bank accounts. Once connected, transactions are automatically imported into your Bkper books shortly after they clear at your financial institution.
- How quickly do transactions appear?
Transactions typically appear in Bkper within hours of clearing at your bank. The exact timing depends on your financial institution, but most transactions are available within the same business day.
- Is my banking data secure?
Yes. Bkper never stores your bank credentials. You connect directly to your financial institution using industry-standard OAuth authentication. All data is encrypted in transit and at rest on Google Cloud infrastructure.
### Platform
Source: https://bkper.com/platform.md
# Financial infrastructure, ready to build on
A distributed transactional engine, real-time event processing, balance auditing, and financial modeling — the hard problems are solved. Build your solution on top.
Start Building [See what's been built](https://bkper.com/apps.md)
### How you build on it
Choose your entry point — from a CLI one-liner to a full managed app. No lock-in between tiers.
#### Scripts & CLI
**No infrastructure needed**
Pipe data through the CLI, write Node.js scripts, or call the REST API directly. Output as JSON or CSV for pipelines and AI agents.
[Explore CLI](https://bkper.com/docs/build/scripts/cli-pipelines.md)
#### Google Workspace
**Google's runtime**
Build automations with Apps Script, extend Google Sheets with custom functions and triggers. Bidirectional sync built in.
[See Apps Script](https://bkper.com/docs/build/google-workspace/apps-script.md)
#### Platform Apps
**Full managed hosting**
Edge hosting, pre-configured OAuth, KV storage, secrets, and event handling. You write business logic — the platform handles infrastructure.
[See the app platform](https://bkper.com/docs/build/apps/overview.md)
## What you don't have to build
Building financial software from scratch means solving transactional integrity, data modeling, event processing, and access control before you write a single line of business logic. The engine handles all of it — accessible through the REST API, TypeScript SDK, and CLI.
| You need | From scratch | With the platform |
| --- | --- | --- |
| Transactional integrity | Design a ledger, enforce double-entry, handle concurrent writes | Zero-sum invariant enforced at API level — every write is atomic |
| Financial modeling | Account type design, balance periods, closing procedures, hierarchical grouping | 4 account types with temporal behavior, period-agnostic balances — query any timeframe without closing. Groups, hierarchies, Collections for multi-entity structures, any countable resource |
| Extensible data model | Custom field schemas, tagging systems, metadata storage | Custom properties on any entity, hashtags for multi-dimensional tracking |
| Real-time automation | Message queues, webhook infrastructure, retry logic, idempotency | 31 event types — declare what you listen for, events route automatically |
| Balance consistency | Reconciliation algorithms, distributed locks, periodic verification | Consensus-based audit, six years of refinement, always consistent |
| Access control | Auth system, roles, permissions, audit logging | Six permission roles with OAuth and agent identity. Full activity trail — every action logged, every change traceable to a user or app |
Built on Google Cloud — Google's data centers, encryption, and infrastructure behind every API call. [See security](https://bkper.com/security.md)
## Developer experience
One command starts your local environment — Vite dev server with HMR, Workers runtime for event handlers, and a Cloudflare tunnel so webhooks reach your laptop. Preview environments before production. JSON and CSV output for scripting.
[Set up your environment](https://bkper.com/docs/build/getting-started/setup.md)
## What the platform handles
Without the platform, building a Bkper app with a UI, event handling, and authentication requires provisioning servers, configuring OAuth, setting up tunnels, and managing secrets. The platform eliminates all of it.
| Concern | Without | With the platform | You get |
| --- | --- | --- | --- |
| Hosting | Provision servers, SSL, CDN | `bkper app deploy` | `your-app.bkper.app` live on the edge |
| Authentication | OAuth client, consent screen, token refresh | `auth.getAccessToken()` | Users sign in with Google — tokens managed for you |
| Webhooks | Public endpoint, DNS, JWT verification | Declare in `bkper.yaml` | Events routed to your handlers automatically |
| Local dev | ngrok, manual tunnel config | `bkper app dev` | HMR + live webhooks on localhost |
| Secrets | Secrets manager, access config | `bkper app secrets put` | `c.env.MY_SECRET` in your code |
| KV storage | Deploy Redis/Memcached, manage connections | Declare `KV` in `bkper.yaml` | `c.env.KV.get()` / `.put()` ready to use |
| Preview | Build a staging pipeline | `bkper app deploy --preview` | Isolated environment with its own secrets & KV |
[Build your first app](https://bkper.com/docs/build/getting-started/first-app.md)
> "Through our partnership with Bkper, we successfully unified the entire accounting, tax, and financial reporting process. Instead of spending time on routine tasks, our professionals can now focus on client advice, reviews, and continuous process improvement."

**Daniel González Cotelo** Partner & Head of Tax and Accounting, [Posadas](https://www.ppv.com.uy/)
> "The partnership with Bkper has been a cornerstone of Brain's digital strategy, driving operational efficiency, cost savings, and enhanced service delivery."

**Camilo Preve** Partner, [Brain](https://www.brain.uy/)
### Pricing
Source: https://bkper.com/pricing.md
# Flexible plans that fit your needs
Start free, upgrade as you grow. No credit card required.
Monthly Yearly (Save ~25%)
### Free
for unlimited evaluation
$0/mo $0/mo
100 transactions/month
This includes:
- ✓ Unlimited books
- ✓ Unlimited accounts
- ✓ Unlimited collaborators
- ✓ Comments & activities
- ✓ Google Sheets add-on ? Connect Bkper to Google Sheets to build custom reports, import data, and automate workflows.
- ✓ Bots & automations
- ✓ Chart reports
Get Started Free
### Standard
for solo Innovators & Consultants
$14/mo $10.50/mo billed as $126/year
1,000 transactions/month
Everything in Free, plus:
- ✓ Saved queries ? Save and reuse custom queries to quickly access the reports and views you use most.
- ✓ Bank connections ? Automatically import transactions from your bank. Supports thousands of banks across the US, Europe, and Brazil.
Subscribe
### Business
for visionary CFOs & Accountants
$32/mo $24/mo billed as $288/year
5,000 transactions/month
Everything in Standard, plus:
- ✓ Book closing & lock dates ? Lock your books at specific dates to prevent changes to past periods. Essential for audit compliance.
- ✓ Domain-wide activation
- ✓ Custom logo
Subscribe
## Need more than 5,000 transactions per month?
Professional plans support up to 10,000 transactions. For larger volumes, contact our team for a custom plan.
[Contact Sales](https://bkper.com/mailto:support@bkper.com)
### FAQ
- What payment options do you accept?
We accept all major credit cards including Visa, MasterCard, and American Express. Payments are securely processed by Stripe.
- Are there any long-term contracts?
There's no contract on any plan. You just pay as you go, and you can cancel any time without penalty.
- What happens if I change plans?
When you change plans, any unused portion of your current plan is applied as a pro rata credit toward your new plan. The switch is instant.
- Can I cancel my subscription?
Yes, you can cancel your subscription at any time. Your plan will remain active until the end of the current billing period, so you won't lose any access you've already paid for.
- Do you offer refunds?
We offer a money-back guarantee for the current billing period if you're not satisfied with the service. Just reach out to our support team.
- How do transaction limits work?
Your transaction counter resets at the start of each billing cycle. Note that deleted transactions still count toward your monthly limit, but draft transactions do not.
### Security
Source: https://bkper.com/security.md
# Your Data. Protected.
Built on Google Cloud Platform, Bkper delivers enterprise-grade protection for your financial data with advanced encryption and industry-standard security protocols.
## How We Protect Your Data
#### Encrypt
**End-to-end data protection**
All data encrypted in transit with SSL and at rest using AES — the same Advanced Encryption Standard and cryptographic key management Google uses to protect its own data.
[Learn about GCP encryption](https://cloud.google.com/security/encryption/default-encryption)
#### Scale
**Global infrastructure, zero downtime**
Enterprise-grade automated infrastructure on Google Cloud that dynamically scales to meet your business demands. Google manages all critical components — servers, networking, and security protocols.
[See GCP infrastructure](https://cloud.google.com/security/infrastructure/)
#### Authenticate
**Secure access with OAuth2**
No passwords stored. Users authenticate directly with Google using industry-standard OAuth2 protocol. Every API request is verified and authorized, ensuring only legitimate access to your financial data.
## Google Cloud Partner
Bkper is a certified Google Cloud Partner since 2018 — meeting the highest product and security standards, verified by Google. Your data runs on the same infrastructure that powers Google's own services.
See partner listing
### FAQ
- Where is my data stored?
All data is stored on Google Cloud Platform servers, distributed across multiple data centers for redundancy and reliability. Google manages physical security, environmental controls, and infrastructure maintenance.
- Is my data encrypted?
Yes. All data is encrypted in transit using SSL/TLS and encrypted at rest using AES (Advanced Encryption Standard). Encryption keys are managed by Google's Key Management Service with automatic key rotation.
- How does authentication work?
Bkper uses OAuth2 for authentication — the same protocol used by Google, GitHub, and other major platforms. You sign in with your Google account, and Bkper never stores or handles your password.
- Does Bkper comply with GDPR?
Yes. As a Google Cloud Partner, Bkper adheres to GDPR requirements for data protection. You maintain full control over your data and can export or delete it at any time.
- Who has access to my financial data?
Only users you explicitly authorize can access your books. Bkper uses Google Workspace's permission model, so you control sharing with the same granularity as Google Docs or Sheets.
### Google Sheets
Source: https://bkper.com/sheets.md
# Turn Google Sheets into a Powerful Accounting Tool
Connect your Bkper books to Google Sheets. Build dynamic financial reports, dashboards, and custom analyses — all connected to your books.
## What You Can Do
#### Functions
**Live financial data in cells**
Use custom Bkper Functions to pull balances, transactions, and account data directly into your spreadsheet. Data updates automatically as transactions are recorded.
[Get the add-on](https://workspace.google.com/marketplace/app/bkper/360398463400)
#### Reports
**Balance sheets, P&L, cash flow**
Create balance sheets, income statements, and cash flow reports that update in real time. Copy and reuse report templates across clients and entities.
#### Dashboards
**Charts and analyses, your way**
Combine Bkper data with Google Sheets' powerful charting tools. Build custom dashboards for expense tracking, revenue forecasting, and any financial analysis you need.
## Bkper Functions
Seven functions give you full access to your financial data from any cell.
\=BKPER\_BALANCES\_TOTAL()
Fetch total balances for accounts or groups over any period
\=BKPER\_BALANCES\_PERIOD()
Fetch period-by-period balances for trend analysis
\=BKPER\_BALANCES\_CUMULATIVE()
Fetch cumulative balances for running totals
\=BKPER\_BALANCES\_TRIAL()
Fetch a trial balance view across all accounts
\=BKPER\_TRANSACTIONS()
Fetch individual transactions with full query support
\=BKPER\_ACCOUNTS()
Fetch a live list of accounts from your book
\=BKPER\_GROUPS()
Fetch a live list of groups from your book
## How It Works
1
#### Install
Get the Bkper add-on from the Google Workspace Marketplace.
2
#### Connect
Link your Bkper books to any Google Sheets spreadsheet.
3
#### Build
Use Bkper Functions to create dynamic financial reports.
### FAQ
- Is the Google Sheets add-on free?
Yes, the Bkper Google Sheets add-on is included with all plans, including the Free plan.
- What are Bkper Functions?
Bkper Functions are custom spreadsheet functions that pull live data from your Bkper books. For example, =BKPER\_BALANCES\_TOTAL() returns the balance of an account or group for any period.
- Can I use it with multiple books?
Yes, you can connect multiple Bkper books to the same spreadsheet, making it easy to consolidate data from different entities or projects.
- Does it work with bank connection data?
Yes, transactions imported via Bank Connections are available through Bkper Functions just like any other transaction.
- Can I reuse reports across clients?
Yes. Since Bkper Functions reference books by ID, you can copy a report template to a new spreadsheet and simply update the book ID to generate the same reports for a different client or entity.
### With Google
Source: https://bkper.com/withgoogle.md
# AI-First Finance and Accounting Platform on Google Cloud
Bkper and Google Cloud provide the secure infrastructure to automate your bookkeeping workflow.
## Strong Infrastructure
Google Cloud offers the highest security and protective standards to your sensitive data and we always use the fastest infrastructure for data processing.
- Modern infrastructure: safe, global, economical, high performance and constant improvements.
- Google Servers: fully automated services that scale according to customers' usage of Bkper.
- Secure and unified billing in your local currency, managed by Google.
[Meet Google Cloud →](https://cloud.google.com/)

## What can I do more with Bkper and Google Cloud?
New customers on Google Cloud Platform (GCP) receive $300 credit that can be used on Bkper paid plans. Unused credit expires in 12 months.
[Start GCP free trial →](https://console.cloud.google.com/freetrial/signup/)
| Bkper Plan | Benefits | $300 credit gives you |
| --- | --- | --- |
| Standard | 1,000 transactions per month | Up to 12 months |
| Business | 5,000 transactions per month | Up to 8 months |
### FAQ
- How long does the $300 credit last?
The $300 credit ends as soon as one of these conditions is met: 12 months have elapsed since you signed up, or you've spent the $300 in credit. Your remaining credit and days are displayed at the top of the Google Cloud Platform Console during your free trial period.
- Do I need to put down credit card information when I sign up?
Google asks for your credit card information when you sign up to verify your identity and distinguish actual customers from robots. Even though you set up a billing account, you won't be charged unless you upgrade to a paid account.
- What happens after the $300 credit ends?
After the credit ends, you will be automatically downgraded to the Bkper Free plan, unless you upgrade to a paid account.
### Mission, Principles & Values
Source: https://bkper.com/about/mission-principles-values.md
Bkper's mission, principles, values, and decision framework — the foundation that guides every choice from product to code.
## Mission Statement
**Make Finance & Accounting effortless, intelligent, and accessible for everyone, everywhere.**
## Core Principles
### User-Centric Focus
- **User focus** - Meet and exceed customer needs and desires in every decision
- **Empathy for users** - Understand their pain points and design solutions that truly help
- **Customer-driven development** - Let user feedback guide product evolution
- **Support-focused** - Prioritize helping users succeed over feature complexity
### Simplicity & Essentialism
- **Do less, but better** - Focus on the essential few over the trivial many
- **Remove before adding** - Before building new features, eliminate unnecessary complexity
- **Every feature must earn its place** - If it's not essential, it doesn't belong
- **Simplicity compounds value** - Simple solutions scale better, cost less, and delight users more
- **One concept, not many** - Use the same powerful abstraction everywhere rather than special cases
- **Ship today, perfect tomorrow** - Default to the simplest solution that delivers value now, complexity must be earned through real usage
- **Speed through simplicity** - Move fast by eliminating unnecessary complexity, not by rushing or compromising
### Technology-First Approach
- **Technology should do the work, not people** - Automate manual processes and reduce human overhead
- **AI should understand context, not just categorize** - Build intelligent systems that comprehend business logic
- **Real-time data is superior to batch processing** - Provide immediate insights and continuous synchronization
- **Paradigm shift over incremental improvement** - Pursue transformative solutions, not just marginal gains
## Operational Values
### Quality & Excellence
- **Quality** - Strive for excellence and continuous improvement in all outputs
- **Simplicity in practice** - Apply our core principle of simplicity to daily operations
- **Move fast with focus** - Act quickly on what's essential, ignore what's not
- **Resilience** - Build robust systems and maintain adaptability under pressure
### Collaboration & Integrity
- **Collaboration** - Work effectively across functional and department boundaries
- **Integrity** - Practice honesty, sincerity, and stand up for beliefs
- **Mutual respect and trust** - Foster an environment of psychological safety
- **Accountability** - Take ownership of decisions and outcomes
### Global Perspective
- **Global mindset** - Consider diverse markets, cultures, and local contexts
- **Accessibility** - Ensure solutions work for users in any country
- **Scalability** - Design systems that grow with global demand
### Platform Guide
Source: https://bkper.com/platform/agents.md
Behavioral and domain context for building on the Bkper platform — technical instincts, quality standards, and product sensibilities.
Simplicity, essentialism, and speed with integrity aren't just values — they're survival strategies that enable a small team to deliver exceptional value globally.
## Technical Instincts
When you write code or architect systems on Bkper, certain principles are essential:
**Simplicity scales better than cleverness.** Reach for proven, boring technology over cutting-edge complexity. Build only what's essential — every line of code, every feature, every decision must earn its place.
**Data integrity is sacred.** In financial systems, eventual consistency isn't good enough. Protect the zero-sum invariant religiously — every dollar tracked must balance perfectly, extending this same rigor to any resource being tracked.
**Performance is user experience.** A fast system isn't a luxury — it's essential for users making rapid financial decisions about cash flow, expenses, and budgets.
**Security is foundational.** Bake security into every layer, knowing that the platform is trusted with sensitive financial data — bank connections, transaction details, and business intelligence.
**Global from day one.** Handle multiple currencies, units of measure, timezones, and formats as first-class concerns, not afterthoughts.
## Quality Instincts
**Tests are contracts with the future.** Tests aren't overhead — they're investments in confidence, documentation, and velocity. Reach for tests when fixing bugs, adding features, or refactoring code. A failing test that reproduces a bug is as valuable as the fix itself.
**Domain understanding precedes implementation.** Model the problem space before jumping to solutions, ensuring code reflects business reality rather than technical convenience. Think in terms of resources, their movements, and their relationships before writing the first line of code.
## Product Sensibilities
**Every feature has a cost.** Not just development time, but cognitive load, maintenance burden, and opportunity cost. Ask "Is this essential?" before "Is this worth it?" Choose the essential few over the trivial many.
**Convention over configuration.** Provide smart defaults that work for 80% of users while allowing power users to customize.
**Progressive disclosure.** Reveal complexity gradually, ensuring new users aren't overwhelmed while power users can access advanced features.
**Error messages are teaching moments.** When something goes wrong, help users understand why and how to fix it, using language they understand.
## How to Approach Problems
1. **Start with user pain.** Don't build features; solve problems. Every solution begins with understanding what's making users' lives difficult.
2. **Question the premise.** Before optimizing a workflow, ask whether it should exist. Before adding a feature, explore if you can eliminate the need for it. Ask "What can we remove?" before "What should we add?"
3. **Think in flows.** Whether it's cash flowing through accounts, inventory through stocks, or instruments through portfolios, visualize movement and identify where friction occurs.
4. **Consider the ecosystem.** Bkper exists in a broader financial context — banks, payment processors, accounting software, tax systems — while recognizing similar ecosystems exist for other resource types. Design for interoperability.
## Standards
**In Code:**
- Readable over clever
- Tested over "it works on my machine"
- Documented over self-documenting
- Maintainable over perfect
**In Design:**
- Intuitive over beautiful
- Accessible over trendy
- Consistent over unique
- Responsive over pixel-perfect
- Flexible over prescriptive
**In Communication:**
- Clear over comprehensive
- Actionable over theoretical
- Honest over diplomatic
- Constructive over critical
### Terms of Service
Source: https://bkper.com/terms.md
##### Updated August 29, 2022
### General Conditions
Bkper Inc. (“Bkper”, “We”) hosts bkper platform (“_bkper_”), websites and related services, in [datacenters](http://www.google.com/about/datacenters/) on Google infrastructure, including [Google Cloud Platform](https://cloud.google.com/), using its [technologies and following its principles](http://www.google.com/policies/technologies/).
By using _bkper_ and related services, The User (“You”) agrees with [Google’s Terms](http://www.google.com/policies/terms/) and [Privacy Policy](http://www.google.com/policies/privacy/), entering into the same legal relationship with Bkper, equivalent, in all aspects, with your legal agreement with Google.
By using _bkper_ and related services, You also agree that Bkper, as a Google Cloud Platform user, is bound to the [Terms of Services, Privacy Policy](https://developers.google.com/cloud/terms/) and [Acceptable Use Policy](https://developers.google.com/cloud/terms/aup) agreements of the latter, and therefore these agreements are also binding to You, and that Bkper can take any action necessary to ensure these conditions are fulfilled.
We assure You that all financial information in any [Book](https://help.bkper.com/en/articles/2569162-books) provided by _bkper_ is confidential and is the sole property of the owner of the Book, as set down in topic 7, _Confidential Information_, of [Google Cloud Platform Terms of Service](https://developers.google.com/cloud/terms/). You can also download and/or exclude all your data from _bkper_ at your convenience at any time.
By using _bkper_ and related services, You also agree that Bkper creates an Account for You to identify You, Your Content and any files on _bkper_. See our [Privacy Policy](https://bkper.com/privacy/.md) for more details.
### Free usage
Bkper has grouped features and established usage thresholds made available to You as a free version (“Free Plan”) of _bkper_. If You choose to use the Free Plan You agree that Bkper may, at its sole discretion, at any time and for any reason modify features, grouped features and usage thresholds, but will endeavor to provide reasonable advance notice via the Bkper website and/or electronic mail.
#### Upgrade from Free Plan to Paid Plan
You can at any time, via means provided to You on the Bkper website, or via electronic mail to Bkper, choose to Subscribe to a Paid Plan (“Change Plan”) to extend Your access to _bkper_ features, grouped features or usage thresholds that are different from Your Free Plan.
### Billing & Payment
Bkper may add additional features or groupings of features to _bkper_ and make these available to You as a paid version (“Paid Plan”). If You choose to Subscribe to a Paid Plan (Subscription), You shall pay Fees (described below) to Bkper. Upon selection of a Paid Plan, You will provide Bkper with the necessary billing information (“Billing Data”).
Bkper accepts Credit cards as payment mechanism of a monthly or yearly subscription Fee (“Subscription Fee”, “Fee”, “Fees”) for a Paid Plan. All currency references are in U.S. dollars. Paid Plans can be paid as either a monthly Subscription Fee or a yearly Subscription Fee. If You select a Paid Plan, You must provide current, complete and accurate Billing Data. You must promptly update all Billing Data to keep Your Account current, complete and accurate (such as a change in billing address, credit card number or credit card expiration date) and You must promptly notify Bkper if Your Payment Method is changed (for example, for loss or theft) or if You become aware of a potential breach of security, such as the unauthorized disclosure or use of Your name or password. If You fail to provide any of the foregoing information, You agree that Bkper may continue charging You for any use of the Paid Plan under your Billing Data unless You have “Terminated” Your Paid Plan as set forth herein.
### Monthly Billing
If You select the Monthly Fee, the credit card that You provide as part of the Billing Data will be automatically and immediately billed on the Day of Your Subscription. You agree that Bkper may charge to Your credit card all amounts due and owing for Your Account on that Day on a monthly basis or upon any Change in Your Paid Plan or upon Termination or Cancellation of Your Account. (see “Termination, Breach, Suspension and Cancellation” and “Refund”).
### Annual Billing
If You select the Yearly Fee, the credit card that You provide as part of the Billing Data will be automatically and immediately billed on the Day of Your Subscription. You agree that Bkper may charge to Your credit card all amounts due and owing for Your Account on that Day on a yearly basis or upon any change in Your Paid Plan or upon Termination or Cancellation of Your Account. (see “Termination, Breach, Suspension and Cancellation” and “Refund”).
Bkper will contact You via electronic mail to inform You upon each charge.
Bkper may change prices of Paid Plans at any time without prior notice, but will endeavor to provide reasonable advance notice via the Bkper website and/or electronic mail.
You agree that in the event Bkper is unable to collect the fees owed to Bkper for Your Account through Your Subscription Fee, Bkper may take any other steps it deems necessary to collect such fees from You and that You will be responsible for all costs and expenses incurred by Bkper in connection with such collection activity, including collection fees, court costs and attorneys’ fees. As long as Your Account remains active and in good standing, You will be charged the Subscription Fee even if You never use _bkper_. You may, however, Change from a Paid Plan to a Free Plan at any time.
If Your Subscription Fee payment is 15 days overdue, Bkper will disable Your access to the features provided by the Paid Plan. (see the “Termination, Breach, Suspension and Cancellation” and “Refund”).
Bkper billing and payment through the Google Cloud Platform Marketplace is subject to Payment Terms on the [Google Cloud Platform Terms of Service](https://cloud.google.com/terms/).
### Paid Usage
If You choose to use a Paid Plan You agree that Bkper may, at its sole discretion, at any time and for any reason modify features, grouped features and usage thresholds within Paid Plans, but will endeavor to provide reasonable advance notice via the Bkper website and/or electronic mail.
#### Upgrade or Downgrade Paid Plan
You can at any time, via means provided to on the Bkper website, or via electronic mail to Bkper, choose to Subscribe to the Free Plan or any Other Paid Plan (“Change Plan”) to reduce or extend Your access to _bkper_ features, grouped features or usage thresholds that are different from Your current Paid Plan.
### Termination, Breach, Suspension and Cancellation
Bkper may, at its sole discretion, at any time and for any reason, terminate the Service, Terminate this Agreement, or Suspend or terminate Your Account. In the event of suspension or termination, Your Account will be disabled and You may not be granted access to Your Account or any files or other Content (including Your User Content) contained in Your Account, and Bkper may Delete Your User Content, although copies of data or data itself may remain in our system for back-up and/or for regulatory and/or legal requirements. In the event of termination, Bkper may also withdraw and at its discretion reallocate any public web address related to Your Account.
You can request to Terminate Your Account, via means provided for cancellation on the Bkper website, or via electronic mail to Bkper, without reason at any time. Bkper will make all reasonable efforts to do so.
In the event of Account Termination Your Content and files contained in Your Account, will not be accessible to You and Deleted after meeting any Regulatory and/or legal requirements. After You Terminate Your Account, Content and files are unavailable to You.
### Refund
You can change your Subscription at any time from a Paid Plan to a Free Plan, meaning that Your credit card will not be charged anymore. You continue to have access to the Paid Plan features, grouped features or usage thresholds through to the end of your billing period. After this period, Your Account will continue with access to _bkper_ in the Free Plan.
You may request a refund related to your Paid Plan (Subscription) at any time via means provided by Bkper, such as a support channel and/or electronic mail. Bkper honors refund requests at its sole discretion for the current active subscription period (either month or year, depending on your plan). Refunds are not be provided for any previous already completed subscription periods, regardless of usage.
### Disclaimers, Indemnity & Limited Liability
#### Responsibility Disclaimer
Bkper isn’t a professional services firm of any sort, and isn’t in the business of giving any kind of professional advice. Through our Websites and Apps we may provide you with information we think might be useful in running your personal finances or business, but this should not be seen as a substitute for any professional advice and we aren’t liable in that way.
#### Warranty Disclaimer
Bkper services and all third-party products are made available to you on an “as is” basis. We disclaim all warranties, express or implied, including any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
#### Indemnity
You indemnify us against all losses, costs (including legal costs), expenses, demands or liability that we incur arising out of, or in connection with, a third-party claim against us relating to your use of our services or any third-party product (except as far as we’re at fault).
#### Limited Liability
Our liability to you in connection with our services or these terms, in contract, tort (including negligence) or otherwise, is limited as follows:
We have no liability arising from your use of our services for any loss of revenue or profit, loss of goodwill, loss of customers, loss of capital, loss of anticipated savings, legal, tax or accounting compliance issues, damage to reputation, loss in connection with any other contract, or indirect, consequential, incidental, punitive, exemplary or special loss, damage or expense.
For loss or corruption of your data (as far as we’re at fault), our liability will be limited to taking reasonable steps to try and recover that data from available backups.
### Changes in Terms
Bkper reserves the right, at its sole discretion, to change, modify, add or remove portions of these Terms of Service, at any time. It is your responsibility to check these Terms of Service periodically for changes. Your continued use of Bkper following the posting of changes will mean that you accept and agree to the changes. As long as you comply with these Terms of Use, Bkper grants you a personal, non-exclusive, non-transferable, limited privilege to enter and use Bkper.
For more information or further questions, email us at [legal@bkper.com](https://bkper.com/mailto:legal@bkper.com).
#### Related links - Google:
Policies & Principles: [http://www.google.com/policies/](http://www.google.com/policies/) Privacy Policy: [http://www.google.com/policies/privacy/](http://www.google.com/policies/privacy/) Google Terms of Service: [http://www.google.com/policies/terms/](http://www.google.com/policies/terms/) Technologies and Principles: [http://www.google.com/policies/technologies/](http://www.google.com/policies/technologies/)
#### Related Links - Google Cloud Platform:
Terms of Service: [https://developers.google.com/cloud/terms/](https://developers.google.com/cloud/terms/) Acceptable Use Policy: [https://developers.google.com/cloud/terms/aup](https://developers.google.com/cloud/terms/aup)
#### Related Links - Bkper:
Privacy Policy: [https://bkper.com/privacy/](https://bkper.com/privacy/) Cookie Policy: [https://bkper.com/cookies/](https://bkper.com/cookies/)
bkper.com is built by Bkper Inc. on top of Google Cloud Platform but is not affiliated to Google.
* * *
_The trademarks, logos, and service marks (collectively the “Trademarks”) displayed on this Web Site are registered and unregistered trademarks of Bkper Inc. its affiliates and others. You can view trademarks owned by Bkper Inc. on LegalForce Trademarkia at this link: [https://www.trademarkia.com/owners/bkper-inc](https://www.trademarkia.com/owners/bkper-inc). Nothing contained on this Web Site should be construed as granting, by implication, estoppel, or otherwise, any license or right to use any Trademark displayed on this Web Site without the written permission of Bkper Inc. or such third party that may own the trademark displayed on this Web Site. Your misuse of the Trademarks displayed on this Web Site, or any other content on this Web Site, except as provided herein, is strictly prohibited._
### Privacy Policy
Source: https://bkper.com/privacy.md
Updated December 12, 2017
Welcome to the Bkper Privacy Policy. This Bkper Privacy Policy (“Policy”) describes how Bkper Inc. (“Bkper,” “we,” “us” or “our”) collects, uses and discloses your personal information. This Policy applies to information we collect when you use our websites, mobile applications and other online products and services where this Policy is posted (collectively, the “Services”).
We may change the provisions of this Policy at any time and will indicate when changes have been made by revising the date at the top of this Policy. Your use of the Services, or any portion thereof, following the posting of such changes shall constitute your consent to such changes. We encourage you to review the Policy whenever you access the Services to make sure that you understand our information collection, use and disclosure practices. If we make material changes to this policy, we will provide you with additional notice of such changes and request your affirmative consent before using or sharing previously collected information in a materially different way.
By providing us with Personal Data, you are consenting to our use of it in accordance with this Privacy Policy.
### Information That You Provide to Us
**Personal Information.** Bkper may collect information that you provide when you use the Services, such as when you: (1) create an account; (2) make a purchase; (3) participate in events or promotions; (4) send questions or comments via e-mail or live chat to Bkper customer support; (5) submit your resume to us online; (6) fill out surveys; or (7) otherwise communicate with us through the Services. The types of personal information that you provide may include your name, e-mail address, telephone number, postal address and other contact or identifying information that you choose to provide.
**Your Data.** Bkper stores, processes and maintains files that you create and/or upload using the Services (as well as previous versions of your files), including Bkper books, accounts, transactions and files that you create and other data related to your account in order to provide the Services to you.
### Information That We Collect Automatically From You
Account activity. Bkper automatically records certain information about your use of bkper. Similar to other web services, Bkper uses both permanent and session cookies, web beacons, and pixel tracking technology to record information such as account activity (e.g., storage usage, number of log-ins, actions taken), data displayed or clicked on (e.g., UI elements, links), other log information (e.g., browser type, IP address, date and time of access, cookie ID, referrer URL, etc.), and to remember user preferences while using the Services. Bkper may collect automated error reports in the case of software malfunction that may be reviewed to help resolve problems in bkper.
### Information We Collect From Third Parties
We may obtain information from other sources and combine that with information we collect through our Services. For example, if you create or log into your Google account, we will have access to certain information from that account, such as your email, name and photo, in accordance with the authorization procedures determined by Google.
If you elect to purchase a subscription to use bkper, we may receive information about your purchase from our third-party payment processor, such as your credit card information, security code, and billing address.
We use analytics services and software provided by third parties to help us understand how users access and use the Services. These tools and services place cookies, web beacons and other devices or technologies on our Services to enable them to track traffic data. The data collected typically includes information such as your IP address, your Internet Service Provider, your web browser, the time spent on webpages. We use this information exclusively to improve our Services and your experience, to see which areas and features of our Services are popular and to count visits.
### How We Use Your Information
#### Personal Information
We use personal information collected through bkper’s services for purposes described in this Policy or otherwise disclosed to you in connection with our services. For example, we may use your information to:
- Operate and improve our services;
- Send you information about new products, contests, features and enhancements, special offers and other events of interest from Bkper and our partners;
- Provide and deliver the products and services you request, process transactions, and to send you related information, including confirmations and invoices;
- Send you technical notices, updates, security alerts and support and administrative messages;
- Respond to your comments, questions and requests and provide customer service;
- Monitor and evaluate trends, usage and activities in connection with our Services;
- We may share with third parties certain pieces of aggregated, non-personal information, such as the number of users who used a Bkper for business purposes. Such information does not identify you individually.
#### Your Data
All information in any Book or uploaded file is confidential and belongs to the owner of the Book. It is not shared outside our services by any means or with our staff, except when you do so. You can also download and/or exclude all your data from bkper at your convenience.
Files you create, upload, or copy to Bkper may, if you choose, be read, copied, used and redistributed by people you know or, again if you choose (by our sharing functionality), by people you do not know.
Information you disclose using the chat function of Bkper may be read, copied, used and redistributed by people participating in the chat. Use care when including sensitive personal information in files you share or in chat sessions, such as social security numbers, financial account information, home addresses or phone numbers.
### Data Security
Bkper takes reasonable measures to protect your personal information and your files from loss, misuse and unauthorized access, disclosure, alteration and destruction and to ensure that your files remain available to you.
### Your Choices
You may terminate your use of Bkper at any time.
Editing or Deleting your Personal Information. If you have created an account, you may at any time review and/or update the contact information we have for you. Please note that even if you delete information from your account, or deactivate it, we may retain certain information as required by law or for legitimate business purposes. We may also retain cached or archived copies of your information for a certain period of time.
You may elect to stop receiving our marketing emails by following the unsubscribe instructions included in such emails, or you may contact us at [contact@bkper.com](https://bkper.com/mailto:contact@bkper.com)
You may elect to stop receiving our weekly update emails by following the unsubscribe instructions included in such emails, or you may contact us at [contact@bkper.com](https://bkper.com/mailto:contact@bkper.com)
If you elect to stop receiving our marketing emails and or weekly updates, we may still send you transactional or relationship messages, such as emails about your account or our ongoing business relations.
Cookies. Most web browsers are set to accept cookies by default. If you prefer, you can usually choose to set your browser to remove or reject browser cookies. Please note that if you choose to remove or reject cookies, this could affect the availability and functionality of our Services.
### Cookie Policy
Source: https://bkper.com/cookies.md
##### Updated September 11, 2024
To make our websites and products work we place small data files called Cookies on your device.
### What are Cookies?
A cookie is a small text file that a Website or App stores on your computer or mobile device when you visit a Website or App.
**First party cookies** are cookies set by the Website or App you’re visiting. Only this Website or App can read them. In addition, a Website or App might potentially use external services, which also set their own cookies, known as **third-party cookies**.
**Persistent cookies** are cookies saved on your computer and that are not deleted automatically when you quit your browser, unlike a **session cookie**, which is deleted when you quit your browser. The Bkper Website and Bkper App make use of all these types of Cookies.
The purpose is to enable the Website and App to remember your preferences (such as user name, language, etc.) and your current position (in App navigation) for a certain period of time.
That way, you don’t have to re-enter them or re-start at a point zero when browsing around the Website or App during the same visit or a future visit.
Cookies can also be used to establish anonymised statistics about the browsing experience on our Website and App (specially by third party Cookies).
### How do we use Cookies?
Bkper Websites and App use **first-party cookies**. These are cookies set and controlled by the Bkper team, and are used purely for the purpose of providing a great user experience and to continuously improve that experience. These are not accessed or controlled in any way by any external organisation.
However, our Websites and App also make use of **third party Cookies** that you will have to accept from external organisations (listed below).
Since our Website, App and Business aren’t operable without the use of Cookies, You, by accessing and using our Website and App agree with this Cookie policy.
#### List of Cookies we use
| Name | Service | Purpose | Type & Duration | Details |
| --- | --- | --- | --- | --- |
| Source | bkper.app | Store http referer to know where the user came from | First, 2 years | Anonymised, for statistical purposes |
| visitedLP | bkper.app | Know the journey through the Bkper website to login | First, 2 years | |
| already-logged | bkper.app | Store if you already logged in the app | First, 2 years | |
| \_\_utma | ga.js | Used to distinguish users and sessions | Third, 2 years | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_\_utmc | ga.js | Determine whether the user was in a new session/visit | Third, session | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_\_utmz | ga.js | Stores the traffic source or campaign that explains how the user reached us | Third, 6 months | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_\_utmt | ga.js | Used to throttle request rate | Third, 10 minutes | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_\_utmb | ga.js | Used to determine new sessions/visits | Third, 30 minutes | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_ga | gtag.js | Used to distinguish users | Third, 2 years | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_gid | gtag.js | Used to distinguish users | Third, 24 hours | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_gat | gtag.js | Used to throttle request rate | Third, 1 minute | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| \_gaexp | Optimize | Used to determine a user's inclusion in an experiment | Third, ~14 days | [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookie-usage#gajs) |
| SSID | Google | Google collects visitor information for videos hosted by YouTube on maps integrated with Google Maps | Third, persistent | |
| SID | Google | Security cookie to confirm visitor authenticity, prevent fraudulent use of login data | Third, 2 years | |
| DSID | Google | Used to link your activity across devices if you've previously signed in to your Google Account | Third, 1 year | [Google](https://policies.google.com/technologies/types?hl=en-US) |
| HSID | Google | Security cookie to confirm visitor authenticity | Third, 2 years | [Google](https://policies.google.com/technologies/types?hl=en-US) |
| LSID | Google | Used to remain connected to your Google Account | Third, 2 years | |
| SIDCC | Google | Security cookie to confirm visitor authenticity | Third, 3 months | |
| SAPISID | Google | Google collects visitor information for videos hosted by YouTube | Third, persistent | |
| APISID | Google | Personalizes Google ads on websites based on recent searches | Third, 2 years | |
| intercom-session-muankhdn | Intercom | Keep track of sessions | Third, 1 week | [Intercom](https://www.intercom.com/help/en/articles/2361922-intercom-messenger-cookies) |
| \_\_Secure-3PSID | Google | Builds a profile of website visitor interests for personalized ads | Third, 2 years | |
| \_\_Secure-3PSIDCC | Google | Builds a profile of website visitor interests for personalized ads | Third, 2 years | |
| \_\_Secure-3PAPISID | Google | Builds a profile of website visitor interests for personalized ads | Third, 2 years | |
| JSESSIONID | J2EE | Session management in the J2EE web application for HTTP protocol | Third, 2 years | |
| \_\_stripe\_mid | Stripe | Fraud prevention and detection | Third, 1 year | [Stripe](https://stripe.com/cookies-policy/legal) |
| GWT\_LOCALE | Google Web Toolkit | Store locale settings | Third, 2 years | |
| IDE | Google | Used by Google DoubleClick to register and report website user actions | Third | [Google](https://policies.google.com/technologies/types?hl=en-US) |
| 1P\_JAR | Google | Based on recent searches and previous interactions, custom ads are shown | Third, 1 week | |
| NID | Google | Stores visitors' preferences and personalizes ads | Third, 6 months | [Google](https://policies.google.com/technologies/types?hl=en-US) |
| ANID | Google | Lists ads on Google sites based on recent searches | Third, persistent | [Google](https://policies.google.com/technologies/types?hl=en-US) |
| OTZ | Google | Links activities of website visitors to other devices previously logged in | Third, 1 month | |
| UULE | Google Analytics | User behaviour on websites | Third, 1 day | |
| G\_ENABLED\_IDPS | Google Authentication | Google Login | Third, persistent | |
| G\_AUTHUSER\_H | Google Authentication | Google Login | Third, session | |
| \_\_Host-GAPS | Google | Pending | Third, 2 years | |
| ACCOUNT\_CHOOSER | Google | Google Accounts login | Third, variable | |
| \_\_Host-3PLSID | Google | Required for the use of the options and services of the website | Third, 2 years | |
| SMSV | Google | Google Accounts login | Third, variable | |
| LSOLH | Google | Required for the use of the options and services of the website | Third, 1 year | |
### Third Party Cookies
Our Website and App make use of content from external providers, e.g. YouTube, Intercom, and Stripe.
To view this third-party content, you have to accept their specific terms and conditions. This includes their cookie policies, which we have no control over.
But if you do not view this content, no third-party cookies are installed on your device.
**Third party providers on Bkper websites and Bkper App**
[Google.com](https://policies.google.com/technologies/cookies) [Intercom.com](https://www.intercom.com/legal/cookie-policy) [Stripe.com](https://stripe.com/cookies-policy/legal) [Youtube.com](https://www.youtube.com/t/terms)
These third-party services are outside of the control of Bkper. Providers may, at any time, change their terms of service, purpose and use of cookies, etc.
### How can you manage cookies?
You can manage/delete cookies as you wish - for details, see [aboutcookies.org](https://www.aboutcookies.org/).
#### Removing cookies from your device
You can delete all cookies that are already on your device by clearing the browsing history of your browser. This will remove all cookies from all websites you have visited.
Be aware though that you may also lose some saved information (e.g. saved login details, site preferences).
#### Managing site-specific cookies
For more detailed control over site-specific cookies, check the privacy and cookie settings in your preferred browser.
#### Blocking cookies
You can set most modern browsers to prevent any cookies being placed on your device, but you may then have to manually adjust some preferences every time you visit a Website or App. And some services and functionalities may not work properly at all (e.g. profile logging-in).
## Docs
---
source: /docs/ai-tooling.md
# AI Tooling
Every page on bkper.com is available as clean Markdown so AI tools can read it, understand the platform, and help you use or build with it.
The root index of all pages is available at [`/llms.txt`](https://bkper.com/llms.txt), and a single-file dump of all site content at [`/llms-full.txt`](https://bkper.com/llms-full.txt).
## Page Options
Every documentation page and app detail page includes a **Page Options** dropdown in the right sidebar:

Copy the page as Markdown, open it directly in [Claude](https://claude.ai) or [ChatGPT](https://chatgpt.com), or grab a ready-made prompt for your AI tool of choice.
## Page Access
Marketing pages, documentation, and app listings are all available as Markdown. Navigation chrome (sidebar, header, footer) is stripped, reducing token usage for AI tools.
### `.md` suffix
Append `.md` to any page URL:
```
https://bkper.com/about # HTML (browser)
https://bkper.com/about.md # Markdown (AI tools)
https://bkper.com/docs/core-concepts.md
```
```sh
curl https://bkper.com/docs/core-concepts.md
```
### Section `.md`
Section URLs return prose from the section index plus a listing of child articles and subsections:
```sh
curl https://bkper.com/docs.md # Documentation root
curl https://bkper.com/docs/guides.md # Guides section
curl https://bkper.com/apps.md # Apps directory
```
> **Tip: Starting points**
> Give your AI tool a section endpoint and let the conversation narrow from there:
>
> - [`/docs/guides.md`](https://bkper.com/docs/guides.md) — user-facing guides
> - [`/docs/build.md`](https://bkper.com/docs/build.md) — developer docs
> - [`/docs/api.md`](https://bkper.com/docs/api.md) — all API libraries at a glance
### `Accept` header
Request Markdown via [content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Content_negotiation) by including `text/markdown` in the `Accept` header. This works with the canonical page URL — no URL modification needed:
```sh
curl https://bkper.com/docs/core-concepts \
-H "Accept: text/markdown"
```
The response includes an `x-markdown-tokens` header with the estimated token count, which agents can use to plan context window usage:
```
HTTP/2 200
content-type: text/markdown; charset=utf-8
vary: Accept
x-markdown-tokens: 1850
```
## API References
API reference endpoints compile the library overview and full spec into a single compact document optimized for agent workflows:
- [`/docs/api/rest.md`](https://bkper.com/docs/api/rest.md) — endpoints, parameters, and data models
- [`/docs/api/bkper-js.md`](https://bkper.com/docs/api/bkper-js.md) — bkper-js README + TypeScript definitions
- [`/docs/api/bkper-gs.md`](https://bkper.com/docs/api/bkper-gs.md) — bkper-gs README + TypeScript definitions
- [`/docs/api/bkper-api-types.md`](https://bkper.com/docs/api/bkper-api-types.md) — shared TypeScript type definitions
- [`/docs/api/bkper-web-auth.md`](https://bkper.com/docs/api/bkper-web-auth.md) — OAuth browser SDK
Compiled Markdown vs raw source (overview + `openapi.json` or `.d.ts`):
| Library | Raw (tokens) | `.md` (tokens) | Reduction |
|---|---|---|---|
| REST API | ~38K | ~9K | 4× |
| bkper-js | ~32K | ~18K | 1.8× |
| bkper-gs | ~22K | ~12K | 1.9× |
| bkper-api-types | ~12K | ~5K | 2.4× |
| bkper-web-auth | ~2K | ~2K | ~1× |
---
source: /docs/api.md
# API Reference
Technical reference documentation for all Bkper APIs and SDKs. Use the REST API directly or choose a client library for your platform.
- [REST API](https://bkper.com/docs/api/rest.md): Full OpenAPI reference for the Bkper REST API — endpoints, parameters, and response schemas.
- [bkper-js](https://bkper.com/docs/api/bkper-js.md): JavaScript/TypeScript client library for Bkper — classes, interfaces, and type definitions.
- [bkper-gs](https://bkper.com/docs/api/bkper-gs.md): Google Apps Script library for Bkper — use Bkper directly in Google Sheets and Apps Script projects.
- [bkper-web-auth](https://bkper.com/docs/api/bkper-web-auth.md): Web authentication SDK for Bkper — OAuth flows, token management, and session handling.
- [bkper-api-types](https://bkper.com/docs/api/bkper-api-types.md): TypeScript type definitions for the Bkper API — shared interfaces and enumerations.
- [Design Tokens](https://bkper.com/docs/api/bkper-web-design.md): CSS design tokens — typography, spacing, colors, and theming for Bkper web applications.
---
source: /docs/api/bkper-api-types.md
# bkper-api-types
This package contains Typescript definitions for the [Bkper REST API](https://bkper.com/docs/#rest-api).
The types are generated based on the Bkper [Open API spec](https://bkper.com/docs/api/rest/openapi.json) using the [dtsgenerator](https://github.com/horiuchi/dtsgenerator) tool.
More information at the [Bkper Developer Documentation](https://bkper.com/docs/#rest-api)
[](https://www.npmjs.com/package/@bkper/bkper-api-types) [](https://github.com/bkper/bkper-api-types)
### 1) Add the package:
```bash
npm i -S @bkper/bkper-api-types
```
### 2) Configure tsconfig.json:
```
{
"compilerOptions": {
"typeRoots" : ["node_modules/@bkper", "node_modules/@types" ]
}
}
```
[Learn more](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#types-typeroots-and-types) about **@types**, **typeRoots** and **types**
---
source: /docs/api/bkper-gs.md
# bkper-gs
[](https://github.com/google/clasp) [](https://www.npmjs.com/package/@bkper/bkper-gs-types) [](https://github.com/bkper/bkper-gs)
## bkper-gs
`bkper-gs` library provides a simple and secure way to access the [Bkper REST API](https://bkper.com/docs/#rest-api) through [Google Apps Script](https://developers.google.com/apps-script/reference/) infrastructure.
With `bkper-gs` you can build [Apps and Bots](https://bkper.com/docs/) to your Books to create bookkeeping and accounting solutions on Google Workspace, such as the Bkper [Add-on for Google Sheets](https://workspace.google.com/marketplace/app/bkper/360398463400), simple automations or advanced solutions, and you can manage your scripts in the [Dashboard](https://script.google.com/home).
It works the same way your favorite Google Apps Script library works, providing a **BkperApp** entry point, like [CalendarApp](https://developers.google.com/apps-script/reference/calendar/calendar-app), [DocumentApp](https://developers.google.com/apps-script/reference/document/document-app), [SpreadsheetApp](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app) and the like.
### Setup
This library is already published as an [Apps Script](https://script.google.com/d/1hMJszJGSUVZDB3vmsWrUZfRhY1UWbhS0SQ6Lzl06gm1zhBF3ioTM7mpJ/edit?usp=sharing), making it easy to include in your project. To add it to your script, do the following in the Apps Script code editor:
1. Click on the menu item "Resources > Libraries..."
2. In the "Add a Library" text box, enter the Script ID "**1hMJszJGSUVZDB3vmsWrUZfRhY1UWbhS0SQ6Lzl06gm1zhBF3ioTM7mpJ**" and click the "Select" button.
3. Choose a version in the dropdown box (usually best to pick the latest version).
4. Click the "Save" button.
#### Typescript Definitions for autocomplete:
To use TypeScript in the development of an Apps Script project, see the [Develop Apps Script using TypeScript](https://developers.google.com/apps-script/guides/typescript) as reference.
##### 1) Add the package:
```bash
npm i -S @bkper/bkper-gs-types
```
##### 2) Configure tsconfig.json:
```
{
"compilerOptions": {
"typeRoots" : ["node_modules/@bkper", "node_modules/@types" ]
}
}
```
[Learn more](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#types-typeroots-and-types) about **@types**, **typeRoots** and **types**
### Get a Book
The get a [Book](https://bkper.com/docs/bkper-gs/#book), use the parameter found on the URL accessed on [bkper.com](https://bkper.com):

To get the Book name:
```javascript
function getBookName() {
var book = BkperApp.getBook('agtzfmJrcGVyLWhyZHIOCxIGTGVkZ2VyGNKJAgw');
var bookName = book.getName();
}
```
### Record Transactions
To record a simple transaction:
```javascript
function recordATransaction() {
var book = BkperApp.getBook('agtzfmJrcGVyLWhyZHIOCxIGTGVkZ2VyGNKJAgw');
book.record('#gas 63.23');
}
```
You can also record transactions in batch by passing an Array of strings as the [record](https://bkper.com/docs/bkper-gs/#book_record) method parameter:
```javascript
function batchRecordTransactions() {
var book = BkperApp.getBook('agtzfmJrcGVyLWhyZHIOCxIGTGVkZ2VyGNKJAgw');
var transactions = new Array();
transactions.push('#breakfast 15.40');
transactions.push('#lunch 27.45');
transactions.push('#dinner 35.86');
book.record(transactions);
}
```
The above code will send all records in a bulk. Very useful for importing large amount of data without the risk of reaching script limits.
### List Transactions
Each book is a large database and every interaction is done in terms of queries. Everytime you "select" an [Account](https://bkper.com/docs/bkper-gs/#account) by clicking on left menu at [bkper.com](https://bkper.com), you are actually filtering transactions by that [Account](https://bkper.com/docs/bkper-gs/#account).
When you retrieve transactions, the [getTransactions](https://bkper.com/docs/bkper-gs/#book_gettransactions) method returns an [TransactionIterator](https://bkper.com/docs/bkper-gs/#transactioniterator) to let you handle potentially large datasets:
```javascript
function listTransactions() {
var book = BkperApp.getBook('agtzfmJrcGVyLWhyZHITCxIGTGVkZ2VyGICAgKCtg6MLDA');
//GetTransactions returns an interator to deal with potencial large datasets
var transactionIterator = book.getTransactions("account:'Bank' after:01/04/2014");
while (transactionIterator.hasNext()) {
var transaction = transactionIterator.next();
Logger.log(transaction.getDescription());
}
}
```
Run the **queryTransactions** function, exchanging your bookId, with the same query, check the log output and you will see the same descriptions:

### List Accounts
You can access all Account objects, in a way similar to the left sidebar:
```javascript
function listAccounts() {
//Open the book
var book = BkperApp.getBook('agtzfmJrcGVyLWhyZHIOCxIGTGVkZ2VyGNKJAgw');
var accounts = book.getAccounts();
for (var i = 0; i < accounts.length; i++) {
var account = accounts[i];
if (account.isPermanent() && account.isActive()) {
Logger.log(account.getName() + ': ' + account.getBalance());
}
}
}
```
---
source: /docs/api/bkper-js.md
# bkper-js
bkper-js library is a simple and secure way to access the [Bkper REST API](https://bkper.com/docs/api/rest) on Node.js and modern browsers.
It provides a set of classes and functions to interact with the Bkper API, including authentication, authorization, and data manipulation.
[](https://www.npmjs.com/package/bkper-js) [](https://github.com/bkper/bkper-js)
### Add the package:
```bash
npm i -S bkper-js
```
### CDN / Browser
The simplest way to use bkper-js in a browser — no build tools, no npm, just a `
```
Get an access token with the [Bkper CLI](https://www.npmjs.com/package/bkper):
```bash
bkper auth login # one-time setup
bkper auth token # prints a token (valid for 1 hour)
```
Pin to a specific version by replacing `@2` with e.g. `@2.31.0`.
### Node.js / CLI Scripts
For local scripts and CLI tools, use the [bkper](https://www.npmjs.com/package/bkper) CLI package for authentication:
```typescript
import { Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
// Configure with CLI authentication
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
// Create Bkper instance
const bkper = new Bkper();
// Get a book and work with it
const book = await bkper.getBook('your-book-id');
console.log(`Book: ${book.getName()}`);
// List all books
const books = await bkper.getBooks();
console.log(`You have ${books.length} books`);
```
First, login via CLI: `bkper auth login`
### npm + Bundler
If you are using a bundler (Vite, webpack, esbuild, etc.), install from npm and provide an access token the same way as the CDN example:
```typescript
import { Bkper } from 'bkper-js';
Bkper.setConfig({
oauthTokenProvider: async () => 'your-access-token',
});
const bkper = new Bkper();
const books = await bkper.getBooks();
```
### Web Applications on \*.bkper.app
> **Note:** `@bkper/web-auth` **only works on `*.bkper.app` subdomains**. Its session cookies are scoped to the `.bkper.app` domain and will not work on any other domain. For apps on other domains, use the [CDN / Browser](#cdn--browser) approach with an access token instead.
For apps hosted on `*.bkper.app` subdomains, use the [@bkper/web-auth](https://www.npmjs.com/package/@bkper/web-auth) SDK for built-in OAuth login flow:
```typescript
import { Bkper } from 'bkper-js';
import { BkperAuth } from '@bkper/web-auth';
// Initialize authentication
const auth = new BkperAuth({
onLoginSuccess: () => initializeApp(),
onLoginRequired: () => showLoginButton(),
});
// Restore session on app load
await auth.init();
// Configure Bkper with web auth
Bkper.setConfig({
oauthTokenProvider: async () => auth.getAccessToken(),
});
// Create Bkper instance and use it
const bkper = new Bkper();
const books = await bkper.getBooks();
```
See the [@bkper/web-auth documentation](https://bkper.com/docs/auth-sdk) for more details.
### API Key (Optional)
API keys are optional and only needed for dedicated quota limits. If not provided, requests use a shared managed quota via the Bkper API proxy.
```typescript
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
apiKeyProvider: async () => process.env.BKPER_API_KEY, // Optional - for dedicated quota
});
```
---
source: /docs/api/bkper-web-auth.md
# @bkper/web-auth
[](https://www.npmjs.com/package/@bkper/web-auth) [](https://github.com/bkper/bkper-web-sdks)
# @bkper/web-auth
OAuth authentication SDK for apps on the [Bkper Platform](https://bkper.com/docs/build/apps/overview) (`*.bkper.app` subdomains).
## Installation
```bash
bun add @bkper/web-auth
```
## Quick Start
```typescript
import { BkperAuth } from '@bkper/web-auth';
// Initialize client with callbacks
const auth = new BkperAuth({
onLoginSuccess: () => {
console.log('User authenticated!');
loadUserData();
},
onLoginRequired: () => {
console.log('Please sign in');
showLoginButton();
},
});
// Initialize authentication flow on app load
await auth.init();
// Get access token for API calls
const token = auth.getAccessToken();
if (token) {
fetch('/api/data', {
headers: { Authorization: `Bearer ${token}` },
});
}
```
## Handling Token Expiration
Access tokens expire and need to be refreshed. The recommended pattern is to handle authentication errors and retry:
```typescript
async function apiRequest(url: string, options: RequestInit = {}) {
// Add auth header
const token = auth.getAccessToken();
options.headers = {
...options.headers,
Authorization: `Bearer ${token}`,
};
const response = await fetch(url, options);
// Handle expired token
if (response.status === 403) {
try {
await auth.refresh();
options.headers = {
...options.headers,
Authorization: `Bearer ${auth.getAccessToken()}`,
};
return fetch(url, options); // Retry once
} catch (error) {
// Refresh failed - the onError callback will be triggered
// Handle the error appropriately (e.g., redirect to login, show error message)
throw error;
}
}
return response;
}
```
## What's Included
- OAuth authentication SDK for apps on `*.bkper.app` subdomains
- Callback-based API for authentication events
- OAuth flow with in-memory token management
- Token refresh mechanism
- TypeScript support with full type definitions
## How It Works
**Session Persistence:**
- Access tokens are stored in-memory (cleared on page refresh)
- Sessions persist via HTTP-only cookies scoped to the `.bkper.app` domain
- Call `init()` on app load to restore the session from cookies
> **Note:** This SDK only works for apps hosted on `*.bkper.app` subdomains. For apps on other domains, use a valid access token directly with [bkper-js](https://github.com/bkper/bkper-js#cdn--browser).
**Security:**
- HTTP-only cookies protect refresh tokens from XSS
- In-memory access tokens minimize exposure
## TypeScript Support
This package is written in TypeScript and provides full type definitions out of the box. All public APIs are fully typed, including callbacks and configuration options.
```typescript
import { BkperAuth, BkperAuthConfig } from '@bkper/web-auth';
const config: BkperAuthConfig = {
onLoginSuccess: () => console.log('Authenticated'),
onError: error => console.error('Auth error:', error),
};
const auth = new BkperAuth(config);
```
## Browser Compatibility
This package requires a modern browser with support for:
- [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility) for HTTP requests
- [Location API](https://developer.mozilla.org/en-US/docs/Web/API/Location) for login/logout redirects
The app must be deployed to a `*.bkper.app` subdomain for session cookies to work.
---
source: /docs/api/bkper-web-design.md
# Design Tokens
[](https://www.npmjs.com/package/@bkper/web-design) [](https://github.com/bkper/bkper-web-sdks)
# @bkper/web-design
Bkper's design system - CSS variables, tokens, and themes.
## Installation
```bash
npm install @bkper/web-design
```
## Usage
Import in your build system:
```css
@import '@bkper/web-design';
```
Or link directly in HTML:
```html
```
Alternatively, skip installation and link directly to a hosted version (CDN):
```html
```
Note: The CDN serves the most recent npm release.
## Web Awesome Integration
This package works standalone with sensible default values. If [Web Awesome](https://www.webawesome.com/) is loaded, Bkper tokens will automatically inherit from Web Awesome's design system for seamless integration.
## Design Tokens
### Typography
| Token | Default | Web Awesome Fallback |
| :--- | :--- | :--- |
| `--bkper-font-family` | `ui-sans-serif, system-ui, sans-serif` | `--wa-font-family-body` |
| `--bkper-font-family-code` | `ui-monospace, monospace` | `--wa-font-family-code` |
| `--bkper-font-size-x-small` | `0.75rem` | `--wa-font-size-xs` |
| `--bkper-font-size-small` | `0.85rem` | — |
| `--bkper-font-size-medium` | `1rem` | `--wa-font-size-m` |
| `--bkper-font-size-large` | `1.25rem` | `--wa-font-size-l` |
| `--bkper-font-weight-bold` | `600` | `--wa-font-weight-bold` |
| `--bkper-line-height-normal` | `1.8` | — |
### Border
| Token | Default | Web Awesome Fallback |
| :--- | :--- | :--- |
| `--bkper-border` | `1px solid var(--bkper-color-border)` | — |
| `--bkper-border-radius` | `0.375rem` | `--wa-border-radius-m` |
### Spacing
| Token | Default | Web Awesome Fallback |
| :--- | :--- | :--- |
| `--bkper-spacing-3x-small` | `0.125rem` | `--wa-space-3xs` |
| `--bkper-spacing-2x-small` | `0.25rem` | `--wa-space-2xs` |
| `--bkper-spacing-x-small` | `0.5rem` | `--wa-space-xs` |
| `--bkper-spacing-small` | `0.75rem` | `--wa-space-s` |
| `--bkper-spacing-medium` | `1rem` | `--wa-space-m` |
| `--bkper-spacing-large` | `1.5rem` | `--wa-space-l` |
| `--bkper-spacing-x-large` | `2rem` | `--wa-space-xl` |
| `--bkper-spacing-2x-large` | `2.5rem` | `--wa-space-2xl` |
| `--bkper-spacing-3x-large` | `3rem` | `--wa-space-3xl` |
| `--bkper-spacing-4x-large` | `4rem` | `--wa-space-4xl` |
### Color
| Token | Default | Web Awesome Fallback |
| :--- | :--- | :--- |
| `--bkper-color-black` | `#1b1d26` | — |
| `--bkper-color-white` | `#f1f2f3` | — |
| `--bkper-color-primary` | `#0071ec` | `--wa-color-brand-50` |
| `--bkper-color-success` | `#00883c` | `--wa-color-success-50` |
| `--bkper-color-danger` | `#dc3146` | `--wa-color-danger-50` |
| `--bkper-color-warning` | `#b45f04` | `--wa-color-warning-50` |
| `--bkper-color-focus` | `#3e96ff` | `--wa-color-focus` |
### Contextual Colors
These tokens change between light and dark themes.
| Token | Light | Dark | Web Awesome Fallback |
| :--- | :--- | :--- | :--- |
| `--bkper-color-text` | `var(--bkper-color-black)` | `var(--bkper-color-white)` | `--wa-color-text-normal` |
| `--bkper-color-link` | `#0053c0` | `#6eb3ff` | `--wa-color-text-link` |
| `--bkper-color-background` | `white` | `#101219` | `--wa-color-surface-default` |
| `--bkper-color-border` | `#e4e5e9` | `#2f323f` | `--wa-color-surface-border` |
| `--bkper-color-neutral` | `#2f323f` | `#e4e5e9` | `--wa-color-neutral-20` |
#### Account Type Colors
Five color families map to Bkper account types, each at three intensity levels. Values change between themes for optimal contrast.
**Grey — Neutral**
| Level | Token | Light | Dark |
| :--- | :--- | :--- | :--- |
| low | `--bkper-color-grey-low` | `#f5f5f5` | `#3A3A3A` |
| medium | `--bkper-color-grey-medium` | `#ccc` | `#6d6d6d` |
| high | `--bkper-color-grey-high` | `#3A3A3A` | `#bfb8b8` |
**Blue — Assets**
| Level | Token | Light | Dark |
| :--- | :--- | :--- | :--- |
| low | `--bkper-color-blue-low` | `#dfedf6` | `#1d4268` |
| medium | `--bkper-color-blue-medium` | `#afd4e9` | `#3478bc` |
| high | `--bkper-color-blue-high` | `#3478bc` | `#50a4d9` |
**Yellow — Liabilities**
| Level | Token | Light | Dark |
| :--- | :--- | :--- | :--- |
| low | `--bkper-color-yellow-low` | `#fef3d8` | `#664900` |
| medium | `--bkper-color-yellow-medium` | `#fce39c` | `#cc9200` |
| high | `--bkper-color-yellow-high` | `#cc9200` | `#e3bb56` |
**Green — Incoming**
| Level | Token | Light | Dark |
| :--- | :--- | :--- | :--- |
| low | `--bkper-color-green-low` | `#e2f3e7` | `#0d3514` |
| medium | `--bkper-color-green-medium` | `#b8e0c3` | `#228c33` |
| high | `--bkper-color-green-high` | `#228c33` | `#36cf64` |
**Red — Outgoing**
| Level | Token | Light | Dark |
| :--- | :--- | :--- | :--- |
| low | `--bkper-color-red-low` | `#f6deda` | `#631b13` |
| medium | `--bkper-color-red-medium` | `#eebbb4` | `#bf4436` |
| high | `--bkper-color-red-high` | `#bf4436` | `#eb7763` |
### Deprecated Tokens
These aliases are kept for backward compatibility. Use the replacement token instead.
| Deprecated Token | Replacement |
| :--- | :--- |
| `--bkper-font-color-default` | `--bkper-color-text` |
| `--bkper-border-color` | `--bkper-color-border` |
| `--bkper-background-color` | `--bkper-color-background` |
| `--bkper-link-color` | `--bkper-color-link` |
---
source: /docs/build.md
# Build
Bkper is designed to be extended. Whether you're piping CLI commands in a shell script or building a full platform app with a UI, events, and managed hosting — the same APIs and tools power everything.
## The building spectrum
**Scripts & CLI** — Pipe data through the CLI, write Node.js scripts, or call the REST API directly. No infrastructure needed.
**Google Workspace** — Build automations with Apps Script, extend Google Sheets with custom functions and triggers.
**Platform Apps** — Full applications with managed hosting, authentication, event handling, and deployment on the [Bkper Platform](https://bkper.com/docs/build/apps/overview.md).
## Where to start
- [Development Setup](https://bkper.com/docs/build/getting-started/setup.md): Install the CLI, authenticate, and verify your environment.
- [Quick Wins](https://bkper.com/docs/build/getting-started/quick-wins.md): The fastest ways to create value with Bkper programmatically.
- [Your First App](https://bkper.com/docs/build/getting-started/first-app.md): Build and deploy a platform app in minutes.
- [The Agent Model](https://bkper.com/docs/build/concepts/agent-model.md): How apps, bots, and integrations are identified in Bkper.
## Build by section
- [Scripts & Integrations](https://bkper.com/docs/build/scripts/cli-pipelines.md): CLI piping, Node.js scripts, and direct API usage.
- [Apps](https://bkper.com/docs/build/apps/overview.md): The Bkper Platform — managed hosting, auth, events, and deployment.
- [Google Workspace](https://bkper.com/docs/build/google-workspace/apps-script.md): Apps Script development and Sheets integrations.
- [Tools](https://bkper.com/docs/build/tools/cli.md): CLI and libraries for building on Bkper.
- [Examples & Patterns](https://bkper.com/docs/build/examples.md): Real-world open source projects to learn from.
---
source: /docs/build/apps/app-listing.md
# App Listing
All Bkper apps are listed on the Automations Portal at *[app.bkper.com](https://app.bkper.com/) > Automations > Apps*. Each app has its own page with logo, description, and details:

App listings are populated from the fields you declare in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md). App metadata is synced to Bkper via `bkper app sync` or `bkper app deploy`.
## Listing fields
Make sure your `bkper.yaml` has the following fields populated for a complete listing:
```yaml
id: your-app-id
name: Your App Name
description: A clear description of what your app does
logoUrl: https://your-app.bkper.app/images/logo.svg
logoUrlDark: https://your-app.bkper.app/images/logo-dark.svg
ownerName: Your Name or Organization
ownerWebsite: https://yourwebsite.com
website: https://your-app.bkper.app
```
See [App Configuration](https://bkper.com/docs/build/apps/configuration.md) for the full `bkper.yaml` reference.
## Default visibility
When you deploy an app, it's visible only to the accounts you've declared in `bkper.yaml`:
```yaml
# Specific users
users: alice@example.com bob@example.com
# Your entire domain
users: *@yourcompany.com
```
Your team can install and use the app, but it doesn't appear in the public Bkper app directory for other users.
## Publishing to all users
To make your app available to all Bkper users, contact us at [support@bkper.com](mailto:support@bkper.com?subject=Publish+Bkper+App). We'll review your app and, once approved, publish it.
### What the review involves
- **Functionality check** — The app works correctly and handles errors gracefully
- **Security review** — Event handlers are idempotent and include loop prevention
- **Listing quality** — The app has a clear name, description, and logo
### Where published apps appear
Once published, your app appears in:
- **[bkper.com/apps](https://bkper.com/apps)** — The public app directory
- **Automations Portal** — Inside every Bkper book, users can find and install your app
---
source: /docs/build/apps/architecture.md
# App Architecture
Bkper platform apps follow a three-package monorepo pattern. Each package handles a distinct concern, all deployed to the same `{appId}.bkper.app` domain.
## Structure
```
packages/
├── shared/ — Shared types and utilities
├── web/
│ ├── client/ — Frontend UI (Vite + Lit)
│ └── server/ — Backend API (Hono)
└── events/ — Event handler (webhooks)
```
The packages are connected via [Bun workspaces](https://bun.sh/docs/install/workspaces). Import shared code from `@my-app/shared` in any package.
## Web client
The client package builds a browser UI with [Lit](https://lit.dev/) and [@bkper/web-design](https://www.npmjs.com/package/@bkper/web-design) for consistent Bkper styling. Authentication uses [@bkper/web-auth](https://www.npmjs.com/package/@bkper/web-auth).
- Built with [Vite](https://vitejs.dev/) — configured in the project's `vite.config.ts` for fast builds and HMR during development
- Static assets served by the web server handler
- Communicates with Bkper via `bkper-js` (authenticated with the web-auth SDK)
This is where your app's UI lives — book pickers, account lists, reports, forms.
## Web server
The server package runs on [Cloudflare Workers](https://developers.cloudflare.com/workers/) using [Hono](https://hono.dev/) as the web framework. It handles:
- Serving the client's static assets
- Custom API routes for your app's backend logic
- Type-safe access to platform services (KV, secrets) via `c.env`
```ts
import { Hono } from 'hono';
import type { Env } from '../../../../env.js';
const app = new Hono<{ Bindings: Env }>();
app.get('/api/data', async (c) => {
const cached = await c.env.KV.get('my-key');
return c.json({ data: cached });
});
export default app;
```
## Events handler
The events package receives webhook calls from Bkper when subscribed [events](https://bkper.com/docs/build/concepts/events.md) occur. It's a separate Hono app that processes events and returns responses.
```ts
import { Hono } from 'hono';
import type { Env } from '../../../env.js';
const app = new Hono<{ Bindings: Env }>().basePath('/events');
app.post('/', async (c) => {
const event: bkper.Event = await c.req.json();
switch (event.type) {
case 'TRANSACTION_CHECKED':
return c.json(await handleTransactionChecked(book, event));
default:
return c.json({ result: false });
}
});
export default app;
```
Event handlers run at `https://{appId}.bkper.app/events` in production. During development, a Cloudflare tunnel routes events to your local machine.
See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) for patterns and details.
## Shared package
Common types, utilities, and constants used across packages:
```ts
// packages/shared/src/types.ts
export interface EventResult {
result?: string | string[] | boolean;
error?: string;
warning?: string;
}
// packages/shared/src/constants.ts
export const APP_NAME = 'my-app';
```
Import in any package:
```ts
import type { EventResult } from '@my-app/shared';
```
> **Note:** The `Env` type (KV bindings, secrets) lives in the root `env.d.ts` file, auto-generated from `bkper.yaml`. Import it as `import type { Env } from '../../../env.js'` — it is not part of the shared package.
## When you don't need all three
Not every app needs a UI, API, and event handler:
- **Event-only app** — Just the `events` package. Automates reactions to book events without a user interface. Remove the `web` section from `bkper.yaml`.
- **UI-only app** — Just the `web` packages. Opens via a [context menu](https://bkper.com/docs/build/apps/context-menu.md) to display data or collect input. Remove the `events` section from `bkper.yaml`.
- **Full app** — All three packages. Interactive UI with backend logic and event-driven automation.
The template includes all three by default. Remove what you don't need.
---
source: /docs/build/apps/configuration.md
# App Configuration
The `bkper.yaml` file is the single configuration file for your Bkper app. It defines the app's identity, access control, menu integration, event handling, and deployment settings.
It lives in the root of your project and is synced to Bkper via `bkper app sync` or `bkper app deploy`.
## Minimal example
```yaml
id: my-app
name: My App
description: A Bkper app that does something useful
developers: myuser
```
## Full example
From the [app template](https://github.com/bkper/bkper-app-template):
```yaml
id: my-app
name: My App
description: A Bkper app that does something useful
logoUrl: https://my-app.bkper.app/images/logo-light.svg
logoUrlDark: https://my-app.bkper.app/images/logo-dark.svg
website: https://bkper.com/apps/bkper-cli
ownerName: Bkper
ownerLogoUrl: https://avatars.githubusercontent.com/u/11943086?v=4
ownerWebsite: https://bkper.com
repoUrl: https://github.com/bkper/bkper-app-template
repoPrivate: true
developers: someuser *@yoursite.com
users: someuser *@yoursite.com
menuUrl: https://my-app.bkper.app?bookId=${book.id}
menuUrlDev: http://localhost:8787?bookId=${book.id}
menuPopupWidth: 500
menuPopupHeight: 300
webhookUrl: https://my-app.bkper.app/events
apiVersion: v5
events:
- TRANSACTION_CHECKED
deployment:
web:
main: packages/web/server/src/index.ts
client: packages/web/client
events:
main: packages/events/src/index.ts
services:
- KV
secrets:
- BKPER_API_KEY
compatibility_date: '2026-01-28'
```
### App identity
| Field | Description |
| --- | --- |
| `id` | Permanent app identifier. Lowercase letters, numbers, and hyphens only. Cannot be changed after creation. |
| `name` | Display name shown in the Bkper UI. |
| `description` | Brief description of what the app does. |
### Branding
| Field | Description |
| --- | --- |
| `logoUrl` | App logo for light mode (SVG recommended). |
| `logoUrlDark` | App logo for dark mode. |
| `website` | App website or documentation URL. |
### Ownership
| Field | Description |
| --- | --- |
| `ownerName` | Developer or company name. |
| `ownerLogoUrl` | Owner's logo/avatar URL. |
| `ownerWebsite` | Owner's website. |
| `repoUrl` | Source code repository URL. |
| `repoPrivate` | Whether the repository is private. |
| `deprecated` | Hides from app listings; existing installs continue working. |
### Access control
| Field | Description |
| --- | --- |
| `developers` | Who can update the app and deploy new versions. Comma-separated Bkper usernames. Supports domain wildcards: `*@yoursite.com`. |
| `users` | Who can install and use the app. Same format as developers. Leave empty for public apps. |
### Menu integration
| Field | Description |
| --- | --- |
| `menuUrl` | Production menu URL. Supports [variable substitution](#menu-url-variables). |
| `menuUrlDev` | Development menu URL (used when the developer clicks the menu). |
| `menuText` | Custom menu text (defaults to app name). |
| `menuPopupWidth` | Popup width in pixels. |
| `menuPopupHeight` | Popup height in pixels. |
See [Context Menu](https://bkper.com/docs/build/apps/context-menu.md) for details on building menu integrations.
### Menu URL variables
The following variables can be used in `menuUrl` and `menuUrlDev`:
| Variable | Description |
| --- | --- |
| `${book.id}` | Current book ID |
| `${book.properties.xxx}` | Book property value |
| `${account.id}` | Selected account ID |
| `${account.name}` | Selected account name |
| `${account.properties.xxx}` | Account property value |
| `${group.id}` | Selected group ID |
| `${group.name}` | Selected group name |
| `${group.properties.xxx}` | Group property value |
| `${transactions.ids}` | Comma-separated selected transaction IDs |
| `${transactions.query}` | Current search query |
### Event handling
| Field | Description |
| --- | --- |
| `webhookUrl` | Production webhook URL for receiving events. |
| `webhookUrlDev` | Development webhook URL (auto-updated by `bkper app dev`). |
| `apiVersion` | API version for event payloads (currently `v5`). |
| `events` | List of [event types](https://bkper.com/docs/build/concepts/events.md#event-types) to subscribe to. |
See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) for details on handling events.
### File patterns
| Field | Description |
| --- | --- |
| `filePatterns` | List of glob patterns (e.g., `*.ofx`, `*.csv`). When a matching file is uploaded, a `FILE_CREATED` event is triggered. |
### Properties schema
The `propertiesSchema` field defines autocomplete suggestions for custom properties in the Bkper UI, helping users discover the correct property keys and values for your app:
```yaml
propertiesSchema:
book:
keys:
- my_app_enabled
values:
- 'true'
- 'false'
group:
keys:
- my_app_category
account:
keys:
- my_app_sync_id
transaction:
keys:
- my_app_reference
```
### Deployment
For apps deployed to the [Bkper Platform](https://bkper.com/docs/build/apps/overview.md):
| Field | Description |
| --- | --- |
| `deployment.web.main` | Entry point for the web handler (serves UI and API). |
| `deployment.web.client` | Directory for static client assets. |
| `deployment.events.main` | Entry point for the events handler (processes webhooks). |
| `deployment.services` | Platform services to provision. Currently: `KV` (key-value storage). |
| `deployment.secrets` | Secret names used by the app. Managed via `bkper app secrets`. |
| `deployment.compatibility_date` | [Cloudflare Workers compatibility date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/). |
See [Building & Deploying](https://bkper.com/docs/build/apps/deploying.md) for the full deployment workflow.
---
source: /docs/build/apps/context-menu.md
# Context Menu
Apps can add context menu items on the Transactions page **More** menu in your Books. This lets you open dynamically built URLs with reference to the current Book's context — the active query, selected account, date range, and more.
## How it works
Once you install an App with a menu configuration, a new menu item appears in your Book:

When clicked, a popup opens carrying the particular context of that book at that moment:

## Configuration
Configure the menu URL in your [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md):
```yaml
menuUrl: https://my-app.bkper.app?bookId=${book.id}&query=${transactions.query}
```
When the user clicks the menu item, the URL expressions `${xxxx}` are replaced with contextual information from the Book:
```
https://my-app.bkper.app?bookId=abc123&query=account:Sales
```
Where `abc123` is the current Book id and `account:Sales` is the current query being executed.
### Development URL
Use `menuUrlDev` for a separate URL during development:
```yaml
menuUrl: https://my-app.bkper.app?bookId=${book.id}&query=${transactions.query}
menuUrlDev: http://localhost:8787?bookId=${book.id}&query=${transactions.query}
```
The development URL is used when the app developer is the one clicking the menu item.
### Popup dimensions
Control the popup size with:
```yaml
menuPopupWidth: 800
menuPopupHeight: 600
```
### Available expressions
The menu URL supports these dynamic expressions:
| Expression | Description |
| --- | --- |
| `${book.id}` | The current Book ID |
| `${transactions.query}` | The current query string |
| `${account.id}` | The selected account ID |
| `${account.name}` | The selected account name |
| `${group.id}` | The selected group ID |
| `${group.name}` | The selected group name |
For the full list of accepted expressions, see the [Menu URL variables](https://bkper.com/docs/build/apps/configuration.md#menu-url-variables) reference.
---
source: /docs/build/apps/deploying.md
# Building & Deploying
## The deployment workflow
1. **Build** — Compile your code
```bash
npm run build
```
This runs two build steps:
- Client (Vite) to static assets in `dist/web/client/`
- Worker bundles (esbuild) — web server to `dist/web/server/`, events handler to `dist/events/`
Build output includes size reporting so you can monitor bundle sizes.
2. **Sync** — Update app metadata
```bash
bkper app sync
```
Syncs your `bkper.yaml` configuration to Bkper — name, description, menu URLs, webhook URLs, access control, and branding. Run this whenever you change app settings.
3. **Deploy** — Upload code to the platform
```bash
bkper app deploy
```
Deploys your pre-built code from `dist/` to the Bkper Platform. Your app is live at `https://{appId}.bkper.app`.
The typical workflow combines all three:
```bash
npm run build && bkper app sync && bkper app deploy
```
### Production
The default deployment target. Your app runs at `https://{appId}.bkper.app`.
```bash
bkper app deploy
```
### Preview
Deploy to a separate preview environment for testing before production:
```bash
bkper app deploy --preview
```
Preview has independent secrets and KV storage from production.
### Independent handler deployment
Deploy only the events handler:
```bash
bkper app deploy --events
```
Useful when you've only changed the events handler and want a faster deployment. Web is deployed by default.
## Secrets management
Secrets are environment variables stored securely on the platform. Declare them in `bkper.yaml`:
```yaml
deployment:
secrets:
- BKPER_API_KEY
- EXTERNAL_SERVICE_TOKEN
```
### Setting secrets
```bash
# Set for production
bkper app secrets put BKPER_API_KEY
# Set for preview
bkper app secrets put BKPER_API_KEY --preview
```
You'll be prompted to enter the value.
### Listing and deleting
```bash
# List all secrets
bkper app secrets list
# Delete a secret
bkper app secrets delete BKPER_API_KEY
```
### Accessing in code
Secrets are available as `c.env.SECRET_NAME` in your Hono handlers:
```ts
app.get('/api/data', async (c) => {
const apiKey = c.env.BKPER_API_KEY;
// use apiKey
});
```
During local development, use the `.dev.vars` file instead. See [Development Experience](https://bkper.com/docs/build/apps/development.md#local-secrets).
### KV storage
Declare KV in `bkper.yaml`:
```yaml
deployment:
services:
- KV
```
The platform provisions a KV namespace for your app. Access it via `c.env.KV`:
```ts
await c.env.KV.put('key', 'value', { expirationTtl: 3600 });
const value = await c.env.KV.get('key');
```
KV storage is separate between production and preview environments.
## Deployment status
Check the current state of your deployment:
```bash
bkper app status
```
## Installing on books
After deploying, install the app on specific books to activate it:
```bash
# Install on a book
bkper app install -b
# Uninstall from a book
bkper app uninstall -b
```
Once installed, the app's [event handlers](https://bkper.com/docs/build/apps/event-handlers.md) receive events from that book, and the app's [context menu](https://bkper.com/docs/build/apps/context-menu.md) appears in the book's UI.
---
source: /docs/build/apps/development.md
# Development Experience
Local development uses two composable processes — the worker runtime and the client dev server — that run concurrently.
## What runs
```bash
npm run dev
```
The project template runs both processes via `concurrently`:
1. **`vite dev`** — Client dev server with HMR. Changes to Lit components reflect instantly in the browser. Configured in `vite.config.ts`.
2. **`bkper app dev`** — The worker runtime:
- **Miniflare** — Simulates the Cloudflare Workers runtime locally for the web server and events handler.
- **Cloudflare tunnel** — Exposes the events handler via a public URL so Bkper can route webhook events to your machine.
- **File watching** — Server and shared package changes trigger automatic rebuilds via esbuild.
You can also run them independently: `npm run dev:client` for just the UI, or `npm run dev:server` / `npm run dev:events` for specific workers.
## URLs
| Handler | URL |
| --- | --- |
| Client (Vite dev server) | `http://localhost:5173` |
| Web server (Miniflare) | `http://localhost:8787` |
| Events (via tunnel) | `https://.trycloudflare.com/events` |
The Vite dev server proxies `/api` requests to `http://localhost:8787` (configured in `vite.config.ts`). The tunnel URL is automatically registered as the `webhookUrlDev` in Bkper, so events from books where you're the developer are routed to your local machine.
## Configuration flags
You can run specific handlers independently:
```bash
# Start only the web worker
bkper app dev --web
# Start only the events worker
bkper app dev --events
# Override default ports
bkper app dev --sp 8787 --ep 8791
```
## Client configuration
The client dev server is configured in `vite.config.ts` at the project root. This is a standard Vite config — add plugins, adjust settings, or customize the dev server as needed.
The template includes a Bkper auth middleware plugin that handles OAuth token refresh during local development, and an `/api` proxy to the Miniflare worker.
## Local secrets
Environment variables for local development live in a `.dev.vars` file at the project root:
```bash
# .dev.vars (gitignored)
BKPER_API_KEY=your-api-key-here
```
Copy from the provided template:
```bash
cp .dev.vars.example .dev.vars
```
These variables are available as `c.env.SECRET_NAME` in your Hono handlers during development.
## KV storage
KV data persists locally in the `.mf/kv/` directory during development. This means your data survives restarts — useful for testing caching and state patterns.
```ts
// Read
const value = await c.env.KV.get('my-key');
// Write with TTL
await c.env.KV.put('my-key', 'value', { expirationTtl: 3600 });
```
See the [Cloudflare KV documentation](https://developers.cloudflare.com/kv/) for more usage patterns.
## Type generation
The `env.d.ts` file provides TypeScript types for the Worker environment — KV bindings, secrets, and other platform services. It's auto-generated based on your `bkper.yaml` configuration and checked into version control.
Rebuild it after changing services or secrets in `bkper.yaml`:
```bash
bkper app build
```
## The development loop
1. Run `npm run dev`
2. Edit client code — see changes instantly via Vite HMR
3. Edit server code — auto-rebuilds and reloads via esbuild watch
4. Trigger events in Bkper — your local handler receives them via the tunnel
5. Check the activity stream in Bkper to see handler responses
6. Iterate
## Debugging
- **Server errors** — Check the terminal output from `bkper app dev`. Worker runtime errors appear here.
- **Event handler errors** — Check the Bkper activity stream. Click on an event handler response to see the result or error, and replay failed events.
- **Client errors** — Use browser DevTools. The Vite dev server provides source maps.
---
source: /docs/build/apps/event-handlers.md
# Event Handlers
Event handlers are the code that reacts to [events](https://bkper.com/docs/build/concepts/events.md) in your Bkper Books. When a transaction is checked, an account is created, or any other event occurs, your handler receives it and can take action — calculate taxes, sync data between books, post to external services, and more.

## How it works
1. You declare which events your app handles in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md)
2. Bkper sends an HTTP POST to your webhook URL when those events fire
3. Your handler processes the event and returns a response
On the [Bkper Platform](https://bkper.com/docs/build/apps/overview.md), events are routed to your `events` package automatically — including local development via tunnels. For [self-hosted](https://bkper.com/docs/build/apps/self-hosted.md) setups, you configure the webhook URL directly.
## Agent identity
Event handlers **run on behalf of the user who installed the app**. Their transactions and activities are identified in the UI by the app's logo and name:

## Responses
Handler responses are recorded in the activity that triggered the event. You can view and replay them by clicking the response at the bottom of the activity:

### Response format
Your handler must return a response in this format:
```ts
{ result?: string | string[] | boolean; error?: string; warning?: string }
```
- The `result` is recorded as the handler response in the book activity
- If you return `{ result: false }`, the response is suppressed and not recorded
- Errors like `{ error: "This is an error" }` show up as error responses
To show the full error stack trace for debugging:
```ts
try {
// handler logic
} catch (err) {
return { error: err instanceof Error ? err.message : String(err) }
}
```
### HTML in responses
If you return an **HTML snippet** (e.g., a link) in the result, it will be rendered in the response popup.
## Development mode
Event handlers run in *Development Mode* when executed by the **developer or owner** of the App.
In development mode, both successful results and errors are shown as responses:

You can click a response to **replay** failed executions — useful for debugging without recreating the triggering event.
To find transactions with bot errors in a book, run the query:
```
error:true
```
## Preventing loops
When your event handler creates or modifies transactions, those changes fire new events. To prevent infinite loops, check the `event.agent.id` field:
```ts
function handleEvent(event: bkper.Event) {
// Skip events triggered by this app
if (event.agent?.id === 'your-app-id') {
return { result: false }
}
// Process the event
// ...
}
```
This pattern is essential for any handler that writes back to the same book.
## Event routing pattern
On the Bkper Platform, the `events` package uses [Hono](https://hono.dev) to receive webhook calls. A typical pattern routes events by type:
```ts
app.post('/', async (c) => {
const event: bkper.Event = await c.req.json()
switch (event.type) {
case 'TRANSACTION_CHECKED':
return c.json(await handleTransactionChecked(book, event))
case 'ACCOUNT_CREATED':
return c.json(await handleAccountCreated(book, event))
default:
return c.json({ result: false })
}
})
```
For the full event type reference, see [Events](https://bkper.com/docs/build/concepts/events.md).
---
source: /docs/build/apps/overview.md
# The Bkper Platform
The Bkper Platform is a complete managed environment for building, deploying, and hosting apps on Bkper. It removes infrastructure complexity so you can focus on business logic.
### Hosting
Apps are deployed to `{appId}.bkper.app` on a global edge network powered by [Cloudflare Workers for Platforms](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/). Your app runs close to your users, with zero infrastructure to manage.
Preview environments are built in — deploy to a preview URL to test before going to production.
### Authentication
OAuth is pre-configured. No client IDs, no redirect URIs, no consent screens to build. In your client code, call `auth.getAccessToken()` and the platform handles the rest. In your event handlers, the user's OAuth token arrives automatically in the request headers.
### Services
Declare the services you need in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md) and the platform provisions them:
- **KV storage** — Key-value storage for caching and state. Access via `c.env.KV` in your handlers.
- **Secrets** — Securely stored environment variables. Set via `bkper app secrets put`, access via `c.env.SECRET_NAME`.
### Developer experience
The project template composes the full development environment:
```bash
npm run dev
```
This runs two processes concurrently: `vite dev` for the client UI (HMR), and `bkper app dev` for the worker runtime (Miniflare for your server and event handlers, plus a Cloudflare tunnel so Bkper can route webhook events to your laptop). Your entire development environment, running locally.
### Deployment
Build and deploy your app:
```bash
npm run build && bkper app sync && bkper app deploy
```
Your app is live at `{appId}.bkper.app`. The platform handles routing, SSL, and edge distribution.
## What you'd build yourself without it
Without the platform, creating a Bkper app with a UI, event handling, and authentication requires:
| Concern | Without the platform | With the platform |
| --- | --- | --- |
| **Hosting** | Provision servers, configure domains, SSL, CDN | `bkper app deploy` |
| **Authentication** | Register OAuth client, build consent screen, handle token refresh, manage redirect URIs | `auth.getAccessToken()` |
| **Event webhooks** | Set up a public endpoint, configure DNS, handle JWT verification | Declare in `bkper.yaml`, platform routes events |
| **Local dev webhooks** | Install ngrok or similar, manually configure tunnel URL | `bkper app dev` starts tunnel automatically |
| **Secrets** | Set up a secrets manager, configure access | `bkper app secrets put` |
| **KV storage** | Deploy Redis/Memcached, manage connections | Declare `KV` in `bkper.yaml` |
| **Preview environments** | Build a staging pipeline | `bkper app deploy --preview` |
| **Type safety** | Manually create type definitions | `env.d.ts` auto-generated |
The platform eliminates all of this. You write business logic, the platform handles infrastructure.
## Getting started
```bash
# Create a new app from the template
bkper app init my-app
# Start developing
npm run dev
```
This gives you a working app with a client UI, server API, and event handler — all running locally with full HMR and webhook tunneling.
See [Your First App](https://bkper.com/docs/build/getting-started/first-app.md) for a complete walkthrough, or continue to [App Architecture](https://bkper.com/docs/build/apps/architecture.md) to understand how platform apps are structured.
---
source: /docs/build/apps/self-hosted.md
# Self-Hosted Alternative
The [Bkper Platform](https://bkper.com/docs/build/apps/overview.md) handles hosting, authentication, and deployment for you. However, you can host event handlers on your own infrastructure if you have specific requirements — existing cloud setup, compliance constraints, or legacy apps.
> **Tip**
> Use the Bkper Platform unless you have a specific reason to self-host. It eliminates the need to manage authentication, secrets, hosting, and deployment yourself.
## Cloud Functions
A Bkper event handler running on [Google Cloud Functions](https://cloud.google.com/functions/) receives authenticated calls from the `bkper-hrd@appspot.gserviceaccount.com` service account. You need to grant this service account the [Cloud Functions Invoker IAM role](https://cloud.google.com/functions/docs/securing/managing-access-iam) (`roles/cloudfunctions.invoker`).
Set the production endpoint in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md):
```yaml
webhookUrl: https://us-central1-my-project.cloudfunctions.net/events
```
### Authentication
An OAuth Access Token **of the user who installed the app** is sent to the production `webhookUrl` endpoint in the `bkper-oauth-token` HTTP header, along with the agent identifier in `bkper-agent-id`, on each event. Your handler uses this token to call the API back on behalf of the user.
The development endpoint (`webhookUrlDev`) does **not** receive these tokens. During development, you need to authenticate locally — this can be simplified using the [CLI](https://bkper.com/docs/build/tools/cli.md).
### Throughput and scaling
Event throughput can be high, especially when processing large batches. Set the [max instance limit](https://cloud.google.com/functions/docs/max-instances#setting_max_instances_limits) — usually **1-2 is enough**. When the function returns `429 Too Many Requests`, the event is automatically retried with incremental backoff until it receives an HTTP `200`.
### Response format
The function response must follow the standard format:
```ts
{ result?: any, error?: any }
```
See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md#response-format) for details on response handling.
### Considerations
- Execution environment is subject to [Cloud Function Quotas](https://cloud.google.com/functions/quotas) — quota counts against the developer account, not the end user
- Recommended for scenarios where event throughput exceeds **1 event/second/user** and processing can be handled asynchronously
- Can be combined with context menus built with [Apps Script HTML Service](https://developers.google.com/apps-script/guides/html) or any other UI infrastructure
---
## Generic Webhooks
You can host event handlers on any infrastructure — other cloud providers, containers, on-premise servers.
Configure the same `webhookUrl` property in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md):
```yaml
webhookUrl: https://my-server.example.com/bkper/events
```
### Authentication
Calls to the production webhook URL are signed with a JWT token using the [Service to Function](https://cloud.google.com/functions/docs/securing/authenticating#service-to-function) method. You can verify this token to assert the identity of the Bkper service.
> **Note**
> Cloud Functions handles JWT verification automatically. For other infrastructure, you need to implement verification yourself. We strongly recommend Cloud Functions for this reason.
### Retry behavior
If your infrastructure returns an HTTP `429` status, the event is automatically retried with incremental backoff until it receives an HTTP `200`. Use this to handle temporary overload gracefully.
---
source: /docs/build/concepts/agent-model.md
# The Agent Model
When you build something that interacts with Bkper — a script, an automation, a full platform app, or even a bank integration — Bkper treats it as an **agent**: any application that can perform actions on books **on behalf of a user**.
These agents can take various forms such as Apps, Bots, Assistants, or even Banks that interact with your books:
[Image: Bkper Agents Model]
## Permissions
Agents can only access books that have been explicitly shared with the user they're acting on behalf of. Your code never has elevated access — it operates within the same permission boundaries as the human user who authorized it.
## Identity
Every API request your app makes includes a `bkper-agent-id` header. This lets Bkper attribute actions to the correct agent, so activities and transactions appear with your app's logo and name throughout the Bkper interface — making it easy for book owners to see which entity performed specific actions:

## Bots vs AI Agents
The distinction between a "bot" and an "AI agent" is about capability, not a different type of Bkper primitive. Both are just apps:
| | **Bot** | **AI Agent** |
| --- | --- | --- |
| **Purpose** | Automating predefined tasks | Autonomously perform tasks |
| **Capabilities** | Follows rules; limited learning; basic interactions | Complex, multi-step actions; learns and adapts; makes decisions independently |
| **Interaction** | Reactive; responds to triggers or commands | Proactive; goal-oriented |
In Bkper, what people call "bots" are typically apps whose primary capability is [event handling](https://bkper.com/docs/build/apps/event-handlers.md) — reacting to things that happen in a book. AI agents go further, combining event handling with LLM reasoning to make decisions.
---
source: /docs/build/concepts/authentication.md
# Authentication
All Bkper API access uses [OAuth 2.0](https://developers.google.com/identity/protocols/oauth2) with the `email` scope. The approach depends on your environment.
## CLI and Node.js scripts
The simplest path. The CLI handles the OAuth flow and stores credentials locally.
```bash
bkper auth login
```
Then use `getOAuthToken()` as the auth provider for `bkper-js`:
```ts
import { Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
```
This works for CLI scripts, Node.js automations, and local development of platform apps.
## Browser with an access token
For any browser environment, use `bkper-js` directly with a valid access token via CDN — no build tools required, works on **any domain**:
```html
```
Get an access token via the [Bkper CLI](https://bkper.com/docs/build/tools/cli.md):
```bash
bkper auth login # one-time setup
bkper auth token # prints a token (valid for 1 hour)
```
Access tokens are automatically refreshed by the CLI and SDKs. When using a token directly (e.g. in a `
```
Get an access token with the [Bkper CLI](https://www.npmjs.com/package/bkper):
```bash
bkper auth login # one-time setup
bkper auth token # prints a token (valid for 1 hour)
```
Pin to a specific version by replacing `@2` with e.g. `@2.31.0`.
### Node.js / CLI Scripts
For local scripts and CLI tools, use the [bkper](https://www.npmjs.com/package/bkper) CLI package for authentication:
```typescript
import { Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
// Configure with CLI authentication
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
// Create Bkper instance
const bkper = new Bkper();
// Get a book and work with it
const book = await bkper.getBook('your-book-id');
console.log(`Book: ${book.getName()}`);
// List all books
const books = await bkper.getBooks();
console.log(`You have ${books.length} books`);
```
First, login via CLI: `bkper auth login`
### npm + Bundler
If you are using a bundler (Vite, webpack, esbuild, etc.), install from npm and provide an access token the same way as the CDN example:
```typescript
import { Bkper } from 'bkper-js';
Bkper.setConfig({
oauthTokenProvider: async () => 'your-access-token',
});
const bkper = new Bkper();
const books = await bkper.getBooks();
```
### Web Applications on \*.bkper.app
> **Note:** `@bkper/web-auth` **only works on `*.bkper.app` subdomains**. Its session cookies are scoped to the `.bkper.app` domain and will not work on any other domain. For apps on other domains, use the [CDN / Browser](#cdn--browser) approach with an access token instead.
For apps hosted on `*.bkper.app` subdomains, use the [@bkper/web-auth](https://www.npmjs.com/package/@bkper/web-auth) SDK for built-in OAuth login flow:
```typescript
import { Bkper } from 'bkper-js';
import { BkperAuth } from '@bkper/web-auth';
// Initialize authentication
const auth = new BkperAuth({
onLoginSuccess: () => initializeApp(),
onLoginRequired: () => showLoginButton(),
});
// Restore session on app load
await auth.init();
// Configure Bkper with web auth
Bkper.setConfig({
oauthTokenProvider: async () => auth.getAccessToken(),
});
// Create Bkper instance and use it
const bkper = new Bkper();
const books = await bkper.getBooks();
```
See the [@bkper/web-auth documentation](https://bkper.com/docs/auth-sdk) for more details.
### API Key (Optional)
API keys are optional and only needed for dedicated quota limits. If not provided, requests use a shared managed quota via the Bkper API proxy.
```typescript
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
apiKeyProvider: async () => process.env.BKPER_API_KEY, // Optional - for dedicated quota
});
```
## Classes
### Account *(extends ResourceProperty)*
This class defines an [Account](https://en.wikipedia.org/wiki/Account_(bookkeeping)) of a `Book`.
It maintains a balance of all amount [credited and debited](http://en.wikipedia.org/wiki/Debits_and_credits) in it by `Transactions`.
An Account can be grouped by `Groups`.
`Account` has no `getBalance()` method. To retrieve account balances, use
`Book.getBalancesReport` and read the resulting `BalancesContainer`.
**Constructor:** `new Account(book: Book, payload?: bkper.Account)`
**Properties:**
- `payload`: `bkper.Account` — The underlying payload data for this resource
**Methods:**
- `addGroup(group: bkper.Group | Group)` → `Account` — Adds a group to the Account.
- `create()` → `Promise` — Performs create new Account.
- `deleteProperty(key: string)` → `this` — Deletes a custom property.
- `getGroups()` / `setGroups(groups: Group[] | bkper.Group[])` → `Promise (set: Group[] | bkper.Group[])` — Gets the `Groups` of this Account.
- `getId()` → `string | undefined` — Gets the Account internal id.
- `getName()` / `setName(name: string)` → `string | undefined (set: string)` — Gets the Account name.
- `getNormalizedName()` → `string` — Gets the normalized name of this Account without spaces or special characters.
- `getProperties()` / `setProperties(properties: { [key: string]: string })` → `{ [key: string]: string }` — Gets the custom properties stored in this resource.
- `getProperty(keys: string[])` / `setProperty(key: string, value: string | null | undefined)` → `string | undefined (set: string)` — Gets the property value for given keys. First property found will be retrieved.
- `getPropertyKeys()` → `string[]` — Gets the custom properties keys stored in this resource.
- `getType()` / `setType(type: AccountType)` → `AccountType` — Gets the type of this Account.
- `getVisibleProperties()` / `setVisibleProperties(properties: { [key: string]: string })` → `{ [key: string]: string }` — Gets the visible custom properties stored in this resource.
Hidden properties (those ending with "_") are excluded from the result.
- `hasTransactionPosted()` → `boolean | undefined` — Tells if the Account has any transaction already posted.
- `isArchived()` → `boolean | undefined` — Tells if this Account is archived.
- `isBalanceVerified()` → `boolean | undefined` — Tells if the balance of this Account has been verified/audited.
- `isCredit()` → `boolean | undefined` — Tells if the Account has a Credit nature or Debit otherwise.
- `isInGroup(group: string | Group)` → `Promise` — Tells if this Account is in the `Group`.
- `isPermanent()` → `boolean | undefined` — Tells if the Account is permanent.
- `json()` → `bkper.Account` — Gets an immutable copy of the JSON payload for this resource.
- `remove()` → `Promise` — Performs delete Account.
- `removeGroup(group: string | Group)` → `Promise` — Removes a group from the Account.
- `setArchived(archived: boolean)` → `Account` — Sets Account archived/unarchived.
- `setVisibleProperty(key: string, value: string | null | undefined)` → `this` — Sets a custom property in this resource, filtering out hidden properties.
Hidden properties are those whose keys end with an underscore "_".
- `update()` → `Promise` — Performs update Account, applying pending changes.
**groups**
When groups are already embedded in the account payload (e.g. from
`Bkper.getBook` with includeGroups), resolves them from the
book's cache instead of making API calls.
**hasTransactionPosted**
Accounts with transaction posted, even with zero balance, can only be archived.
**isCredit**
Credit Accounts are just for representation purposes. It increase or decrease the absolute balance. It doesn't affect the overall balance or the behavior of the system.
The absolute balance of credit Accounts increase when it participate as a credit/origin in a transaction. Its usually for Accounts that increase the balance of the assets, like revenue Accounts.
```
Crediting a credit
Thus ---------------------> Account increases its absolute balance
Debiting a debit
Debiting a credit
Thus ---------------------> Account decreases its absolute balance
Crediting a debit
```
As a rule of thumb, and for simple understanding, almost all Accounts are Debit nature (NOT credit), except the ones that "offers" amount for the books, like revenue Accounts.
**isPermanent**
Permanent Accounts are the ones which final balance is relevant and keep its balances over time.
They are also called [Real Accounts](http://en.wikipedia.org/wiki/Account_(Accountancy)#Based_on_periodicity_of_flow)
Usually represents assets or tangibles, capable of being perceived by the senses or the mind, like bank Accounts, money, debts and so on.
### AccountsDataTableBuilder
A AccountsDataTableBuilder is used to setup and build two-dimensional arrays containing accounts.
**Constructor:** `new AccountsDataTableBuilder(accounts: Account[])`
**Methods:**
- `archived(include: boolean)` → `AccountsDataTableBuilder` — Defines whether the archived accounts should be included.
- `build()` → `Promise` — Builds a two-dimensional array containing all accounts.
- `groups(include: boolean)` → `AccountsDataTableBuilder` — Defines whether include account groups.
- `hiddenProperties(include: boolean)` → `AccountsDataTableBuilder` — Defines whether to include hidden properties (keys ending with underscore "_").
- `ids(include: boolean)` → `AccountsDataTableBuilder` — Defines whether include account ids.
- `properties(include: boolean)` → `AccountsDataTableBuilder` — Defines whether include custom account properties.
### Agent
Defines an Agent on Bkper.
An Agent represents an entity (such as an App or Bot) that interacts with Bkper, executing actions on behalf of users.
**Constructor:** `new Agent(payload?: bkper.Agent)`
**Properties:**
- `payload`: `bkper.Agent`
**Methods:**
- `getId()` → `string | undefined` — Gets the Agent universal identifier.
- `getLogoUrl()` → `string | undefined` — Gets the Agent logo URL.
- `getLogoUrlDark()` → `string | undefined` — Gets the Agent logo URL in dark mode.
- `getName()` → `string | undefined` — Gets the Agent name.
- `json()` → `bkper.Agent` — Gets the wrapped plain JSON object.
### Amount
This class defines an Amount for arbitrary-precision decimal arithmetic.
It inherits methods from [big.js](http://mikemcl.github.io/big.js/) library
**Constructor:** `new Amount(n: string | number | Amount)`
The Amount constructor.
**Methods:**
- `abs()` → `Amount` — Returns an absolute Amount.
- `cmp(n: string | number | Amount)` → `-1 | 0 | 1` — Compares this Amount with another value.
- `div(n: string | number | Amount)` → `Amount` — Divides this Amount by another value.
- `eq(n: string | number | Amount)` → `boolean` — Checks if this Amount equals another value.
- `gt(n: string | number | Amount)` → `boolean` — Checks if this Amount is greater than another value.
- `gte(n: string | number | Amount)` → `boolean` — Checks if this Amount is greater than or equal to another value.
- `lt(n: string | number | Amount)` → `boolean` — Checks if this Amount is less than another value.
- `lte(n: string | number | Amount)` → `boolean` — Checks if this Amount is less than or equal to another value.
- `minus(n: string | number | Amount)` → `Amount` — Subtracts another value from this Amount.
- `mod(n: string | number | Amount)` → `Amount` — Calculates the modulo (remainder) of dividing this Amount by another value.
- `plus(n: string | number | Amount)` → `Amount` — Adds another value to this Amount.
- `round(dp?: number)` → `Amount` — Rounds this Amount to a maximum of dp decimal places.
- `times(n: string | number | Amount)` → `Amount` — Multiplies this Amount by another value.
- `toFixed(dp?: number)` → `string` — Returns a string representing the value of this Amount in normal notation to a fixed number of decimal places.
- `toNumber()` → `number` — Returns a primitive number representing the value of this Amount.
- `toString()` → `string` — Returns a string representing the value of this Amount.
**mod**
Similar to % operator
### App *(extends Resource)*
Defines an App on Bkper.
Apps can be installed on Books by users.
**Constructor:** `new App(payload?: bkper.App, config?: Config)`
**Properties:**
- `payload`: `bkper.App` — The underlying payload data for this resource
**Methods:**
- `create()` → `Promise` — Performs the app creation, applying pending changes.
- `getDescription()` → `string | undefined` — Gets the description of this App.
- `getDevelopers()` / `setDevelopers(developers?: string)` → `string | undefined (set: string)` — Gets the developers (usernames and domain patterns).
- `getEvents()` → `EventType[] | undefined` — Gets the events bound to this App.
- `getFilePatterns()` → `string[] | undefined` — Gets the file patterns the App handles.
- `getId()` → `string | undefined` — Gets the App universal identifier.
- `getLogoUrl()` → `string | undefined` — Gets the logo url of this App.
- `getLogoUrlDark()` → `string | undefined` — Gets the logo url of this App in dark mode.
- `getMenuPopupHeight()` → `string | undefined` — Gets the menu popup height of this App.
- `getMenuPopupWidth()` → `string | undefined` — Gets the menu popup width of this App.
- `getMenuText()` → `string | undefined` — Gets the menu text of this App.
- `getMenuUrl()` → `string | undefined` — Gets the menu url of this App.
- `getMenuUrlDev()` → `string | undefined` — Gets the menu development url of this App.
- `getName()` → `string | undefined` — Gets the name of this App.
- `getOwnerLogoUrl()` → `string | undefined` — Gets the logo url of the owner of this App.
- `getOwnerName()` → `string | undefined` — Gets the name of the owner of this App.
- `getOwnerWebsiteUrl()` → `string | undefined` — Gets the website url of the owner of this App.
- `getReadme()` / `setReadme(readme?: string)` → `string | undefined (set: string)` — Gets the readme.md file as text.
- `getRepositoryUrl()` → `string | undefined` — Gets the repository url of this App.
- `getUsers()` / `setUsers(users?: string)` → `string | undefined (set: string)` — Gets the whitelisted users (usernames and domain patterns).
- `getWebsiteUrl()` → `string | undefined` — Gets the website url of this App.
- `hasEvents()` → `boolean` — Checks if this App has events bound to it.
- `isInstallable()` → `boolean` — Tells if this App is installable.
- `isPublished()` → `boolean` — Checks if this App is published.
- `isRepositoryPrivate()` → `boolean | undefined` — Tells if the repository is private.
- `json()` → `bkper.App` — Gets an immutable copy of the JSON payload for this resource.
- `setClientSecret(clientSecret?: string)` → `App` — Sets the client secret.
- `setWebhookUrlDev(webhookUrlDev: string)` → `App` — Sets the webhook url for development.
- `update()` → `Promise` — Performs a full update of the App, applying pending changes.
**create**
The App id MUST be unique. If another app is already existing, an error will be thrown.
### Backlog *(extends Resource)*
This class defines the Backlog of a `Book`.
A Backlog is a list of pending tasks in a Book
**Constructor:** `new Backlog(payload?: bkper.Backlog, config?: Config)`
**Properties:**
- `payload`: `bkper.Backlog` — The underlying payload data for this resource
**Methods:**
- `getCount()` → `number | undefined` — Returns the number of pending tasks in this Backlog.
- `json()` → `bkper.Backlog` — Gets an immutable copy of the JSON payload for this resource.
### Balance
Class that represents an `Account` or `Group` balance on a window of time (Day / Month / Year).
**Constructor:** `new Balance(container: BalancesContainer, balancePlain: bkper.Balance)`
**Properties:**
- `payload`: `bkper.Balance`
**Methods:**
- `getCumulativeBalance()` → `Amount` — The cumulative balance to the date, based on the credit nature of the container
- `getCumulativeBalanceRaw()` → `Amount` — The raw cumulative balance to the date.
- `getCumulativeCredit()` → `Amount` — The cumulative credit to the date.
- `getCumulativeDebit()` → `Amount` — The cumulative debit to the date.
- `getDate()` → `Date` — Date object constructed based on `Book` time zone offset. Usefull for
- `getDay()` → `number` — The day of the balance. Days starts on 1 to 31.
- `getFuzzyDate()` → `number` — The Fuzzy Date of the balance, based on `Periodicity` of the `BalancesReport` query, composed by Year, Month and Day.
- `getMonth()` → `number` — The month of the balance. Months starts on 1 (January) to 12 (December)
- `getPeriodBalance()` → `Amount` — The balance on the date period, based on credit nature of the container.
- `getPeriodBalanceRaw()` → `Amount` — The raw balance on the date period.
- `getPeriodCredit()` → `Amount` — The credit on the date period.
- `getPeriodDebit()` → `Amount` — The debit on the date period.
- `getYear()` → `number` — The year of the balance
**getDate**
If Month or Day is zero, the date will be constructed with first Month (January) or Day (1) of the next period.
**getDay**
Day can be 0 (zero) in case of Monthly or Early `Periodicity` of the `BalancesReport`
**getFuzzyDate**
The format is **YYYYMMDD**. Very usefull for ordering and indexing
Month and Day can be 0 (zero), depending on the granularity of the `Periodicity`.
*Example:*
**20180125** - 25, January, 2018 - DAILY Periodicity
**20180100** - January, 2018 - MONTHLY Periodicity
**20180000** - 2018 - YEARLY Periodicity
**getMonth**
Month can be 0 (zero) in case of Early `Periodicity` of the `BalancesReport`
### BalancesDataTableBuilder *(implements BalancesDataTableBuilder)*
A BalancesDataTableBuilder is used to setup and build two-dimensional arrays containing balance information.
**Constructor:** `new BalancesDataTableBuilder(book: Book, balancesContainers: BalancesContainer[], periodicity: Periodicity)`
**Methods:**
- `build()` → `any[][]` — Builds an two-dimensional array with the balances.
- `expanded(expanded: number | boolean)` → `BalancesDataTableBuilder` — Defines whether Groups should expand its child accounts.
- `formatDates(format: boolean)` → `BalancesDataTableBuilder` — Defines whether the dates should be ISO formatted YYYY-MM-DD. E.g. 2025-01-01
- `formatValues(format: boolean)` → `BalancesDataTableBuilder` — Defines whether the value should be formatted based on decimal separator of the `Book`.
- `hiddenProperties(include: boolean)` → `BalancesDataTableBuilder` — Defines whether to include hidden properties (keys ending with underscore "_").
- `hideDates(hide: boolean)` → `BalancesDataTableBuilder` — Defines whether the dates should be hidden for **PERIOD** or **CUMULATIVE** `BalanceType`.
- `hideNames(hide: boolean)` → `BalancesDataTableBuilder` — Defines whether the `Accounts` and `Groups` names should be hidden.
- `period(period: boolean)` → `BalancesDataTableBuilder` — Defines whether should force use of period balances for **TOTAL** `BalanceType`.
- `properties(include: boolean)` → `BalancesDataTableBuilder` — Defines whether include custom `Accounts` and `Groups` properties.
- `raw(raw: boolean)` → `BalancesDataTableBuilder` — Defines whether should show raw balances, no matter the credit nature of the Account or Group.
- `transposed(transposed: boolean)` → `BalancesDataTableBuilder` — Defines whether should rows and columns should be transposed.
- `trial(trial: boolean)` → `BalancesDataTableBuilder` — Defines whether should split **TOTAL** `BalanceType` into debit and credit.
- `type(type: BalanceType)` → `BalancesDataTableBuilder` — Fluent method to set the `BalanceType` for the builder.
**expanded**
true to expand itself
-1 to expand all subgroups
-2 to expand all accounts
0 to expand nothing
1 to expand itself and its first level of children
2 to expand itself and its first two levels of children
etc.
**transposed**
For **TOTAL** `BalanceType`, the **transposed** table looks like:
```
_____________________________
| Expenses | Income | ... |
| -4568.23 | 5678.93 | ... |
|___________|_________|_______|
```
Two rows, and each `Account` or `Group` per column.
For **PERIOD** or **CUMULATIVE** `BalanceType`, the **transposed** table will be a time table, and the format looks like:
```
_______________________________________________________________
| | Expenses | Income | ... | ... |
| 15/01/2014 | -2345.23 | 3452.93 | ... | ... |
| 15/02/2014 | -2345.93 | 3456.46 | ... | ... |
| 15/03/2014 | -2456.45 | 3567.87 | ... | ... |
| ... | ... | ... | ... | ... |
|____________|____________|____________|____________|___________|
```
First column will be each Date, and one column for each `Account` or `Group`.
### BalancesReport
Class representing a Balance Report, generated when calling [Book.getBalanceReport](#book_getbalancesreport)
**Constructor:** `new BalancesReport(book: Book, payload: bkper.Balances)`
**Properties:**
- `payload`: `bkper.Balances`
**Methods:**
- `createDataTable()` → `BalancesDataTableBuilder` — Creates a BalancesDataTableBuilder to generate a two-dimensional array with all `BalancesContainers`.
- `getBalancesContainer(name: string)` → `BalancesContainer` — Gets a specific `BalancesContainer`.
- `getBalancesContainers()` → `BalancesContainer[]` — Gets all `BalancesContainers` of the report.
- `getBook()` → `Book` — Gets the `Book` that generated the report.
- `getPeriodicity()` → `Periodicity` — Gets the `Periodicity` of the query used to generate the report.
### Billing *(extends Resource)*
This class defines the Billing information for a `User`.
The Billing information includes the plan, the admin email, and the billing portal URL.
**Constructor:** `new Billing(json?: bkper.Billing, config?: Config)`
**Properties:**
- `payload`: `bkper.Billing` — The underlying payload data for this resource
**Methods:**
- `getAdminEmail()` → `string | undefined` — Gets the admin email for this User's billing account.
- `getCheckoutUrl(plan: string, successUrl?: string, cancelUrl?: string, cycle?: string)` → `Promise` — Gets the URL to redirect the User to the billing checkout.
- `getCounts()` → `Promise` — Gets the transaction counts associated to the User's billing account.
- `getDaysLeftInTrial()` → `number | undefined` — Gets the number of days left in User's trial period.
- `getEmail()` → `string | undefined` — Gets the email for the User.
- `getHostedDomain()` → `string | undefined` — Gets the hosted domain for the User.
- `getPlan()` → `string | undefined` — Gets the current plan of the User.
- `getPortalUrl(returnUrl: string)` → `Promise` — Gets the URL to redirect the User to the billing portal.
- `getTotalTransactionsThisMonth()` → `number | undefined` — Gets the number of total transactions this month for the User's billing account.
- `getTotalTransactionsThisYear()` → `number | undefined` — Gets the number of total transactions this year for the User's billing account.
- `hasStartedTrial()` → `boolean | undefined` — Tells if the User has started the trial period.
- `isEnabled()` → `boolean | undefined` — Tells if billing is enabled for the User.
- `isPlanOverdue()` → `boolean | undefined` — Tells if the User's current plan payment is overdue.
- `json()` → `bkper.Billing` — Gets an immutable copy of the JSON payload for this resource.
### Bkper
This is the main entry point of the [bkper-js](https://www.npmjs.com/package/bkper-js) library.
You can configure the library in two ways:
1. Using static configuration (traditional approach):
```typescript
Bkper.setConfig({
apiKeyProvider: () => process.env.BKPER_API_KEY,
oauthTokenProvider: () => process.env.BKPER_OAUTH_TOKEN
});
const bkper = new Bkper();
const book = await bkper.getBook('bookId');
```
2. Using per-instance configuration (recommended for Cloudflare Workers):
```typescript
const bkper = new Bkper({
apiKeyProvider: () => process.env.BKPER_API_KEY,
oauthTokenProvider: () => process.env.BKPER_OAUTH_TOKEN
});
const book = await bkper.getBook('bookId');
```
**Constructor:** `new Bkper(config?: Config)`
Creates a new Bkper instance with the provided configuration.
**Methods:**
- `getApp(id: string)` → `Promise` — Gets the `App` with the specified id.
- `getApps()` → `Promise` — Gets all `Apps` available for the user.
- `getBook(id: string, includeAccounts?: boolean, includeGroups?: boolean)` → `Promise` — Gets the `Book` with the specified bookId from url param.
- `getBooks(query?: string)` → `Promise` — Gets all `Books` the user has access to.
- `getCollections()` → `Promise` — Gets all `Collections` the user has access to.
- `getConfig()` → `Config` — Gets the current instance configuration.
- `getTemplates()` → `Promise` — Gets all `Templates` available for the user.
- `getUser()` → `Promise` — Gets the current logged `User`.
- `static setConfig(config: Config)` → `void` — Sets the global API configuration for all Bkper operations.
**setConfig**
WARNING: This configuration will be shared and should NOT be used on shared environments.
### BkperError *(extends Error)*
Standard error class for Bkper API errors.
Extends Error to enable instanceof checks and standard error handling.
**Constructor:** `new BkperError(code: number, message: string, reason?: string)`
**Properties:**
- `readonly code`: `number` — HTTP status code (e.g., 404, 400, 500)
- `message`: `string`
- `name`: `string`
- `readonly reason?`: `string` — Machine-readable reason (e.g., "notFound", "badRequest")
- `stack?`: `string`
- `static prepareStackTrace?`: `(err: Error, stackTraces: __global.NodeJS.CallSite[]) => any` — Optional override for formatting stack traces
- `static stackTraceLimit`: `number`
**Methods:**
- `static captureStackTrace(targetObject: object, constructorOpt?: Function)` → `void` — Create .stack property on a target object
### Book *(extends ResourceProperty)*
A Book represents a [General Ledger](https://en.wikipedia.org/wiki/General_ledger) for a company or business, but can also represent a [Ledger](https://en.wikipedia.org/wiki/Ledger) for a project or department
It contains all `Accounts` where `Transactions` are recorded/posted;
**Constructor:** `new Book(payload?: bkper.Book, config?: Config)`
**Properties:**
- `payload`: `bkper.Book` — The underlying payload data for this resource
**Methods:**
- `audit()` → `void` — Trigger [Balances Audit](https://help.bkper.com/en/articles/4412038-balances-audit) async process.
- `batchCheckTransactions(transactions: Transaction[])` → `Promise` — Batch check `Transactions` on the Book.
- `batchCreateAccounts(accounts: Account[])` → `Promise` — Create `Accounts` on the Book, in batch.
- `batchCreateGroups(groups: Group[])` → `Promise` — Create `Groups` on the Book, in batch.
- `batchCreateTransactions(transactions: Transaction[])` → `Promise` — Batch create `Transactions` on the Book.
- `batchPostTransactions(transactions: Transaction[])` → `Promise` — Batch post `Transactions` on the Book.
- `batchReplayEvents(events: Event[], errorOnly?: boolean)` → `Promise` — Replay `Events` on the Book, in batch.
- `batchTrashTransactions(transactions: Transaction[], trashChecked?: boolean)` → `Promise` — Batch trash `Transactions` on the Book.
- `batchUncheckTransactions(transactions: Transaction[])` → `Promise` — Batch uncheck `Transactions` on the Book.
- `batchUntrashTransactions(transactions: Transaction[])` → `Promise` — Batch untrash `Transactions` on the Book.
- `batchUpdateTransactions(transactions: Transaction[], updateChecked?: boolean)` → `Promise` — Batch update `Transactions` on the Book.
- `copy(name: string, copyTransactions?: boolean, fromDate?: number)` → `Promise` — Creates a copy of this Book
- `countTransactions(query?: string)` → `Promise` — Retrieve the number of transactions based on a query.
- `create()` → `Promise` — Performs create new Book.
- `createAccountsDataTable(accounts?: Account[])` → `Promise` — Create a `AccountsDataTableBuilder`, to build two dimensional Array representations of `Account` dataset.
- `createGroupsDataTable(groups?: Group[])` → `Promise` — Create a `GroupsDataTableBuilder`, to build two dimensional Array representations of `Group` dataset.
- `createIntegration(integration: bkper.Integration | Integration)` → `Promise` — Creates a new `Integration` in the Book.
- `createTransactionsDataTable(transactions: Transaction[], account?: Account)` → `TransactionsDataTableBuilder` — Create a `TransactionsDataTableBuilder`, to build two dimensional Array representations of `Transaction` dataset.
- `formatDate(date: Date, timeZone?: string)` → `string` — Formats a date according to date pattern of the Book.
- `formatValue(value: number | Amount | null | undefined)` → `string` — Formats a value according to `DecimalSeparator` and fraction digits of the Book.
- `getAccount(idOrName?: string)` → `Promise` — Gets an `Account` object by id or name.
- `getAccounts()` → `Promise` — Gets all `Accounts` of this Book with full account-group relationships.
- `getApps()` → `Promise` — Retrieve installed `Apps` for this Book.
- `getAutoPost()` / `setAutoPost(autoPost: boolean)` → `boolean | undefined (set: boolean)` — Gets the auto post status of the Book.
- `getBacklog()` → `Promise` — Gets the Backlog of this Book.
- `getBalancesReport(query: string)` → `Promise` — Create a `BalancesReport` based on query.
- `getClosingDate()` / `setClosingDate(closingDate: string | null)` → `string | undefined (set: string | null)` — Gets the closing date of the Book in ISO format yyyy-MM-dd.
- `getCollaborators()` → `Promise` — Gets all collaborators of this Book.
- `getCollection()` → `Collection | undefined` — Gets the collection of this Book, if any.
- `getDatePattern()` / `setDatePattern(datePattern: string)` → `string` — Gets the date pattern of the Book.
- `getDecimalPlaces()` → `number | undefined` — Gets the number of decimal places supported by this Book.
- `getDecimalSeparator()` / `setDecimalSeparator(decimalSeparator: DecimalSeparator)` → `DecimalSeparator` — Gets the decimal separator of the Book.
- `getFile(id: string)` → `Promise` — Retrieve a file by id.
- `getFractionDigits()` / `setFractionDigits(fractionDigits: number)` → `number | undefined (set: number)` — Gets the number of fraction digits supported by this Book.
- `getGroup(idOrName?: string)` → `Promise` — Gets a `Group` object by id or name.
- `getGroups()` → `Promise` — Gets all `Groups` of this Book with complete parent/child hierarchy.
- `getId()` → `string` — Gets the unique identifier of this Book.
- `getIntegrations()` → `Promise` — Gets the existing `Integrations` in the Book.
- `getLastUpdateMs()` → `number | undefined` — Gets the last update date of the book, in milliseconds.
- `getLockDate()` / `setLockDate(lockDate: string | null)` → `string | undefined (set: string | null)` — Gets the lock date of the Book in ISO format yyyy-MM-dd.
- `getName()` / `setName(name: string)` → `string | undefined (set: string)` — Gets the name of this Book.
- `getOwnerName()` → `string | undefined` — Gets the name of the owner of the Book.
- `getPageSize()` / `setPageSize(pageSize: number)` → `number | undefined (set: number)` — Gets the transactions pagination page size.
- `getPeriod()` / `setPeriod(period: Period)` → `Period` — Gets the period slice for balances visualization.
- `getPeriodStartMonth()` / `setPeriodStartMonth(month: Month)` → `Month` — Gets the start month when YEAR period is set.
- `getPermission()` → `Permission` — Gets the permission for the current user in this Book.
- `getSavedQueries()` → `Promise` — Gets the saved queries from this book.
- `getTimeZone()` / `setTimeZone(timeZone: string)` → `string | undefined (set: string)` — Gets the time zone of the Book.
- `getTimeZoneOffset()` → `number | undefined` — Gets the time zone offset of the book, in minutes.
- `getTotalTransactions()` → `number` — Gets the total number of posted transactions.
- `getTotalTransactionsCurrentMonth()` → `number` — Gets the total number of posted transactions on current month.
- `getTotalTransactionsCurrentYear()` → `number` — Gets the total number of posted transactions on current year.
- `getTransaction(id: string)` → `Promise` — Retrieve a transaction by id.
- `getVisibility()` / `setVisibility(visibility: Visibility)` → `Visibility` — Gets the visibility of the book.
- `json()` → `bkper.Book` — Gets an immutable copy of the JSON payload for this resource.
- `listEvents(afterDate: string | null, beforeDate: string | null, onError: boolean, resourceId: string | null, limit: number, cursor?: string)` → `Promise` — Lists events in the Book based on the provided parameters.
- `listTransactions(query?: string, limit?: number, cursor?: string)` → `Promise` — Lists transactions in the Book based on the provided query, limit, and cursor, for pagination.
- `parseDate(date: string)` → `Date` — Parse a date string according to date pattern and timezone of the Book. Also parse ISO yyyy-mm-dd format.
- `parseValue(value: string)` → `Amount | undefined` — Parse a value string according to `DecimalSeparator` and fraction digits of the Book.
- `remove()` → `Promise` — Warning!
- `round(value: number | Amount)` → `Amount` — Rounds a value according to the number of fraction digits of the Book.
- `update()` → `Promise` — Perform update Book, applying pending changes.
- `updateIntegration(integration: bkper.Integration)` → `Promise` — Updates an existing `Integration` in the Book.
*Standard property methods (deleteProperty, getProperties, getProperty, getPropertyKeys, getVisibleProperties, setProperties, setProperty, setVisibleProperties, setVisibleProperty) — see Account.*
**getAccount**
Results are cached to avoid repeated server calls. Account-group relationships
are included if the full chart was loaded via getAccounts() or when the Book
was loaded with includeAccounts=true.
```typescript
// Get individual account (basic data, cached)
const account = await book.getAccount('Bank Account');
// For account-group relationships, use one of these approaches:
// Option 1: Load book with full data upfront
const bookWithAccounts = await Bkper.getBook(bookId, true);
const accountWithGroups = await bookWithAccounts.getAccount('Bank Account');
// Option 2: Load full chart when needed
await book.getAccounts();
const accountWithGroups2 = await book.getAccount('Bank Account');
```
**getAccounts**
Results are cached for performance. Groups are automatically loaded first
to ensure proper linking. Consider using Bkper.getBook(id, true) for
upfront loading when you know you'll need all accounts.
```typescript
// Load all accounts with complete relationships
const accounts = await book.getAccounts();
// Alternative: Load book with accounts upfront (more efficient)
const bookWithAccounts = await Bkper.getBook(bookId, true);
const accounts2 = await bookWithAccounts.getAccounts(); // Already cached
```
**getBalancesReport**
The balances report
Example:
```js
var book = BkperApp.getBook("agtzfmJrcGVyLWhyZHITCxIGTGVkZ2VyGICAgPXjx7oKDA");
var balancesReport = book.getBalancesReport("group:'Equity' after:7/2018 before:8/2018");
var accountBalance = balancesReport.getBalancesContainer("Bank Account").getCumulativeBalance();
```
**getGroup**
Results are cached to avoid repeated server calls. Parent/child relationships
are included if all groups were loaded via getGroups() or when the Book was
loaded with includeGroups=true.
```typescript
// Get individual group (basic data, cached)
const group = await book.getGroup('Assets');
// For parent/child relationships, use one of these approaches:
// Option 1: Load book with full hierarchy upfront
const bookWithGroups = await Bkper.getBook(bookId, false, true);
const groupWithTree = await bookWithGroups.getGroup('Assets');
// Option 2: Load full hierarchy when needed
await book.getGroups();
const groupWithTree2 = await book.getGroup('Assets');
console.log(groupWithTree2.getParent(), groupWithTree2.getChildren());
```
**getGroups**
Results are cached for performance. Group tree relationships are built
during loading. Consider using Bkper.getBook(id, false, true) for
upfront loading when you know you'll need all groups.
```typescript
// Load all groups with complete hierarchy
const groups = await book.getGroups();
// Alternative: Load book with groups upfront (more efficient)
const bookWithGroups = await Bkper.getBook(bookId, false, true);
const groups2 = await bookWithGroups.getGroups(); // Already cached
```
**remove**
Deletes this Book and all its data (transactions, accounts, groups). Book owner only.
### BooksDataTableBuilder
A BooksDataTableBuilder is used to setup and build two-dimensional arrays containing books.
**Constructor:** `new BooksDataTableBuilder(books: Book[])`
**Methods:**
- `build()` → `any[][]` — Builds a two-dimensional array containing all Books.
- `hiddenProperties(include: boolean)` → `BooksDataTableBuilder` — Defines whether to include hidden properties (keys ending with underscore "_").
- `ids(include: boolean)` → `BooksDataTableBuilder` — Defines whether to include book ids.
- `properties(include: boolean)` → `BooksDataTableBuilder` — Defines whether to include custom book properties.
### BotResponse
This class defines a Bot Response associated to an `Event`.
**Constructor:** `new BotResponse(event: Event, payload?: bkper.BotResponse)`
**Properties:**
- `payload`: `bkper.BotResponse`
**Methods:**
- `getAgentId()` → `string | undefined` — Gets the agent id of this Bot Response.
- `getCreatedAt()` → `Date | undefined` — Gets the date this Bot Response was created.
- `getEvent()` → `Event` — Gets the Event this Bot Response is associated to.
- `getMessage()` → `string | undefined` — Gets the message of this Bot Response.
- `getType()` → `BotResponseType | undefined` — Gets the type of this Bot Response.
- `remove()` → `Promise` — Delete this Bot Response.
- `replay()` → `Promise` — Replay this Bot Response.
### Collaborator *(extends Resource)*
This class defines a Collaborator of a `Book`.
A Collaborator represents a user that has been granted access to a Book with specific permissions.
**Constructor:** `new Collaborator(book: Book, payload?: bkper.Collaborator)`
**Properties:**
- `payload`: `bkper.Collaborator` — The underlying payload data for this resource
**Methods:**
- `create(message?: string)` → `Promise` — Performs create new Collaborator.
- `getEmail()` / `setEmail(email: string)` → `string | undefined (set: string)` — Gets the Collaborator email address.
- `getId()` → `string | undefined` — Gets the Collaborator internal id.
- `getPermission()` / `setPermission(permission: Permission)` → `Permission | undefined (set: Permission)` — Gets the permission level of the Collaborator.
- `json()` → `bkper.Collaborator` — Gets an immutable copy of the JSON payload for this resource.
- `remove()` → `Promise` — Performs remove Collaborator.
- `update()` → `Promise` — Performs update Collaborator.
### Collection *(extends Resource)*
This class defines a Collection of `Books`.
**Constructor:** `new Collection(payload?: bkper.Collection, config?: Config)`
**Properties:**
- `payload`: `bkper.Collection` — The underlying payload data for this resource
**Methods:**
- `addBooks(books: Book[])` → `Promise` — Adds Books to this Collection.
- `create()` → `Promise` — Performs create new Collection.
- `getBooks()` → `Book[]` — Gets all Books of this collection.
- `getId()` → `string | undefined` — Gets the unique identifier of this Collection.
- `getName()` / `setName(name: string)` → `string | undefined (set: string)` — Gets the name of this Collection.
- `getOwnerUsername()` → `string | undefined` — Gets the username of the owner of this Collection
- `getPermission()` → `Permission | undefined` — Gets the user permission for this Collection
- `getUpdatedAt()` → `string | undefined` — Gets the last update date of this Collection
- `json()` → `bkper.Collection` — Gets an immutable copy of the JSON payload for this resource.
- `remove()` → `Promise` — Performs delete Collection.
- `removeBooks(books: Book[])` → `Promise` — Removes Books from this Collection.
- `update()` → `Promise` — Performs update Collection, applying pending changes.
### Connection *(extends ResourceProperty)*
This class defines a Connection from an `User` to an external service.
**Constructor:** `new Connection(payload?: bkper.Connection, config?: Config)`
**Properties:**
- `payload`: `bkper.Connection` — The underlying payload data for this resource
**Methods:**
- `clearTokenProperties()` → `void` — Cleans any token property stored in the Connection.
- `create()` → `Promise` — Performs create new Connection.
- `getAgentId()` / `setAgentId(agentId: string)` → `string | undefined (set: string)` — Gets the agentId of the Connection.
- `getDateAddedMs()` → `string | undefined` — Gets the date when the Connection was added.
- `getEmail()` → `string | undefined` — Gets the email of the owner of the Connection.
- `getId()` → `string | undefined` — Gets the id of the Connection.
- `getIntegrations()` → `Promise` — Gets the existing `Integrations` on the Connection.
- `getLogo()` → `string | undefined` — Gets the logo of the Connection.
- `getName()` / `setName(name: string)` → `string | undefined (set: string)` — Gets the name of the Connection.
- `getType()` / `setType(type: "APP" | "BANK")` → `"APP" | "BANK" | undefined (set: "APP" | "BANK")` — Gets the type of the Connection.
- `getUUID()` / `setUUID(uuid: string)` → `string | undefined (set: string)` — Gets the universal unique identifier of this Connection.
- `json()` → `bkper.Connection` — Gets an immutable copy of the JSON payload for this resource.
- `remove()` → `Promise` — Performs remove Connection.
*Standard property methods (deleteProperty, getProperties, getProperty, getPropertyKeys, getVisibleProperties, setProperties, setProperty, setVisibleProperties, setVisibleProperty) — see Account.*
### Event
This class defines an Event from a `Book`.
An event is an object that represents an action (such as posting or deleting a `Transaction`) made by an actor (such as a user or a [Bot](https://bkper.com/apps) acting on behalf of a user).
**Constructor:** `new Event(book: Book, payload?: bkper.Event)`
**Properties:**
- `payload`: `bkper.Event`
**Methods:**
- `getAgent()` → `Agent | undefined` — Gets the Agent who performed the Event.
- `getBook()` → `Book` — Gets the book in which the Event was created.
- `getBotResponses()` → `BotResponse[]` — Gets the Bot Responses associated to this Event.
- `getCreatedAt()` → `Date | undefined` — Gets the date the Event was created.
- `getId()` → `string | undefined` — Gets the id of the Event.
- `getType()` → `EventType | undefined` — Gets the type of the Event.
- `getUser()` → `User | undefined` — Gets the user who performed the Event.
- `hasErrorResponse()` → `boolean` — Checks if this Event has at least one Bot Response of type ERROR.
- `json()` → `bkper.Event` — Gets an immutable copy of the JSON payload for this Event.
### EventList
A list associated with an event query.
**Constructor:** `new EventList(book: Book, payload: bkper.EventList)`
**Methods:**
- `getCursor()` → `string | undefined` — Gets the cursor associated with the query for pagination.
- `getFirst()` → `Event | undefined` — Gets the first Event in the list.
- `getItems()` → `Event[]` — Get the events in the list.
- `size()` → `number` — Get the total number of events in the list.
### File *(extends ResourceProperty)*
This class defines a File uploaded to a `Book`.
A File can be attached to a `Transaction` or used to import data.
**Constructor:** `new File(book: Book, payload?: bkper.File)`
**Properties:**
- `payload`: `bkper.File` — The underlying payload data for this resource
**Methods:**
- `create()` → `Promise` — Perform create new File.
- `getBook()` → `Book` — Gets the Book this File belongs to.
- `getContent()` / `setContent(content: string)` → `Promise (set: string)` — Gets the file content Base64 encoded.
- `getContentType()` / `setContentType(contentType: string)` → `string | undefined (set: string)` — Gets the File content type.
- `getId()` → `string | undefined` — Gets the File id.
- `getName()` / `setName(name: string)` → `string | undefined (set: string)` — Gets the File name.
- `getSize()` → `number | undefined` — Gets the file size in bytes.
- `getUrl()` → `string | undefined` — Gets the file serving url for accessing via browser.
- `json()` → `bkper.File` — Gets an immutable copy of the JSON payload for this resource.
- `update()` → `Promise` — Perform update File, applying pending changes.
*Standard property methods (deleteProperty, getProperties, getProperty, getPropertyKeys, getVisibleProperties, setProperties, setProperty, setVisibleProperties, setVisibleProperty) — see Account.*
### Group *(extends ResourceProperty)*
This class defines a Group of `Accounts`.
Accounts can be grouped by different meaning, like Expenses, Revenue, Assets, Liabilities and so on
Its useful to keep organized and for high level analysis.
**Constructor:** `new Group(book: Book, payload?: bkper.Group)`
**Properties:**
- `payload`: `bkper.Group` — The underlying payload data for this resource
**Methods:**
- `create()` → `Promise` — Performs create new group.
- `getAccounts()` → `Promise` — Gets all Accounts of this group.
- `getChildren()` → `Group[]` — Gets the children of the Group.
- `getDepth()` → `number` — Gets the depth of the Group in the hierarchy.
- `getDescendants()` → `Set` — Gets all descendant Groups of the current Group.
- `getDescendantTreeIds()` → `Set` — Gets the IDs of all descendant Groups in a tree structure.
- `getId()` → `string | undefined` — Gets the id of this Group.
- `getName()` / `setName(name: string)` → `string | undefined (set: string)` — Gets the name of this Group.
- `getNormalizedName()` → `string` — Gets the normalized name of this group without spaces and special characters.
- `getParent()` / `setParent(group: Group | null | undefined)` → `Group | undefined (set: Group | null | undefined)` — Gets the parent Group.
- `getRoot()` → `Group` — Gets the root Group of the current Group.
- `getRootName()` → `string` — Gets the name of the root Group.
- `getType()` → `AccountType` — Gets the type of the accounts of this group.
- `hasAccounts()` → `boolean | undefined` — Tells if this group has any account in it.
- `hasChildren()` → `boolean` — Checks if the Group has any children.
- `hasParent()` → `boolean` — Checks if the Group has a parent.
- `isBalanceVerified()` → `Promise` — Tells if the balance of this Group has been verified/audited.
- `isCredit()` → `boolean | undefined` — Tells if this is a credit (Incoming and Liabilities) group.
- `isHidden()` → `boolean | undefined` — Tells if the Group is hidden on main transactions menu.
- `isLeaf()` → `boolean` — Checks if the Group is a leaf node (i.e., has no children).
- `isLocked()` → `boolean` — Tells if the Group is locked by the Book owner.
- `isMixed()` → `boolean | undefined` — Tells if this is a mixed (Assets/Liabilities or Incoming/Outgoing) group.
- `isPermanent()` → `boolean | undefined` — Tells if the Group is permanent.
- `isRoot()` → `boolean` — Checks if the Group is a root node (i.e., has no parent).
- `json()` → `bkper.Group` — Gets an immutable copy of the JSON payload for this resource.
- `remove()` → `Promise` — Performs delete group.
- `setHidden(hidden: boolean)` → `Group` — Hide/Show group on main menu.
- `setLocked(locked: boolean)` → `Group` — Sets the locked state of the Group.
- `update()` → `Promise` — Performs update group, applying pending changes.
*Standard property methods (deleteProperty, getProperties, getProperty, getPropertyKeys, getVisibleProperties, setProperties, setProperty, setVisibleProperties, setVisibleProperty) — see Account.*
### GroupsDataTableBuilder
A GroupsDataTableBuilder is used to setup and build two-dimensional arrays containing groups.
**Constructor:** `new GroupsDataTableBuilder(groups: Group[])`
**Methods:**
- `build()` → `any[][]` — Builds a two-dimensional array containing all Groups.
- `hiddenProperties(include: boolean)` → `GroupsDataTableBuilder` — Defines whether to include hidden properties (keys ending with underscore "_").
- `ids(include: boolean)` → `GroupsDataTableBuilder` — Defines whether include group ids.
- `properties(include: boolean)` → `GroupsDataTableBuilder` — Defines whether include custom group properties.
- `tree(enable: boolean)` → `GroupsDataTableBuilder` — Defines whether to render groups as an indented tree instead of flat rows with a Parent column.
### Integration *(extends ResourceProperty)*
This class defines a Integration from an `User` to an external service.
**Constructor:** `new Integration(payload?: bkper.Integration, config?: Config)`
**Properties:**
- `payload`: `bkper.Integration` — The underlying payload data for this resource
**Methods:**
- `getAddedBy()` → `string | undefined` — Gets the name of the user who added the Integration.
- `getAgentId()` → `string | undefined` — Gets the agent id of the Integration.
- `getBookId()` → `string | undefined` — Gets the `Book` id of the Integration.
- `getDateAddedMs()` → `string | undefined` — Gets the date when the Integration was added.
- `getId()` → `string | undefined` — Gets the id of the Integration.
- `getLastUpdateMs()` → `string | undefined` — Gets the date when the Integration was last updated.
- `getLogo()` → `string | undefined` — ~~Deprecated: Use getLogoUrl instead.~~ Gets the logo of the Integration.
- `getLogoUrl()` → `string | undefined` — Gets the logo url of this Integration.
- `getLogoUrlDark()` → `string | undefined` — Gets the logo url of this Integration in dark mode.
- `getName()` → `string | undefined` — Gets the name of the Integration.
- `json()` → `bkper.Integration` — Gets an immutable copy of the JSON payload for this resource.
- `remove()` → `Promise` — Performs remove Integration.
*Standard property methods (deleteProperty, getProperties, getProperty, getPropertyKeys, getVisibleProperties, setProperties, setProperty, setVisibleProperties, setVisibleProperty) — see Account.*
### Query *(extends Resource)*
Defines a saved Query in a `Book`.
Queries can be saved on Books by users.
**Constructor:** `new Query(book: Book, payload?: bkper.Query)`
**Properties:**
- `payload`: `bkper.Query` — The underlying payload data for this resource
**Methods:**
- `create()` → `Promise` — Perform create new Query.
- `getId()` → `string | undefined` — Gets the Query universal identifier.
- `getQuery()` / `setQuery(query: string)` → `string | undefined (set: string)` — Gets the query string to be executed.
- `getTitle()` / `setTitle(title: string)` → `string | undefined (set: string)` — Gets the title of this saved Query.
- `json()` → `bkper.Query` — Gets an immutable copy of the JSON payload for this resource.
- `remove()` → `Promise` — Perform delete Query.
- `update()` → `Promise` — Perform update Query, applying pending changes.
### Template *(extends Resource)*
This class defines a Template.
A Template is a pre-configured setup for `Books` and associated Google Sheets that provides users with a starting point for specific accounting or financial management needs.
**Constructor:** `new Template(json?: bkper.Template, config?: Config)`
**Properties:**
- `payload`: `bkper.Template` — The underlying payload data for this resource
**Methods:**
- `getBookId()` → `string | undefined` — Gets the bookId of the `Book` associated with the Template.
- `getBookLink()` → `string | undefined` — Gets the link of the `Book` associated with the Template.
- `getCategory()` → `string | undefined` — Gets the category of the Template.
- `getDescription()` → `string | undefined` — Gets the description of the Template.
- `getImageUrl()` → `string | undefined` — Gets the url of the image of the Template.
- `getName()` → `string | undefined` — Gets the name of the Template.
- `getSheetsLink()` → `string | undefined` — Gets the link of the Google Sheets spreadsheet associated with the Template.
- `getTimesUsed()` → `number` — Gets the times the Template has been used.
- `json()` → `bkper.Template` — Gets an immutable copy of the JSON payload for this resource.
### Transaction *(extends ResourceProperty)*
This class defines a Transaction between [credit and debit](http://en.wikipedia.org/wiki/Debits_and_credits) `Accounts`.
A Transaction is the main entity on the [Double Entry](http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system) [Bookkeeping](http://en.wikipedia.org/wiki/Bookkeeping) system.
**Constructor:** `new Transaction(book: Book, payload?: bkper.Transaction)`
**Properties:**
- `payload`: `bkper.Transaction` — The underlying payload data for this resource
**Methods:**
- `addFile(file: File)` → `Transaction` — Adds a file attachment to the Transaction.
- `addRemoteId(remoteId: string)` → `Transaction` — Add a remote id to the Transaction.
- `addUrl(url: string)` → `Transaction` — Add a url to the Transaction. Url starts with https://
- `check()` → `Promise` — Perform check transaction.
- `create()` → `Promise` — Perform create new draft transaction.
- `from(account: bkper.Account | Account | null | undefined)` → `Transaction` — Sets the credit/origin `Account` of this Transaction. Same as setCreditAccount()
- `getAccountBalance(raw?: boolean)` → `Promise` — Gets the balance that the `Account` has at that day, when listing transactions of that Account.
- `getAgentId()` → `string | undefined` — Gets the unique identifier of the agent that created this transaction.
- `getAgentLogoUrl()` → `string | undefined` — Gets the logo URL of the agent that created this transaction.
- `getAgentLogoUrlDark()` → `string | undefined` — Gets the dark mode logo URL of the agent that created this transaction.
- `getAgentName()` → `string | undefined` — Gets the name of the agent that created this transaction.
- `getAmount()` / `setAmount(amount: string | number | Amount)` → `Amount | undefined (set: string | number | Amount)` — Gets the amount of this Transaction.
- `getAmountFormatted()` → `string | undefined` — Gets the formatted amount of this Transaction according to the Book format.
- `getBook()` → `Book` — Gets the book associated with this transaction.
- `getCreatedAt()` → `Date` — Gets the date when the transaction was created.
- `getCreatedAtFormatted()` → `string` — Gets the formatted creation date of the transaction.
- `getCreatedBy()` → `string | undefined` — Gets the username of the user who created the transaction.
- `getCreditAccount()` / `setCreditAccount(account: bkper.Account | Account | null | undefined)` → `Promise (set: bkper.Account | Account | null | undefined)` — Gets the credit account associated with this Transaction. Same as origin account
- `getCreditAccountName()` → `Promise` — Gets the name of this Transaction's credit account.
- `getCreditAmount(account: string | Account)` → `Promise` — Get the absolute amount of this Transaction if the given account is at the credit side.
- `getDate()` / `setDate(date: string | Date)` → `string | undefined (set: string | Date)` — Gets the transaction date in ISO format.
- `getDateFormatted()` → `string | undefined` — Gets the transaction date formatted according to the book's date pattern.
- `getDateObject()` → `Date` — Gets the transaction date as a Date object in the book's timezone.
- `getDateValue()` → `number | undefined` — Gets the transaction date as a numeric value.
- `getDebitAccount()` / `setDebitAccount(account: bkper.Account | Account | null | undefined)` → `Promise (set: bkper.Account | Account | null | undefined)` — Gets the debit account associated with this Transaction. Same as destination account
- `getDebitAccountName()` → `Promise` — Gets the name of this Transaction's debit account.
- `getDebitAmount(account: string | Account)` → `Promise` — Gets the absolute amount of this Transaction if the given account is at the debit side.
- `getDescription()` / `setDescription(description: string)` → `string` — Gets the description of this Transaction.
- `getFiles()` → `File[]` — Gets all files attached to the transaction.
- `getId()` → `string | undefined` — Gets the unique identifier of the transaction.
- `getOtherAccount(account: string | Account)` → `Promise` — Gets the `Account` at the other side of the transaction given the one in one side.
- `getOtherAccountName(account: string | Account)` → `Promise` — The Account name at the other side of this Transaction given the one in one side.
- `getRemoteIds()` → `string[]` — Gets the remote IDs associated with this transaction. Remote ids are used to avoid duplication.
- `getStatus()` → `TransactionStatus` — Gets the status of the transaction.
- `getTags()` → `string[]` — Gets all hashtags used in the transaction.
- `getUpdatedAt()` → `Date` — Gets the date when the transaction was last updated.
- `getUpdatedAtFormatted()` → `string` — Gets the formatted last update date of the transaction.
- `getUrls()` / `setUrls(urls: string[])` → `string[]` — Gets all URLs associated with the transaction.
- `hasTag(tag: string)` → `boolean` — Check if the transaction has the specified tag.
- `isChecked()` → `boolean | undefined` — Checks if the transaction is marked as checked.
- `isCredit(account?: Account)` → `Promise` — Tell if the given account is credit on this Transaction
- `isDebit(account?: Account)` → `Promise` — Tell if the given account is debit on the Transaction
- `isLocked()` → `boolean` — Checks if the transaction is locked by the book's lock or closing date.
- `isPosted()` → `boolean | undefined` — Checks if the transaction has been posted to the accounts.
- `isTrashed()` → `boolean | undefined` — Checks if the transaction is in the trash.
- `json()` → `bkper.Transaction` — Gets an immutable copy of the JSON payload for this resource.
- `post()` → `Promise` — Perform post transaction, changing credit and debit `Account` balances.
- `removeFile(file: File)` → `Transaction` — Removes a file attachment from the Transaction.
- `setChecked(checked: boolean)` → `Transaction` — Set the check state of the Transaction.
- `to(account: bkper.Account | Account | null | undefined)` → `Transaction` — Sets the debit/destination `Account` of this Transaction. Same as setDebitAccount()
- `trash()` → `Promise` — Trash the transaction.
- `uncheck()` → `Promise` — Perform uncheck transaction.
- `untrash()` → `Promise` — Untrash the transaction.
- `update()` → `Promise` — Update transaction, applying pending changes.
*Standard property methods (deleteProperty, getProperties, getProperty, getPropertyKeys, getVisibleProperties, setProperties, setProperty, setVisibleProperties, setVisibleProperty) — see Account.*
**addFile**
Files not previously created in the Book will be automatically created when the transaction is persisted.
**getAccountBalance**
Evolved balances is returned when searching for transactions of a permanent `Account`.
Only comes with the last posted transaction of the day.
### TransactionList
A list associated with a transaction query.
**Constructor:** `new TransactionList(book: Book, payload: bkper.TransactionList)`
**Methods:**
- `getAccount()` → `Promise` — Retrieves the account associated with the query, when filtering by account.
- `getCursor()` → `string | undefined` — Gets the cursor associated with the query for pagination.
- `getFirst()` → `Transaction | undefined` — Gets the first Transaction in the list.
- `getItems()` → `Transaction[]` — Gets the transactions in the list.
- `size()` → `number` — Gets the total number of transactions in the list.
### TransactionsDataTableBuilder
A TransactionsDataTableBuilder is used to setup and build two-dimensional arrays containing transactions.
**Constructor:** `new TransactionsDataTableBuilder(book: Book, transactions: Transaction[], account?: Account)`
**Methods:**
- `build()` → `Promise` — Builds a two-dimensional array containing all transactions.
- `formatDates(format: boolean)` → `TransactionsDataTableBuilder` — Defines whether the dates should be formatted, based on date pattern of the `Book`.
- `formatValues(format: boolean)` → `TransactionsDataTableBuilder` — Defines whether amounts should be formatted based on `DecimalSeparator` of the `Book`.
- `getAccount()` → `Account | undefined` — Gets the account used to filter transactions, when applicable.
- `hiddenProperties(include: boolean)` → `TransactionsDataTableBuilder` — Defines whether to include hidden properties (keys ending with underscore "_").
- `ids(include: boolean)` → `TransactionsDataTableBuilder` — Defines whether to include transaction ids and remote ids.
- `includeIds(include: boolean)` → `TransactionsDataTableBuilder` — ~~Deprecated: Use `ids` instead.~~
- `includeProperties(include: boolean)` → `TransactionsDataTableBuilder` — ~~Deprecated: Use `properties` instead.~~
- `includeUrls(include: boolean)` → `TransactionsDataTableBuilder` — ~~Deprecated: Use `urls` instead.~~
- `properties(include: boolean)` → `TransactionsDataTableBuilder` — Defines whether to include custom transaction properties.
- `recordedAt(include: boolean)` → `TransactionsDataTableBuilder` — Defines whether to include the "Recorded at" column.
- `urls(include: boolean)` → `TransactionsDataTableBuilder` — Defines whether to include attachments and url links.
### User *(extends Resource)*
This class defines a User on the Bkper platform.
Users can own and collaborate on `Books`, manage `Collections`, and connect to external services through `Connections`.
Each User has a unique identity, subscription plan details, and access permissions across the platform.
**Constructor:** `new User(payload?: bkper.User, config?: Config)`
**Properties:**
- `payload`: `bkper.User` — The underlying payload data for this resource
**Methods:**
- `getAvatarUrl()` → `string | undefined` — Gets the avatar url of the User.
- `getBilling()` → `Promise` — Gets the billing information for this User.
- `getConnection(id: string)` → `Promise` — Gets a `Connection` of the User.
- `getConnections()` → `Promise` — Gets the `Connections` of the User.
- `getEmail()` → `string | undefined` — Gets the email of the User.
- `getFullName()` → `string | undefined` — Gets the full name of the User.
- `getGivenName()` → `string | undefined` — Gets the given name of the User.
- `getHostedDomain()` → `string | undefined` — Gets the hosted domain of the User.
- `getId()` → `string | undefined` — Gets the id of the User.
- `getName()` → `string | undefined` — Gets the name of the User.
- `getUsername()` → `string | undefined` — Gets the username of the User.
- `hasUsedConnections()` → `boolean | undefined` — Tells if the User has already used `Connections`.
- `json()` → `bkper.User` — Gets an immutable copy of the JSON payload for this resource.
## Interfaces
### BalancesContainer
The container of balances of an `Account` or `Group`
The container is composed of a list of `Balances` for a window of time, as well as its period and cumulative totals.
**Properties:**
- `getAccount`: `() => Promise` — Gets the `Account` associated with this container.
- `getBalances`: `() => Balance[]` — Gets all `Balances` of the container
- `getBalancesContainer`: `(name: string) => BalancesContainer` — Gets a specific `BalancesContainer`.
- `getBalancesContainers`: `() => BalancesContainer[]` — Gets all child `BalancesContainers`.
- `getBalancesReport`: `() => BalancesReport` — Gets the parent `BalancesReport` of the container.
- `getCumulativeBalance`: `() => Amount` — Gets the cumulative balance to the date.
- `getCumulativeBalanceRaw`: `() => Amount` — Gets the cumulative raw balance to the date.
- `getCumulativeBalanceRawText`: `() => string` — Gets the cumulative raw balance formatted according to `Book` decimal format and fraction digits.
- `getCumulativeBalanceText`: `() => string` — Gets the cumulative balance formatted according to `Book` decimal format and fraction digits.
- `getDepth`: `() => number` — Gets the depth in the parent chain up to the root.
- `getGroup`: `() => Promise` — Gets the `Group` associated with this container.
- `getName`: `() => string` — Gets the `Account` or `Group` name.
- `getNormalizedName`: `() => string` — Gets the `Account` or `Group` name without spaces or special characters.
- `getParent`: `() => BalancesContainer | null` — Gets the parent BalanceContainer.
- `getPeriodBalance`: `() => Amount` — Gets the balance on the date period.
- `getPeriodBalanceRaw`: `() => Amount` — Gets the raw balance on the date period.
- `getPeriodBalanceRawText`: `() => string` — Gets the raw balance on the date period formatted according to `Book` decimal format and fraction digits.
- `getPeriodBalanceText`: `() => string` — Gets the balance on the date period formatted according to `Book` decimal format and fraction digits.
- `hasGroupBalances`: `() => boolean` — Gets whether the balance container is from a parent group.
- `isCredit`: `() => boolean | undefined` — Gets the credit nature of the BalancesContainer, based on `Account` or `Group`.
- `isFromAccount`: `() => boolean` — Gets whether this balance container is from an `Account`.
- `isFromGroup`: `() => boolean` — Gets whether this balance container is from a `Group`.
- `isPermanent`: `() => boolean` — Tell if this balance container is permanent, based on the `Account` or `Group`.
- `payload`: `bkper.AccountBalances | bkper.GroupBalances`
**Methods:**
- `createDataTable()` → `BalancesDataTableBuilder` — Creates a BalancesDataTableBuilder to generate a two-dimensional array with all `BalancesContainers`
- `getCumulativeCredit()` → `Amount` — The cumulative credit to the date.
- `getCumulativeCreditText()` → `string` — The cumulative credit formatted according to `Book` decimal format and fraction digits.
- `getCumulativeDebit()` → `Amount` — The cumulative debit to the date.
- `getCumulativeDebitText()` → `string` — The cumulative credit formatted according to `Book` decimal format and fraction digits.
- `getPeriodCredit()` → `Amount` — The credit on the date period.
- `getPeriodCreditText()` → `string` — The credit on the date period formatted according to `Book` decimal format and fraction digits
- `getPeriodDebit()` → `Amount` — The debit on the date period.
- `getPeriodDebitText()` → `string` — The debit on the date period formatted according to `Book` decimal format and fraction digits
- `getProperties()` → `{ [key: string]: string }` — Gets the custom properties stored in this Account or Group.
- `getProperty(keys: string[])` → `string | undefined` — Gets the property value for given keys. First property found will be retrieved
- `getPropertyKeys()` → `string[]` — Gets the custom properties keys stored in the associated `Account` or `Group`.
**getBalancesContainers**
**NOTE**: Only for Group balance containers. Accounts returns null.
**isCredit**
For `Account`, the credit nature will be the same as the one from the Account.
For `Group`, the credit nature will be the same, if all accounts containing on it has the same credit nature. False if mixed.
**isPermanent**
Permanent are the ones which final balance is relevant and keep its balances over time.
They are also called [Real Accounts](http://en.wikipedia.org/wiki/Account_(accountancy)#Based_on_periodicity_of_flow).
Usually represents assets or liabilities, capable of being perceived by the senses or the mind, like bank accounts, money, debts and so on.
### Config
This class defines the `Bkper` API Config.
**Properties:**
- `agentIdProvider?`: `() => Promise` — Provides the agent ID to identify the calling agent for attribution purposes.
- `apiKeyProvider?`: `() => Promise` — Optional API key for dedicated quota limits.
- `oauthTokenProvider?`: `() => Promise` — Issue a valid OAuth2 access token with **https://www.googleapis.com/auth/userinfo.email** scope authorized.
- `requestErrorHandler?`: `(error: any) => any` — Custom request error handler
- `requestHeadersProvider?`: `() => Promise<{ [key: string]: string }>` — Provides additional headers to append to the API request
- `requestRetryHandler?`: `(status?: number, error?: any, attempt?: number) => Promise` — Custom request retry handler.
**agentIdProvider**
This ID is sent via the `bkper-agent-id` header with each API request,
allowing the server to attribute actions to the correct agent.
**apiKeyProvider**
If not provided, requests use a shared managed quota via the Bkper API proxy.
Use your own API key for dedicated quota limits and project-level usage tracking.
API keys are for project identification only, not for authentication or agent attribution.
Agent attribution is handled separately via the `agentIdProvider`.
**requestRetryHandler**
This function is called when a request fails and needs to be retried.
It provides the HTTP status code, error message, and the number of retry attempts made so far.
## Enums
### AccountType
Enum that represents account types.
- `ASSET` — Asset account type
- `INCOMING` — Incoming account type
- `LIABILITY` — Liability account type
- `OUTGOING` — Outgoing account type
### BalanceType
Enum that represents balance types.
- `CUMULATIVE` — Cumulative balance
- `PERIOD` — Period balance
- `TOTAL` — Total balance
### BotResponseType
Enum that represents the type of a Bot Response
- `ERROR` — Error bot response
- `INFO` — Info bot response
- `WARNING` — Warning bot response
### DecimalSeparator
Decimal separator of numbers on book
- `COMMA` — ,
- `DOT` — .
### EventType
Enum that represents event types.
- `ACCOUNT_CREATED`
- `ACCOUNT_DELETED`
- `ACCOUNT_UPDATED`
- `BOOK_DELETED`
- `BOOK_UPDATED`
- `COLLABORATOR_ADDED`
- `COLLABORATOR_REMOVED`
- `COLLABORATOR_UPDATED`
- `COMMENT_CREATED`
- `COMMENT_DELETED`
- `FILE_CREATED`
- `FILE_UPDATED`
- `GROUP_CREATED`
- `GROUP_DELETED`
- `GROUP_UPDATED`
- `INTEGRATION_CREATED`
- `INTEGRATION_DELETED`
- `INTEGRATION_UPDATED`
- `QUERY_CREATED`
- `QUERY_DELETED`
- `QUERY_UPDATED`
- `TRANSACTION_CHECKED`
- `TRANSACTION_CREATED`
- `TRANSACTION_DELETED`
- `TRANSACTION_POSTED`
- `TRANSACTION_RESTORED`
- `TRANSACTION_UNCHECKED`
- `TRANSACTION_UPDATED`
### Month
Enum that represents a Month.
- `APRIL`
- `AUGUST`
- `DECEMBER`
- `FEBRUARY`
- `JANUARY`
- `JULY`
- `JUNE`
- `MARCH`
- `MAY`
- `NOVEMBER`
- `OCTOBER`
- `SEPTEMBER`
### Period
Enum that represents a period slice.
- `MONTH` — Monthly period
- `QUARTER` — Quarterly period
- `YEAR` — Yearly period
### Periodicity
The Periodicity of the query. It may depend on the level of granularity you write the range params.
- `DAILY` — Example: after:25/01/1983, before:04/03/2013, after:$d-30, before:$d, after:$d-15/$m
- `MONTHLY` — Example: after:jan/2013, before:mar/2013, after:$m-1, before:$m
- `YEARLY` — Example: on:2013, after:2013, $y
### Permission
Enum representing permissions of user in the Book
- `EDITOR` — Manage accounts, transactions, book configuration and sharing
- `NONE` — No permission
- `OWNER` — Manage everything, including book visibility and deletion. Only one owner per book.
- `POSTER` — View transactions, accounts, record and delete drafts
- `RECORDER` — Record and delete drafts only. Useful to collect data only
- `VIEWER` — View transactions, accounts and balances.
### TransactionStatus
Enum that represents the status of a Transaction.
- `CHECKED` — Transaction is posted and checked
- `DRAFT` — Transaction is a draft, not yet posted
- `TRASHED` — Transaction is in the trash
- `UNCHECKED` — Transaction is posted but not checked
### Visibility
Enum representing the visibility of a Book
- `PRIVATE` — The book can be accessed by the owner and collaborators
- `PUBLIC` — The book can be accessed by anyone with the link
---
source: /docs/api/bkper-web-auth.md
# @bkper/web-auth
> Web authentication SDK for Bkper — OAuth flows, token management, and session handling.
[](https://www.npmjs.com/package/@bkper/web-auth) [](https://github.com/bkper/bkper-web-sdks)
# @bkper/web-auth
OAuth authentication SDK for apps on the [Bkper Platform](https://bkper.com/docs/build/apps/overview) (`*.bkper.app` subdomains).
## Quick Start
```typescript
import { BkperAuth } from '@bkper/web-auth';
// Initialize client with callbacks
const auth = new BkperAuth({
onLoginSuccess: () => {
console.log('User authenticated!');
loadUserData();
},
onLoginRequired: () => {
console.log('Please sign in');
showLoginButton();
},
});
// Initialize authentication flow on app load
await auth.init();
// Get access token for API calls
const token = auth.getAccessToken();
if (token) {
fetch('/api/data', {
headers: { Authorization: `Bearer ${token}` },
});
}
```
## Handling Token Expiration
Access tokens expire and need to be refreshed. The recommended pattern is to handle authentication errors and retry:
```typescript
async function apiRequest(url: string, options: RequestInit = {}) {
// Add auth header
const token = auth.getAccessToken();
options.headers = {
...options.headers,
Authorization: `Bearer ${token}`,
};
const response = await fetch(url, options);
// Handle expired token
if (response.status === 403) {
try {
await auth.refresh();
options.headers = {
...options.headers,
Authorization: `Bearer ${auth.getAccessToken()}`,
};
return fetch(url, options); // Retry once
} catch (error) {
// Refresh failed - the onError callback will be triggered
// Handle the error appropriately (e.g., redirect to login, show error message)
throw error;
}
}
return response;
}
```
## What's Included
- OAuth authentication SDK for apps on `*.bkper.app` subdomains
- Callback-based API for authentication events
- OAuth flow with in-memory token management
- Token refresh mechanism
- TypeScript support with full type definitions
## How It Works
**Session Persistence:**
- Access tokens are stored in-memory (cleared on page refresh)
- Sessions persist via HTTP-only cookies scoped to the `.bkper.app` domain
- Call `init()` on app load to restore the session from cookies
> **Note:** This SDK only works for apps hosted on `*.bkper.app` subdomains. For apps on other domains, use a valid access token directly with [bkper-js](https://github.com/bkper/bkper-js#cdn--browser).
**Security:**
- HTTP-only cookies protect refresh tokens from XSS
- In-memory access tokens minimize exposure
## TypeScript Support
This package is written in TypeScript and provides full type definitions out of the box. All public APIs are fully typed, including callbacks and configuration options.
```typescript
import { BkperAuth, BkperAuthConfig } from '@bkper/web-auth';
const config: BkperAuthConfig = {
onLoginSuccess: () => console.log('Authenticated'),
onError: error => console.error('Auth error:', error),
};
const auth = new BkperAuth(config);
```
## Browser Compatibility
This package requires a modern browser with support for:
- [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility) for HTTP requests
- [Location API](https://developer.mozilla.org/en-US/docs/Web/API/Location) for login/logout redirects
The app must be deployed to a `*.bkper.app` subdomain for session cookies to work.
## Classes
### BkperAuth
OAuth authentication client for the Bkper API.
Provides framework-agnostic authentication with callback-based event handling.
Access tokens are stored in-memory; sessions persist via HTTP-only cookies.
```typescript
// Initialize authentication client
const auth = new BkperAuth({
onLoginSuccess: () => loadUserData(),
onLoginRequired: () => showLoginButton()
});
// Restore session on app load
await auth.init();
```
**Constructor:** `new BkperAuth(config?: BkperAuthConfig)`
Creates a new BkperAuth instance.
```typescript
// Simple usage with defaults
const auth = new BkperAuth();
// With callbacks
const auth = new BkperAuth({
onLoginSuccess: () => console.log('Logged in!'),
onLoginRequired: () => showLoginDialog(),
onError: (error) => console.error(error)
});
```
**Methods:**
- `getAccessToken()` → `string | undefined` — Gets the current access token.
- `init()` → `Promise` — Initializes the authentication state by attempting to refresh the access token.
- `login()` → `void` — Redirects the user to the login page.
- `logout()` → `void` — Logs out the user and redirects to the logout page.
- `refresh()` → `Promise` — Refreshes the access token using the current session.
**getAccessToken**
```typescript
const token = auth.getAccessToken();
if (token) {
// Make authenticated API calls
fetch('/api/data', {
headers: { 'Authorization': `Bearer ${token}` }
});
}
```
**init**
Call this method when your app loads to restore the user's session.
Triggers `onLoginSuccess` if a valid session exists, or `onLoginRequired` if login is needed.
**login**
The user will be redirected to the authentication service to complete the login flow.
After successful login, they will be redirected back to the current page.
```typescript
// Trigger login when user clicks a button
loginButton.addEventListener('click', () => {
auth.login();
});
```
**logout**
Triggers the `onLogout` callback before redirecting.
The user's session will be terminated.
```typescript
// Logout when user clicks logout button
logoutButton.addEventListener('click', () => {
auth.logout();
});
```
**refresh**
Call this when API requests return 403 to get a new token and retry.
Triggers `onTokenRefresh` callback if successful.
Throws error if the refresh fails (network error, expired session, etc.).
```typescript
// Handle 403 by refreshing and retrying
const response = await fetch('/api/data', {
headers: { 'Authorization': `Bearer ${auth.getAccessToken()}` }
});
if (response.status === 403) {
await auth.refresh();
// Retry with new token
return fetch('/api/data', {
headers: { 'Authorization': `Bearer ${auth.getAccessToken()}` }
});
}
```
## Interfaces
### BkperAuthConfig
Configuration options for the BkperAuth class.
**Properties:**
- `baseUrl?`: `string` — Override the authentication service base URL.
- `getAdditionalAuthParams?`: `() => Record` — Provide additional parameters to send to the authentication service.
- `onError?`: `(error: unknown) => void` — Called when an error occurs during authentication.
- `onLoginRequired?`: `() => void` — Called when login is required (user needs to sign in).
- `onLoginSuccess?`: `() => void` — Called when login succeeds (user is authenticated).
- `onLogout?`: `() => void` — Called when the user logs out.
- `onTokenRefresh?`: `(token: string) => void` — Called when the access token is refreshed.
**baseUrl**
Most users don't need this. The default production URL works out of the box.
Use cases:
- Testing: Point to a mock authentication service for integration tests
- Development: Use a local mock server
```typescript
// Testing with mock server
const auth = new BkperAuth({
baseUrl: 'http://localhost:3000/mock-auth'
});
```
**getAdditionalAuthParams**
Useful for custom authentication flows or passing additional context
to your authentication implementation.
```typescript
// Custom authentication context
const auth = new BkperAuth({
getAdditionalAuthParams: () => {
const token = new URLSearchParams(location.search).get('custom-token');
return token ? { customToken: token } : {};
}
});
```
---
source: /docs/api/rest.md
# REST API
> Full OpenAPI reference for the Bkper REST API — endpoints, parameters, and response schemas.
RESTful API for managing financial books, accounts, transactions, and balances in [Bkper](https://bkper.com).
## Base URL
```
https://api.bkper.app
```
All endpoints are under `/v5/`. For example:
- `GET https://api.bkper.app/v5/user` — Get the authenticated user
- `GET https://api.bkper.app/v5/books` — List books
- `GET https://api.bkper.app/v5/books/{bookId}` — Get a specific book
## Authentication
All requests require a [Google OAuth2](https://developers.google.com/identity/protocols/oauth2) access token with the `email` scope, sent as a Bearer token:
```
Authorization: Bearer
```
### Getting a token
The easiest way to authenticate is through the [Bkper CLI](https://www.npmjs.com/package/bkper), which manages the OAuth flow for you:
```bash
npm i -g bkper
bkper auth login # Opens browser for Google sign-in
bkper book list # You're connected
```
For programmatic access, use a client library that handles token management:
- **Node.js** — [bkper-js](https://www.npmjs.com/package/bkper-js) with the CLI's `getOAuthToken()` for local scripts, or with [@bkper/web-auth](https://www.npmjs.com/package/@bkper/web-auth) for browser apps
- **Google Apps Script** — [bkper-gs](https://www.npmjs.com/package/@bkper/bkper-gs) library, which uses Apps Script's built-in OAuth
You can also set up your own [OAuth2 client credentials](https://developers.google.com/identity/protocols/oauth2) in a Google Cloud project if you need full control over the authentication flow.
## API Key (optional)
For dedicated quota and project-level usage tracking, you can pass an API key via the `key` query parameter. API keys are for quota management only — they do not replace OAuth2 authentication.
## OpenAPI Specification
The machine-readable spec is available at [`https://bkper.com/docs/api/rest/openapi.json`](https://bkper.com/docs/api/rest/openapi.json). Use it with Swagger UI, Postman, or any OpenAPI-compatible tool.
Content-Type: `application/json`
## Endpoints
All `/v5/books/{bookId}/...` endpoints require `bookId` (path, string, required) — the book's unique identifier.
### Apps
#### `GET /v5/apps` — listApps
**Response 200:** AppList
#### `POST /v5/apps` — createApp
**Request body:** App
**Response 200:** App
#### `PUT /v5/apps` — updateApp
**Request body:** App
**Response 200:** App
#### `GET /v5/apps/{agentId}` — getApp
**Parameters:**
- `agentId` (path, string, required)
**Response 200:** App
### Books
#### `GET /v5/books` — listBooks
**Parameters:**
- `query` (query, string) — Optional search term to filter books
**Response 200:** BookList
#### `POST /v5/books` — createNewBook
**Parameters:**
- `name` (query, string)
**Request body:** Book
**Response 200:** Book
#### `PUT /v5/books` — updateBook
**Request body:** Book
**Response 200:** Book
#### `GET /v5/books/{bookId}` — getBook
Load a book
**Parameters:**
- `loadAccounts` (query, boolean) — Optionally load accounts and groups
- `loadGroups` (query, boolean) — Optionally load groups
**Response 200:** Book
#### `PUT /v5/books/{bookId}` *(deprecated)* — updateBookDeprecated
**Request body:** Book
**Response 200:** Book
#### `DELETE /v5/books/{bookId}` — deleteBook
**Response 200:** Book
#### `GET /v5/books/{bookId}/apps` — listBookApps
**Response 200:** AppList
#### `PATCH /v5/books/{bookId}/audit` — auditBook
Audit a book async
**Response 204:** A successful response
#### `POST /v5/books/{bookId}/copy` — copyBook
Copy a book with optional transaction copying
**Parameters:**
- `name` (query, string) — Name for the copied book
- `copyTransactions` (query, boolean) — Whether to copy transactions
- `fromDate` (query, integer (int32)) — Start date for copying transactions (YYYYMMDD format)
**Response 200:** Book
### Accounts
#### `GET /v5/books/{bookId}/accounts` — listAccounts
**Response 200:** AccountList
#### `POST /v5/books/{bookId}/accounts` — createAccount
**Request body:** Account
**Response 200:** Account
#### `PUT /v5/books/{bookId}/accounts` — updateAccount
**Request body:** Account
**Response 200:** Account
#### `POST /v5/books/{bookId}/accounts/batch` — createAccountsBatch
Batch create accounts
**Request body:** AccountList
**Response 200:** AccountList
#### `PUT /v5/books/{bookId}/accounts/batch` — updateAccountsBatch
Batch update accounts
**Request body:** AccountList
**Response 200:** AccountList
#### `POST /v5/books/{bookId}/accounts/delete/batch` — deleteAccountsBatch
Batch delete accounts
**Request body:** AccountList
**Response 200:** AccountList
#### `GET /v5/books/{bookId}/accounts/{id}` — getAccount
**Parameters:**
- `id` (path, string, required) — The account id or name
**Response 200:** Account
#### `DELETE /v5/books/{bookId}/accounts/{id}` — deleteAccount
**Parameters:**
- `id` (path, integer (int64), required) — The account id
**Response 200:** Account
#### `GET /v5/books/{bookId}/accounts/{id}/groups` — listAccountGroups
List the groups of an account
**Parameters:**
- `id` (path, string, required) — The account id or name
**Response 200:** GroupList
### Balances
#### `GET /v5/books/{bookId}/balances` — getBalances
**Parameters:**
- `query` (query, string, required) — The query to filter balances
**Response 200:** Balances
### Collaborators
#### `GET /v5/books/{bookId}/collaborators` — listCollaborators
List collaborators of the book
**Response 200:** CollaboratorPayloadCollection
#### `POST /v5/books/{bookId}/collaborators` — addCollaborator
Add or update a collaborator to the book
**Parameters:**
- `message` (query, string) — Optional message to send with the invitation email
**Request body:** Collaborator
**Response 200:** Collaborator
#### `DELETE /v5/books/{bookId}/collaborators/{id}` — removeCollaborator
Remove a collaborator from the book
**Parameters:**
- `id` (path, string, required) — The collaborator id or email
**Response 200:** Collaborator
### Collections
#### `GET /v5/collections` — listCollections
**Response 200:** CollectionList
#### `POST /v5/collections` — createCollection
**Request body:** Collection
**Response 200:** Collection
#### `PUT /v5/collections` — updateCollection
**Request body:** Collection
**Response 200:** Collection
#### `DELETE /v5/collections/{id}` — deleteCollection
**Parameters:**
- `id` (path, string, required)
**Response 200:** BookList
#### `PATCH /v5/collections/{id}/books/add` — addBooksToCollection
**Parameters:**
- `id` (path, string, required)
**Request body:** BookList
**Response 200:** BookList
#### `PATCH /v5/collections/{id}/books/remove` — removeBooksFromCollection
**Parameters:**
- `id` (path, string, required)
**Request body:** BookList
**Response 200:** BookList
### Events
#### `GET /v5/books/{bookId}/events` — listEvents
**Parameters:**
- `after` (query, string (date-time)) — After date and time, on RFC3339 format
- `before` (query, string (date-time)) — Before date and time, on RFC3339 format
- `error` (query, boolean) — Filter by error
- `resoureId` (query, string) — The resourceId associated
- `limit` (query, integer (int32)) — The dataset limit. Useful for pagination
**Response 200:** EventList
#### `GET /v5/books/{bookId}/events/backlog` — getBookEventsBacklog
Get book events backlog
**Response 200:** Backlog
#### `PATCH /v5/books/{bookId}/events/replay/batch` — replayEvents
Batch replay events responses
**Parameters:**
- `errorsOnly` (query, boolean) — Replay errors only
**Request body:** EventList
**Response 204:** A successful response
#### `PUT /v5/books/{bookId}/events/{id}/responses/{agentId}` — replayEventResponse
Replay an event response
**Parameters:**
- `id` (path, string, required) — The event id
- `agentId` (path, string, required) — The agent id
**Response 200:** Event
#### `DELETE /v5/books/{bookId}/events/{id}/responses/{agentId}` — deleteEventResponse
Delete an event response
**Parameters:**
- `id` (path, string, required) — The event id
- `agentId` (path, string, required) — The agent id
**Response 200:** Event
### Files
#### `POST /v5/books/{bookId}/files` — createFile
**Request body:** File
**Response 200:** File
#### `PUT /v5/books/{bookId}/files` — updateFile
**Request body:** File
**Response 200:** File
#### `GET /v5/books/{bookId}/files/{id}` — getFile
**Parameters:**
- `id` (path, string, required) — The file id
**Response 200:** File
### Groups
#### `GET /v5/books/{bookId}/groups` — listGroups
**Response 200:** GroupList
#### `POST /v5/books/{bookId}/groups` — createGroup
Group a group
**Request body:** Group
**Response 200:** Group
#### `PUT /v5/books/{bookId}/groups` — updateGroup
**Request body:** Group
**Response 200:** Group
#### `POST /v5/books/{bookId}/groups/batch` — createGroupsBatch
Batch create groups
**Request body:** GroupList
**Response 200:** GroupList
#### `GET /v5/books/{bookId}/groups/{id}` — getGroup
**Parameters:**
- `id` (path, string, required) — The group id or name
**Response 200:** Group
#### `DELETE /v5/books/{bookId}/groups/{id}` — deleteGroup
**Parameters:**
- `id` (path, integer (int64), required) — The group id
**Response 200:** Group
#### `GET /v5/books/{bookId}/groups/{id}/accounts` — listGroupAccounts
List the accounts of a group
**Parameters:**
- `id` (path, string, required) — The group id or name
**Response 200:** AccountList
### Integrations
#### `GET /v5/books/{bookId}/integrations` — listIntegrations
List the integrations of the book
**Response 200:** IntegrationList
#### `POST /v5/books/{bookId}/integrations` — createIntegration
**Request body:** Integration
**Response 200:** Integration
#### `PUT /v5/books/{bookId}/integrations` — updateIntegration
**Request body:** Integration
**Response 200:** Integration
#### `DELETE /v5/books/{bookId}/integrations/{id}` — deleteIntegration
**Parameters:**
- `id` (path, integer (int64), required)
**Response 200:** Integration
### Queries
#### `GET /v5/books/{bookId}/queries` — listQueries
**Response 200:** QueryList
#### `POST /v5/books/{bookId}/queries` — saveQuery
Create a saved query
**Request body:** Query
**Response 200:** Query
#### `PUT /v5/books/{bookId}/queries` — updateQuery
Update a saved query
**Request body:** Query
**Response 200:** Query
#### `DELETE /v5/books/{bookId}/queries/{id}` — deleteQuery
Delete a saved query
**Parameters:**
- `id` (path, integer (int64), required) — The query id
**Response 200:** Query
### Templates
#### `GET /v5/templates` — listTemplates
**Response 200:** TemplateList
### Transactions
#### `GET /v5/books/{bookId}/transactions` — listTransactions
**Parameters:**
- `query` (query, string) — The query to filter transactions
- `limit` (query, integer (int32)) — The dataset limit. Useful for pagination
**Response 200:** TransactionList
#### `POST /v5/books/{bookId}/transactions` — createTransaction
**Parameters:**
- `timeZone` (query, string) — Optional time zone for parsing dates when recording from different book time zone
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PUT /v5/books/{bookId}/transactions` — updateTransaction
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `POST /v5/books/{bookId}/transactions/batch` — createTransactionsBatch
Batch create transactions
**Parameters:**
- `timeZone` (query, string) — Optional time zone for parsing dates when recording from different book time zone
**Request body:** TransactionList
**Response 200:** TransactionList
#### `PUT /v5/books/{bookId}/transactions/batch` — updateTransactionsBatch
Batch update transactions
**Parameters:**
- `updateChecked` (query, boolean) — True to also update checked transactions
**Request body:** TransactionList
**Response 200:** TransactionList
#### `PATCH /v5/books/{bookId}/transactions/check` — checkTransaction
Check a transaction
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PATCH /v5/books/{bookId}/transactions/check/batch` — checkTransactionsBatch
Batch check transactions
**Request body:** TransactionList
**Response 204:** A successful response
#### `GET /v5/books/{bookId}/transactions/count` — countTransactions
Count transactions
**Parameters:**
- `query` (query, string) — The query to filter transactions
**Response 200:** Count
#### `GET /v5/books/{bookId}/transactions/count/posted` — countTransactionsPosted
Count transactions posted
**Parameters:**
- `after` (query, string (date), required) — After date, on yyyy-mm-dd format.
- `before` (query, string (date), required) — Before date, on yyyy-mm-dd format.
- `periodicity` (query, string — `DAILY` | `MONTHLY` | `YEARLY`, required) — Periodicity DAILY or MONTHLY
**Response 200:** Counts
#### `PATCH /v5/books/{bookId}/transactions/post` — postTransaction
Post a transaction into accounts
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PATCH /v5/books/{bookId}/transactions/post/batch` — postTransactionsBatch
Batch post transactions
**Request body:** TransactionList
**Response 204:** A successful response
#### `PATCH /v5/books/{bookId}/transactions/remove` *(deprecated)* — removeTransaction
Remove a transaction, sending to trash
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PATCH /v5/books/{bookId}/transactions/restore` *(deprecated)* — restoreTransaction
Restore a transaction from trash
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PATCH /v5/books/{bookId}/transactions/trash` — trashTransaction
Trash a transaction
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PATCH /v5/books/{bookId}/transactions/trash/batch` — trashTransactionsBatch
Batch trash transactions
**Parameters:**
- `trashChecked` (query, boolean) — True to also trash checked transactions
**Request body:** TransactionList
**Response 204:** A successful response
#### `PATCH /v5/books/{bookId}/transactions/uncheck` — uncheckTransaction
Uncheck a transaction
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PATCH /v5/books/{bookId}/transactions/uncheck/batch` — uncheckTransactionsBatch
Batch uncheck a transactions
**Request body:** TransactionList
**Response 204:** A successful response
#### `PATCH /v5/books/{bookId}/transactions/untrash` — untrashTransaction
Untrash a transaction
**Request body:** Transaction
**Response 200:** TransactionOperation
#### `PATCH /v5/books/{bookId}/transactions/untrash/batch` — untrashTransactionsBatch
Batch untrash transactions
**Request body:** TransactionList
**Response 204:** A successful response
#### `GET /v5/books/{bookId}/transactions/{id}` — getTransaction
**Parameters:**
- `id` (path, string, required) — The transaction id
**Response 200:** Transaction
### User
#### `GET /v5/user` — getUser
Retrieve the current user
**Response 200:** User
#### `GET /v5/user/billing` — getBilling
Retrieve the user billing information
**Response 200:** Billing
#### `GET /v5/user/billing/checkout` — getBillingCheckout
Retrieve the user billing checkout url for a plan
**Parameters:**
- `plan` (query, string, required)
- `cycle` (query, string)
- `successUrl` (query, string, required)
- `cancelUrl` (query, string, required)
**Response 200:** Url
#### `GET /v5/user/billing/counts` — listBillingCounts
List user billing transaction counts for last 12 months
**Response 200:** Counts
#### `GET /v5/user/billing/portal` — getBillingPortal
Retrieve the user billing portal url
**Parameters:**
- `returnUrl` (query, string, required)
**Response 200:** Url
#### `GET /v5/user/connections` — listConnections
**Response 200:** ConnectionList
#### `POST /v5/user/connections` — createConnection
**Request body:** Connection
**Response 200:** Connection
#### `PUT /v5/user/connections` — updateConnection
**Request body:** Connection
**Response 200:** Connection
#### `GET /v5/user/connections/{id}` — getConnection
Retrieve a connection by id
**Parameters:**
- `id` (path, string, required)
**Response 200:** Connection
#### `DELETE /v5/user/connections/{id}` — deleteConnection
**Parameters:**
- `id` (path, string, required)
**Response 200:** Connection
#### `GET /v5/user/connections/{id}/integrations` — listConnectionIntegrations
List integrations by connection
**Parameters:**
- `id` (path, string, required)
**Response 200:** IntegrationList
## Data Models
### Account
- `agentId`: string — The id of agent that created the resource
- `archived`: boolean — Archived accounts are kept for history
- `balance`: string — The running balance of the account at the transaction date. Only present when the account is part of a transaction response filtered by account. NOT the current account balance. To get current balances, use the Balances endpoint: GET /books/{bookId}/balances
- `balanceVerified`: boolean — Whether the account balance has been verified/audited
- `createdAt`: string — The creation timestamp, in milliseconds
- `credit`: boolean — Credit nature or Debit otherwise
- `groups`: Group[] — The groups of the account
- `hasTransactionPosted`: boolean — Whether the account has any transactions posted
- `id`: string — The unique id that identifies the Account in the Book
- `name`: string — The name of the Account
- `normalizedName`: string — The name of the Account, lowercase, without spaces or special characters
- `permanent`: boolean — Permanent are such as bank accounts, customers or the like
- `properties`: Record — The key/value custom properties of the Account
- `type`: string — `ASSET` | `LIABILITY` | `INCOMING` | `OUTGOING` — The type of the account
- `updatedAt`: string — The last update timestamp, in milliseconds
### AccountBalances
- `archived`: boolean
- `balances`: Balance[]
- `credit`: boolean
- `cumulativeBalance`: string
- `cumulativeCredit`: string
- `cumulativeDebit`: string
- `empty`: boolean
- `name`: string
- `normalizedName`: string
- `periodBalance`: string
- `periodCredit`: string
- `periodDebit`: string
- `permanent`: boolean
- `properties`: Record
### AccountList
- `items`: Account[] — List items
### Agent
- `id`: string — The agent id
- `logo`: string — The agent logo. Public url or Base64 encoded
- `logoDark`: string — The agent logo on dark mode. Public url or Base64 encoded
- `name`: string — The agent name
### App
- `apiVersion`: string — `v0` | `v1` | `v2` | `v3` | `v4` | `v5` — The API version of the event payload
- `clientId`: string — The Google OAuth Client ID
- `clientSecret`: string — The Google OAuth Client Secret
- `connectable`: boolean — Whether this app is connectable by a user
- `deprecated`: boolean — Whether the app is deprecated
- `description`: string — The App description
- `developers`: string — The developers (usernames and domain patterns), comma or space separated
- `events`: string[] — `FILE_CREATED` | `FILE_UPDATED` | `TRANSACTION_CREATED` | `TRANSACTION_UPDATED` | `TRANSACTION_DELETED` | `TRANSACTION_POSTED` | `TRANSACTION_CHECKED` | `TRANSACTION_UNCHECKED` | `TRANSACTION_RESTORED` | `ACCOUNT_CREATED` | `ACCOUNT_UPDATED` | `ACCOUNT_DELETED` | `QUERY_CREATED` | `QUERY_UPDATED` | `QUERY_DELETED` | `GROUP_CREATED` | `GROUP_UPDATED` | `GROUP_DELETED` | `COMMENT_CREATED` | `COMMENT_DELETED` | `COLLABORATOR_ADDED` | `COLLABORATOR_UPDATED` | `COLLABORATOR_REMOVED` | `INTEGRATION_CREATED` | `INTEGRATION_UPDATED` | `INTEGRATION_DELETED` | `BOOK_CREATED` | `BOOK_AUDITED` | `BOOK_UPDATED` | `BOOK_DELETED` — Event types the App listen to
- `filePatterns`: string[] — File patterns the App handles - wildcard accepted. E.g. *.pdf, *-bank.csv
- `id`: string — The unique agent id of the App - this can't be changed after created
- `installable`: boolean — Whether this app is installable in a book
- `logoUrl`: string — The App logo url
- `logoUrlDark`: string — The App logo url in dark mode
- `menuPopupHeight`: string — The menu popup window height
- `menuPopupWidth`: string — The menu popup window width
- `menuText`: string — The contex menu text - default to the App name
- `menuUrl`: string — The context menu url
- `menuUrlDev`: string — The context menu url in dev mode
- `name`: string — The App name
- `ownerEmail`: string — The owner user email
- `ownerId`: string — The owner user id
- `ownerLogoUrl`: string — The owner company logo url
- `ownerName`: string — The owner company name
- `ownerWebsite`: string — The owner company website url
- `propertiesSchema`: AppPropertiesSchema
- `published`: boolean — Whether this app is already published
- `readme`: string — The readme.md file as string
- `readmeMd`: string — The readme.md file as raw markdown string
- `repoPrivate`: boolean — Whether the code repository is private
- `repoUrl`: string — The code repository url
- `scopes`: string[] — The Google OAuth Scopes used by the app
- `users`: string — The users (usernames and domain patterns) to enable the App while not yet published
- `webhookUrl`: string — The Webhook endpoint URL to listen for book events
- `webhookUrlDev`: string — The Webhook endpoint URL to listen for book events in dev mode
- `website`: string — The App website url
### AppList
- `items`: App[]
### AppPropertiesSchema
- `account`: AppPropertySchema
- `book`: AppPropertySchema
- `group`: AppPropertySchema
- `transaction`: AppPropertySchema
### AppPropertySchema
- `keys`: string[] — The property keys schema
- `values`: string[] — The property values schema
### Backlog
- `count`: integer (int32)
### Balance
- `cumulativeBalance`: string
- `cumulativeCredit`: string
- `cumulativeDebit`: string
- `day`: integer (int32)
- `fuzzyDate`: integer (int32)
- `month`: integer (int32)
- `periodBalance`: string
- `periodCredit`: string
- `periodDebit`: string
- `year`: integer (int32)
### Balances
- `accountBalances`: AccountBalances[]
- `balancesUrl`: string
- `groupBalances`: GroupBalances[]
- `nextRange`: string
- `periodicity`: string — `DAILY` | `MONTHLY` | `YEARLY`
- `previousRange`: string
- `range`: string
- `rangeBeginLabel`: string
- `rangeEndLabel`: string
### Billing
- `adminEmail`: string — The billing admin email for the user's billing account
- `daysLeftInTrial`: integer (int32) — How many days the user has left in the trial period
- `email`: string — The user's email address
- `enabled`: boolean — True if billing is enabled for the user
- `hostedDomain`: string — The user hosted domain
- `plan`: string — The user's current plan
- `planOverdue`: boolean — True if subscription payment is overdue
- `startedTrial`: boolean — True if the user has started the trial period
- `totalTransactionsThisMonth`: integer (int64) — User-level total transactions this month
- `totalTransactionsThisYear`: integer (int64) — User-level total transactions this year
### Book
- `accounts`: Account[] — The book Accounts
- `agentId`: string — The id of agent that created the resource
- `autoPost`: boolean — Tells if the Book has auto post enabled
- `closingDate`: string — The book closing date, in ISO format yyyy-MM-dd. Transactions on or before this date are closed for the period
- `collection`: Collection
- `createdAt`: string — The creation timestamp, in milliseconds
- `datePattern`: string — The date pattern of the Book. Example: dd/MM/yyyy
- `decimalSeparator`: string — `DOT` | `COMMA` — The decimal separator of the Book
- `fractionDigits`: integer (int32) — The number of fraction digits (decimal places) of the Book. E.g. 2 for ####.##, 4 for ####.####
- `groups`: Group[] — The book account Groups
- `id`: string — The unique id that identifies the Book in the system. Found at bookId url param
- `lastUpdateMs`: string — The last update date of the Book, in milliseconds
- `lockDate`: string — The book lock date, in ISO format yyyy-MM-dd. Transactions on or before this date are locked
- `name`: string — The name of the Book
- `ownerName`: string — The Book owner username
- `pageSize`: integer (int32) — The transactions pagination page size
- `period`: string — `MONTH` | `QUARTER` | `YEAR` — The period slice for balances visualization
- `periodStartMonth`: string — `JANUARY` | `FEBRUARY` | `MARCH` | `APRIL` | `MAY` | `JUNE` | `JULY` | `AUGUST` | `SEPTEMBER` | `OCTOBER` | `NOVEMBER` | `DECEMBER` — The start month when YEAR period set
- `permission`: string — `OWNER` | `EDITOR` | `POSTER` | `RECORDER` | `VIEWER` | `NONE` — The Permission the current user has in the Book
- `properties`: Record — The key/value custom properties of the Book
- `timeZone`: string — The time zone of the Book, in IANA format. E.g. America/New_York, Europe/London
- `timeZoneOffset`: integer (int32) — The time zone offset of the Book, in minutes
- `totalTransactions`: integer (int64) — The total transactions posted
- `totalTransactionsCurrentMonth`: integer (int64) — The total transactions posted on current month
- `totalTransactionsCurrentYear`: integer (int64) — The total transactions posted on current year
- `updatedAt`: string — The last update timestamp, in milliseconds
- `visibility`: string — `PUBLIC` | `PRIVATE` — The Visibility of the Book
### BookList
- `items`: Book[] — List items
### BotResponse
- `agentId`: string
- `createdAt`: string
- `message`: string
- `type`: string — `INFO` | `WARNING` | `ERROR`
### Collaborator
- `agentId`: string — The id of agent that created the resource
- `createdAt`: string — The creation timestamp, in milliseconds
- `email`: string — The email of the Collaborator
- `id`: string — The unique id that identifies the Collaborator in the Book
- `permission`: string — `OWNER` | `EDITOR` | `POSTER` | `RECORDER` | `VIEWER` | `NONE` — The permission the Collaborator has in the Book
- `updatedAt`: string — The last update timestamp, in milliseconds
### CollaboratorPayloadCollection
An ordered list of Collaborator
- `items`: Collaborator[]
### Collection
- `agentId`: string — The id of agent that created the resource
- `books`: Book[] — The Books contained in the Collection
- `createdAt`: string — The creation timestamp, in milliseconds
- `id`: string — The unique id of the Collection
- `name`: string — The name of the Collection
- `ownerUsername`: string — The username of the Collection owner
- `permission`: string — `OWNER` | `EDITOR` | `POSTER` | `RECORDER` | `VIEWER` | `NONE` — The permission the current user has in the Collection. E.g. OWNER, EDITOR, NONE
- `updatedAt`: string — The last update timestamp, in milliseconds
### CollectionList
- `items`: Collection[] — List items
### Connection
- `agentId`: string — The id of agent that created the resource
- `createdAt`: string — The creation timestamp, in milliseconds
- `dateAddedMs`: string
- `email`: string
- `id`: string
- `logo`: string
- `name`: string
- `properties`: Record
- `type`: string — `APP` | `BANK`
- `updatedAt`: string — The last update timestamp, in milliseconds
- `userId`: string
- `uuid`: string
### ConnectionList
- `items`: Connection[] — List items
### Count
- `day`: integer (int32)
- `fuzzyDate`: integer (int32)
- `month`: integer (int32)
- `total`: integer (int64)
- `year`: integer (int32)
### Counts
- `posted`: Count[]
- `trashed`: Count[]
### Event
- `agent`: Agent
- `book`: Book
- `bookId`: string — The id of the Book associated to the Event
- `botResponses`: BotResponse[] — The list of bot responses associated to the Event
- `createdAt`: string — The creation timestamp, in milliseconds
- `createdOn`: string (date-time) — The creation date time on RFC3339 format
- `data`: EventData
- `id`: string — The unique id that identifies the Event
- `resource`: string — The resource associated to the Event
- `type`: string — `FILE_CREATED` | `FILE_UPDATED` | `TRANSACTION_CREATED` | `TRANSACTION_UPDATED` | `TRANSACTION_DELETED` | `TRANSACTION_POSTED` | `TRANSACTION_CHECKED` | `TRANSACTION_UNCHECKED` | `TRANSACTION_RESTORED` | `ACCOUNT_CREATED` | `ACCOUNT_UPDATED` | `ACCOUNT_DELETED` | `QUERY_CREATED` | `QUERY_UPDATED` | `QUERY_DELETED` | `GROUP_CREATED` | `GROUP_UPDATED` | `GROUP_DELETED` | `COMMENT_CREATED` | `COMMENT_DELETED` | `COLLABORATOR_ADDED` | `COLLABORATOR_UPDATED` | `COLLABORATOR_REMOVED` | `INTEGRATION_CREATED` | `INTEGRATION_UPDATED` | `INTEGRATION_DELETED` | `BOOK_CREATED` | `BOOK_AUDITED` | `BOOK_UPDATED` | `BOOK_DELETED` — The type of the Event
- `user`: User
### EventData
- `object`: object
- `previousAttributes`: Record — The object previous attributes when updated
### EventList
- `cursor`: string — The cursor, for pagination
- `items`: Event[] — List items
### File
- `agentId`: string — The id of agent that created the resource
- `content`: string — The file content Base64 encoded
- `contentType`: string — The file content type
- `createdAt`: string — The creation timestamp, in milliseconds
- `id`: string — The unique id that identifies the file in the book
- `name`: string — The file name
- `properties`: Record — The key/value custom properties of the File
- `size`: integer (int64) — The file size in bytes
- `updatedAt`: string — The last update timestamp, in milliseconds
- `url`: string — The file serving url
### Group
- `agentId`: string — The id of agent that created the resource
- `createdAt`: string — The creation timestamp, in milliseconds
- `credit`: boolean — Whether the group has credit nature
- `hasAccounts`: boolean — Whether the group has any accounts
- `hasGroups`: boolean — Whether the group has any children groups
- `hidden`: boolean — Whether the group is hidden on the transactions main menu
- `id`: string — The unique id that identifies the Group in the Book
- `locked`: boolean — Whether the group is locked by the Book owner
- `mixed`: boolean — Whether the group has mixed types of accounts
- `name`: string — The name of the Group
- `normalizedName`: string — The name of the Group, lowercase, without spaces or special characters
- `parent`: Group
- `permanent`: boolean — Whether the group is permanent
- `properties`: Record — The key/value custom properties of the Group
- `type`: string — `ASSET` | `LIABILITY` | `INCOMING` | `OUTGOING` — The type of the accounts in the group. E.g. ASSET, LIABILITY, INCOMING, OUTGOING
- `updatedAt`: string — The last update timestamp, in milliseconds
### GroupBalances
- `accountBalances`: AccountBalances[]
- `balances`: Balance[]
- `credit`: boolean
- `cumulativeBalance`: string
- `cumulativeCredit`: string
- `cumulativeDebit`: string
- `groupBalances`: GroupBalances[]
- `name`: string
- `normalizedName`: string
- `periodBalance`: string
- `periodCredit`: string
- `periodDebit`: string
- `permanent`: boolean
- `properties`: Record
### GroupList
- `items`: Group[] — List items
### Integration
- `addedBy`: string
- `agentId`: string — The id of agent that created the resource
- `bookId`: string
- `connectionId`: string
- `createdAt`: string — The creation timestamp, in milliseconds
- `dateAddedMs`: string
- `id`: string
- `lastUpdateMs`: string
- `logo`: string
- `logoDark`: string
- `name`: string
- `normalizedName`: string
- `properties`: Record
- `updatedAt`: string — The last update timestamp, in milliseconds
- `userId`: string
### IntegrationList
- `items`: Integration[] — List items
### Query
- `agentId`: string — The id of agent that created the resource
- `createdAt`: string — The creation timestamp, in milliseconds
- `id`: string — The unique id that identifies the saved Query in the Book
- `query`: string — The Query string to be executed
- `title`: string — The title of the saved Query
- `updatedAt`: string — The last update timestamp, in milliseconds
### QueryList
- `items`: Query[] — List items
### Template
- `bookId`: string
- `bookLink`: string
- `category`: string
- `description`: string
- `imageUrl`: string
- `name`: string
- `sheetsLink`: string
- `timesUsed`: integer (int32)
### TemplateList
- `items`: Template[] — List items
### Transaction
- `agentId`: string — The id of agent that created the resource
- `agentLogo`: string — The logo of the agent that created the transaction
- `agentLogoDark`: string — The logo in dark mode, of the agent that created the transaction
- `agentName`: string — The name of the agent that created the transaction
- `amount`: string — The amount on format ####.##
- `checked`: boolean — Whether the transaction is checked
- `createdAt`: string — The creation timestamp, in milliseconds
- `createdBy`: string — The actor username that created the transaction
- `creditAccount`: Account
- `date`: string — The date on ISO format yyyy-MM-dd
- `dateFormatted`: string — The date on format of the Book
- `dateValue`: integer (int32) — The date number representation on format YYYYMMDD
- `debitAccount`: Account
- `description`: string — The transaction description
- `draft`: boolean — Whether the transaction is a draft
- `files`: File[] — The files attached to the transaction
- `id`: string — The unique id that identifies the transaction in the book
- `posted`: boolean — Whether the transaction is already posted on accounts, otherwise is a draft
- `properties`: Record — The key/value custom properties of the Transaction
- `remoteIds`: string[] — The transaction remote ids, to avoid duplication
- `tags`: string[] — The transaction #hashtags
- `trashed`: boolean — Whether the transaction is trashed
- `updatedAt`: string — The last update timestamp, in milliseconds
- `urls`: string[] — The transaction urls
### TransactionList
- `account`: string — The account id when filtering by a single account. E.g. account='Bank'
- `cursor`: string — The cursor, for pagination
- `items`: Transaction[] — List items
### TransactionOperation
- `accounts`: Account[] — The affected accounts
- `transaction`: Transaction
### Url
- `url`: string
### User
- `avatarUrl`: string — The user public avatar url
- `bankConnections`: boolean — True if user already had any bank connection
- `billingAdminEmail`: string — The billing admin email for this user's billing account
- `billingEnabled`: boolean — True if billing is enabled for the user
- `daysLeftInTrial`: integer (int32) — How many days left in trial
- `email`: string — The user email
- `free`: boolean — True if user is in the free plan
- `fullName`: string — The user full name
- `givenName`: string — The user given name
- `hash`: string — The user hash
- `hostedDomain`: string — The user hosted domain
- `id`: string — The user unique id
- `name`: string — The user display name
- `plan`: string — The user plan
- `planOverdue`: boolean — True if subscription payment is overdue
- `startedTrial`: boolean — True if user started trial
- `totalTransactionsThisMonth`: integer (int64) — User-level total transactions this month
- `totalTransactionsThisYear`: integer (int64) — User-level total transactions this year
- `username`: string — The Bkper username of the user
## Apps
Complete Markdown dump for all apps that provide Markdown READMEs.
## Bkper Agent
Source: https://bkper.com/apps/bookbot.md
**Extract and categorize transactions instantly with AI.** Upload invoices, receipts, or bank statements and the agent automatically extracts amounts, dates, descriptions, and intelligently finds the right accounts in your book.
```mermaid
sequenceDiagram
participant Book as 📚 Bkper Book
participant Agent as ✨ Bkper Agent
participant LLM as 🧠 LLM
Book->>Agent: Transactions and Files
Agent->>Book: Get Context & Samples
Agent->>LLM: Document + Context
LLM->>Agent: Extracted Data
Agent->>Agent: Discover Accounts
Agent->>Book: Create/Update Transaction
```
## Features
- **Smart Learning**: Learns from existing transactions in your book to match your bookkeeping patterns
- **Import**: Upload files to an book → creates new transactions
- **Attach**: Attach files to existing transactions → updates them with extracted data
- **Context-Aware**: Uses account properties to guide parsing for specific document types
Advanced Configuration
The Agent should be working out of the box for most cases, but you can customize its behavior.
### Book Properties
- `agent_prompt_book_id`: ID of a remote book to fetch contexts from (for centralized configuration)
### Account/Group Properties
- `agent_prompt`: Instructions for extracting data from documents when parsing
- `agent_prompt_id`: ID to match context from remote book - defaults to account/group name
### Example Setup
1. Create the "Bank Itau" account that represents your checking account.
2. Add `agent_prompt` property to the account with the value:
```md
Extract Transactions in Date Sequence table from the document.
- Do not include headers
- quantity and price are optional properties and should be added to properties only include if the column Quantity and Price filled, leave it null otherwise.
```
3. Upload bank statements with this account selected → transactions are created automatically
## Development & Deployment
### Local Development
For local development, you can bypass Cloudflare AI Gateway by setting the `bypassAIGateway` environment variable:
```bash
# .env file
bypassAIGateway=true
GEMINI_API_KEY=your_gemini_api_key
```
This connects directly to the Gemini API without caching or analytics.
### Production Deployment
**⚠️ Important**: When deploying to production, ensure the following environment variables are configured as Cloudflare Worker secrets:
- `GEMINI_API_KEY` - Your Google Gemini API key
- `CF_ACCOUNT_ID` - Your Cloudflare account ID
- `CF_AI_GATEWAY_TOKEN` - Cloudflare AI Gateway token
- **Do NOT set** `bypassAIGateway` (or set it to `"false"`)
Production deployments should use Cloudflare AI Gateway for:
- Request caching (cost reduction)
- Rate limiting and usage control
- Analytics and monitoring
- Centralized logging
Configure secrets using:
```bash
wrangler secret put GEMINI_API_KEY
wrangler secret put CF_ACCOUNT_ID
wrangler secret put CF_AI_GATEWAY_TOKEN
```
See [Cloudflare AI Gateway docs](https://developers.cloudflare.com/ai-gateway/) for setup instructions.
## Bkper CLI
Source: https://bkper.com/apps/bkper-cli.md
[bkper.yaml reference]: #bkperyaml-reference
[Developer Docs]: https://bkper.com/docs
[App Template]: https://github.com/bkper/bkper-app-template
[Pi]: https://pi.dev/
A unified **interface for [Bkper](https://bkper.com)**. Use `bkper` in two complementary modes:
- **Interactive mode** — run `bkper` with no arguments to open the agent TUI
- **Command mode** — run `bkper ` for explicit CLI workflows, scripts, and automation
With one tool, you can build and deploy Bkper apps, and manage financial data -- books, accounts, transactions, and balances.
[](https://www.npmjs.com/package/bkper)
## Quick Start
### Prerequisites
- [Node.js](https://nodejs.org/) >= 18
### Install (choose one)
```bash tab="bun"
bun add -g bkper
```
```bash tab="npm"
npm i -g bkper
```
```bash tab="pnpm"
pnpm add -g bkper
```
```bash tab="yarn"
yarn global add bkper
```
### Authenticate
```bash
bkper auth login
```
### Start using bkper
```bash
# Interactive mode (agent TUI)
bkper
```
```bash
# Command mode (explicit command)
bkper book list
```
Pick a book and create your first transaction:
```bash
bkper transaction create -b --description "Office supplies 123.78"
```
> Run `bkper --help` or `bkper --help` for built-in documentation on any command.
>
> To build and deploy Bkper Apps, see [App Management](#app-management).
### Access Token
Use the access token for direct API calls from any tool:
```bash
# Print the current access token
TOKEN=$(bkper auth token)
# Use it with curl, httpie, or any HTTP client
curl -s -H "Authorization: Bearer $TOKEN" \
https://api.bkper.app/v5/books | jq '.items[].name'
```
## Interactive Mode (powered by Pi)
When you run `bkper` with no arguments in an interactive terminal, bkper starts the embedded agent TUI.
Bkper's agent mode is intentionally a **thin wrapper** around [Pi][Pi]:
- Pi provides the core agent runtime and TUI
- bkper adds Bkper-specific domain context and startup maintenance behavior
### Startup maintenance (non-blocking)
On each agent startup, bkper performs a background CLI auto-update check (same behavior as command mode).
### Pi passthrough
Use Pi CLI features directly through bkper:
```bash
bkper agent --
```
Examples:
```bash
bkper agent -- -p "Summarize this repository"
bkper agent -- --model openai/gpt-4o -c
bkper agent -- install
```
`bkper agent` keeps Bkper defaults (including Bkper system prompt) unless you explicitly pass `--system-prompt`.
For all available passthrough flags and commands, see the Pi CLI reference:
https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent#cli-reference
Pi-specific extensions are loaded from Pi extension folders (for example `.pi/extensions` and `~/.pi/agent/extensions`).
---
## Data Management
**Interact with books, accounts, transactions, and balances.**
All data commands that operate within a book use `-b, --book ` to specify the book context.
### Books
Create and manage financial books with locale-specific settings.
```bash
# List all books
bkper book list
# Get book details
bkper book get abc123
# Create a book with Brazilian settings
bkper book create --name "My Company" --fraction-digits 2 \
--date-pattern "dd/MM/yyyy" --decimal-separator COMMA \
--time-zone "America/Sao_Paulo"
# Create a book with custom properties
bkper book create --name "Project X" -p "code=PX001" -p "department=Engineering"
# Update a book
bkper book update abc123 --lock-date 2024-12-31
```
Command reference
- `book list` - List all books
- `-q, --query ` - Search query
- `book get ` - Get a book's details
- `book create` - Create a new book
- `--name ` - Book name (required)
- `--fraction-digits ` - Number of decimal places (`0`-`8`)
- `--date-pattern ` - Date format pattern (`dd/MM/yyyy`, `MM/dd/yyyy`, or `yyyy/MM/dd`)
- `--decimal-separator ` - Decimal separator (`DOT` or `COMMA`)
- `--time-zone ` - IANA time zone (e.g. `America/New_York`, `UTC`)
- `--period ` - Period (`MONTH`, `QUARTER`, or `YEAR`)
- `-p, --property ` - Set a property (repeatable)
- `book update ` - Update a book
- `--name ` - Book name
- `--fraction-digits ` - Number of decimal places (`0`-`8`)
- `--date-pattern ` - Date format pattern (`dd/MM/yyyy`, `MM/dd/yyyy`, or `yyyy/MM/dd`)
- `--decimal-separator ` - Decimal separator (`DOT` or `COMMA`)
- `--time-zone ` - IANA time zone identifier (e.g. `America/New_York`, `Europe/London`, `UTC`)
- `--lock-date ` - Lock date in ISO format (`yyyy-MM-dd`, e.g. `2024-01-31`)
- `--closing-date ` - Closing date in ISO format (`yyyy-MM-dd`)
- `--period ` - Period (`MONTH`, `QUARTER`, or `YEAR`)
- `-p, --property ` - Set a property (repeatable, e.g. `-p code=1010 -p branch=NYC`; empty value deletes the property)
### Accounts
Manage your chart of accounts within a book.
```bash
# List all accounts
bkper account list -b abc123
# Get an account by name
bkper account get "Bank Account" -b abc123
# Create an asset account
bkper account create -b abc123 --name "Bank Account" --type ASSET --groups "Current Assets"
# Update an account
bkper account update "Bank Account" -b abc123 --type LIABILITY
# Archive an account
bkper account update "Old Account" -b abc123 --archived true
# Delete an account
bkper account delete "Old Account" -b abc123
```
Command reference
- `account list -b ` - List accounts in a book
- `account get -b ` - Get an account
- `account create -b ` - Create a new account
- `--name ` - Account name (required)
- `--type ` - Account type (`ASSET`, `LIABILITY`, `INCOMING`, `OUTGOING`)
- `--description ` - Account description
- `--groups ` - Comma-separated group names
- `-p, --property ` - Set a property (repeatable)
- `account update -b ` - Update an account
- `--name ` - Account name
- `--type ` - Account type (`ASSET`, `LIABILITY`, `INCOMING`, `OUTGOING`)
- `--archived ` - Archive status
- `-p, --property ` - Set a property (repeatable, merges with existing)
- `account delete -b ` - Delete an account
### Groups
Organize accounts into hierarchical groups for structured reporting.
```bash
# List all groups (shows hierarchy)
bkper group list -b abc123
# Create a group
bkper group create -b abc123 --name "Current Assets"
# Create a child group
bkper group create -b abc123 --name "Cash" --parent "Current Assets"
# Update a group
bkper group update "Cash" -b abc123 --hidden true
# Delete a group
bkper group delete "Cash" -b abc123
```
Command reference
- `group list -b ` - List groups in a book
- `group get -b ` - Get a group
- `group create -b ` - Create a new group
- `--name ` - Group name (required)
- `--parent ` - Parent group name or ID
- `--hidden` - Hide the group
- `-p, --property ` - Set a property (repeatable)
- `group update -b ` - Update a group
- `--name ` - Group name
- `--hidden ` - Hide status
- `-p, --property ` - Set a property (repeatable, merges with existing)
- `group delete -b ` - Delete a group
### Transactions
Record, query, and manage financial transactions.
```bash
# Create a draft transaction
bkper transaction create -b abc123 --description "Office supplies"
# Create a complete transaction
bkper transaction create -b abc123 --date 2025-01-15 --amount 100.50 \
--from "Bank Account" --to "Office Supplies" --description "Printer paper"
# List transactions for a full year (on:YYYY)
bkper transaction list -b abc123 -q "on:2025"
# List transactions for a month (on:YYYY-MM)
bkper transaction list -b abc123 -q "on:2025-01"
# List with custom properties included
bkper transaction list -b abc123 -q "account:Sales" -p
# Update a transaction
bkper transaction update tx_456 -b abc123 --amount 120.00 --description "Printer paper (corrected)"
# Post a draft transaction
bkper transaction post tx_456 -b abc123
# Check (reconcile) a transaction
bkper transaction check tx_456 -b abc123
# Trash a transaction
bkper transaction trash tx_456 -b abc123
# Merge two duplicate transactions
bkper transaction merge tx_123 tx_456 -b abc123
```
Command reference
- `transaction list -b -q ` - List transactions matching a query (auto-paginates through all results)
- `-p, --properties` - Include custom properties in the output
- `transaction create -b ` - Create a transaction
- `--date ` - Transaction date
- `--amount ` - Transaction amount
- `--description ` - Transaction description
- `--from ` - Credit account (source)
- `--to ` - Debit account (destination)
- `--url ` - URL (repeatable)
- `--remote-id ` - Remote ID (repeatable)
- `-p, --property ` - Set a property (repeatable, empty value deletes)
- `transaction update [transactionId] -b ` - Update a transaction (or batch update via stdin)
- `--date ` - Transaction date
- `--amount ` - Transaction amount
- `--description ` - Transaction description
- `--from ` - Credit account (source)
- `--to ` - Debit account (destination)
- `--url ` - URL (repeatable, replaces all)
- `--update-checked` - Also update checked transactions
- `-p, --property ` - Set a property (repeatable, empty value deletes)
- `transaction post -b ` - Post a draft transaction
- `transaction check -b ` - Check a transaction
- `transaction trash -b ` - Trash a transaction
- `transaction merge -b ` - Merge two transactions
### Balances
Query account balances and group totals.
```bash
# List balances for a specific date (point-in-time)
bkper balance list -b abc123 -q "on:2025-12-31"
# Monthly balance evolution of one account during 2025
bkper balance list -b abc123 -q "account:'' after:2025-01-01 before:2026-01-01 by:m" --expanded 2
```
Command reference
- `balance list -b -q ` - List balances
- `--expanded ` - Expand groups to specified depth (`0`+)
### Query semantics (transactions and balances)
Use the same query language across Bkper web app, CLI, and Google Sheets integrations.
- `on:` supports different granularities:
- `on:2025` → full year
- `on:2025-01` → full month
- `on:2025-01-31` → specific day
- `after:` is **inclusive** and `before:` is **exclusive**.
- Full year 2025: `after:2025-01-01 before:2026-01-01`
- For point-in-time statements (typically permanent accounts `ASSET`/`LIABILITY`), prefer `on:` or `before:`.
- For activity statements over a period (typically non-permanent accounts `INCOMING`/`OUTGOING`), prefer `after:` + `before:`.
- For statement-level analysis, prefer filtering by the report root group. Root names vary by book.
```bash
# Balance Sheet snapshot (point-in-time)
bkper balance list -b abc123 -q "group:'' before:2026-01-01"
# P&L activity over 2025
bkper balance list -b abc123 -q "group:'' after:2025-01-01 before:2026-01-01"
```
### Collections
Organize books into collections.
```bash
# Create a collection
bkper collection create --name "My Collection"
# Add books to a collection
bkper collection add-book col_789 -b abc123 -b def456
# List all collections
bkper collection list
# Remove a book from a collection
bkper collection remove-book col_789 -b abc123
# Delete a collection
bkper collection delete col_789
```
Command reference
- `collection list` - List all collections
- `collection get ` - Get a collection
- `collection create` - Create a new collection
- `--name ` - Collection name (required)
- `collection update ` - Update a collection
- `--name ` - Collection name
- `collection delete ` - Delete a collection
- `collection add-book ` - Add books to a collection
- `-b, --book ` - Book ID (repeatable)
- `collection remove-book ` - Remove books from a collection
- `-b, --book ` - Book ID (repeatable)
### Output Format
All commands support three output formats via the `--format` global flag:
| Format | Flag | Best for |
| ------ | -------------------------- | ------------------------------------------- |
| Table | `--format table` (default) | Human reading in the terminal |
| JSON | `--format json` | Programmatic access, single-item detail |
| CSV | `--format csv` | LLM consumption, spreadsheets, list reports |
```bash
# Table output (default)
bkper account list -b abc123
# JSON output
bkper account list -b abc123 --format json
# CSV output -- raw data, no truncation, RFC 4180
bkper account list -b abc123 --format csv
```
**CSV output details:**
- **RFC 4180 compliant** -- proper quoting, CRLF line endings, no truncation
- **All metadata included** -- IDs, properties, hidden properties, URLs, and timestamps are enabled
- **Raw values** -- dates stay in ISO format, numbers are unformatted (no locale formatting)
- **Single-item commands** (e.g. `account get`, `transaction create`) fall back to JSON since CSV adds no value for non-tabular data
**LLM-first output guidance (important):**
When command output will be loaded into an LLM context (chat, prompt, memory, or agent reasoning), prefer:
- **`--format csv` for list commands** (`balance list`, `transaction list`, `account list`, etc.).
- **`--format json` for single-item commands** (`get`, `create`, `update`) and CLI-to-CLI pipelines.
CSV is significantly more token-efficient than JSON for tabular data, and for wide balance outputs it can reduce token usage by up to **95%**.
**Quick rule:**
- **LLM consumption of lists/reports** → CSV
- **Programmatic processing / pipelines** → JSON
- **Human terminal reading** → Table
### Batch Operations & Piping
Write commands (`account create`, `group create`, `transaction create`) accept JSON data piped via stdin for batch operations. The `transaction update` command also accepts stdin for batch updates. The input format follows the [Bkper API Types](https://raw.githubusercontent.com/bkper/bkper-api-types/refs/heads/master/index.d.ts) exactly -- a single JSON object or an array of objects.
```bash
# Create transactions
echo '[{
"date": "2025-01-15",
"amount": "100.50",
"creditAccount": {"name": "Bank Account"},
"debitAccount": {"name": "Office Supplies"},
"description": "Printer paper",
"properties": {"invoice": "INV-001"}
}]' | bkper transaction create -b abc123
# Create accounts
echo '[{"name":"Cash","type":"ASSET"},{"name":"Revenue","type":"INCOMING"}]' | \
bkper account create -b abc123
# Create groups
echo '[{"name":"Fixed Costs","hidden":true}]' | \
bkper group create -b abc123
# Pipe from a script
python export_bank.py | bkper transaction create -b abc123
```
The input follows the exact `bkper.Transaction`, `bkper.Account`, or `bkper.Group` type from the [Bkper API Types](https://raw.githubusercontent.com/bkper/bkper-api-types/refs/heads/master/index.d.ts). Custom properties go inside the `properties` object.
The `--property` CLI flag can override or delete properties from the stdin payload:
```bash
echo '[{"name":"Cash","type":"ASSET"}]' | \
bkper account create -b abc123 -p "region=LATAM"
```
**Batch output:** results are output as a flat JSON array, matching the same format as list commands:
```bash
bkper account create -b abc123 < accounts.json
# Output: [{"id":"acc-abc","name":"Cash",...}, {"id":"acc-def","name":"Revenue",...}]
```
**Piping between commands:**
All JSON output is designed to be piped directly as stdin to other commands. The output of any list or batch create command can feed directly into a create or update command:
```bash
# Copy all accounts from one book to another
bkper account list -b $BOOK_A --format json | bkper account create -b $BOOK_B
# Copy all groups from one book to another
bkper group list -b $BOOK_A --format json | bkper group create -b $BOOK_B
# Copy transactions matching a query
bkper transaction list -b $BOOK_A -q "after:2025-01-01" --format json | \
bkper transaction create -b $BOOK_B
# Clone a full chart of accounts: groups, then accounts, then transactions
bkper group list -b $SOURCE --format json | bkper group create -b $DEST
bkper account list -b $SOURCE --format json | bkper account create -b $DEST
bkper transaction list -b $SOURCE -q "after:2025-01-01" --format json | \
bkper transaction create -b $DEST
# Batch update: list transactions, modify, and pipe back to update
bkper transaction list -b $BOOK -q "after:2025-01-01" --format json | \
jq '[.[] | .description = "Updated: " + .description]' | \
bkper transaction update -b $BOOK
# Batch update: add a property to all matching transactions
bkper transaction list -b $BOOK -q "account:Expenses" --format json | \
bkper transaction update -b $BOOK -p "reviewed=true"
# Batch update checked transactions
bkper transaction list -b $BOOK -q "is:checked after:2025-01-01" --format json | \
bkper transaction update -b $BOOK --update-checked -p "migrated=true"
```
Writable fields reference
Only the fields below are meaningful when creating or updating resources via stdin. For batch updates, items must include an `id` field. Other read-only fields (`createdAt`, `updatedAt`, etc.) are ignored.
**Transaction** (`bkper.Transaction`)
| Field | Type | Notes |
| --------------- | ---------------------------------- | --------------------------------------------- |
| `id` | `string` | Required for batch updates, ignored on create |
| `date` | `string` | ISO format `yyyy-MM-dd` |
| `amount` | `string` | Decimal format `####.##` (string, not number) |
| `creditAccount` | `{"name":"..."}` or `{"id":"..."}` | Reference to an existing account |
| `debitAccount` | `{"name":"..."}` or `{"id":"..."}` | Reference to an existing account |
| `description` | `string` | Free-text description |
| `urls` | `string[]` | Attached URLs (e.g. receipts) |
| `remoteIds` | `string[]` | External IDs to prevent duplicates |
| `properties` | `{"key": "value", ...}` | Custom key/value properties |
**Account** (`bkper.Account`)
| Field | Type | Notes |
| ------------ | ----------------------- | -------------------------------------------------- |
| `name` | `string` | Account name (required) |
| `type` | `string` | `ASSET`, `LIABILITY`, `INCOMING`, or `OUTGOING` |
| `credit` | `boolean` | Credit nature (`true`) or debit (`false`) |
| `archived` | `boolean` | Archive the account on creation |
| `permanent` | `boolean` | Permanent accounts (e.g. bank accounts, customers) |
| `groups` | `[{"name":"..."}, ...]` | Groups to assign by name or id |
| `properties` | `{"key": "value", ...}` | Custom key/value properties |
**Group** (`bkper.Group`)
| Field | Type | Notes |
| ------------ | ---------------------------------- | -------------------------------- |
| `name` | `string` | Group name (required) |
| `hidden` | `boolean` | Hide from transactions main menu |
| `parent` | `{"name":"..."}` or `{"id":"..."}` | Parent group for nesting |
| `properties` | `{"key": "value", ...}` | Custom key/value properties |
---
## App Management
**Build, deploy, and manage Bkper apps.**
### Development Workflow
```bash
# Scaffold a new app from the template
bkper app init my-app
# Start the worker runtime (Miniflare + tunnel + file watching)
# In your project, use "npm run dev" to run both Vite and workers concurrently
bkper app dev
# Build worker bundles (web server + events handler)
# In your project, use "npm run build" to build both client (Vite) and workers
bkper app build
# Sync configuration and deploy to production
bkper app sync && bkper app deploy
# Deploy to development environment
bkper app deploy --preview
# Deploy only the events handler
bkper app deploy --events
# Check deployment status
bkper app status
```
> **Note:** `bkper app dev` runs the worker runtime only — Miniflare, file watching, and the Cloudflare tunnel. The Vite client dev server is configured in the project's `vite.config.ts` and run separately. The project template composes both via `npm run dev` using `concurrently`.
### Install Apps on Books
```bash
# Install an app on a book
bkper app install my-app -b abc123
# Uninstall an app from a book
bkper app uninstall my-app -b abc123
```
### Secrets
```bash
# Store a secret (prompts for value)
bkper app secrets put API_KEY
# List all secrets
bkper app secrets list
# Delete a secret
bkper app secrets delete API_KEY
```
### Configuration
Apps are configured via a `bkper.yaml` file in the project root. See the complete **[bkper.yaml reference]** below.
bkper.yaml reference
```yaml
# =============================================================================
# bkper.yaml Reference
# =============================================================================
# This file documents all available configuration options for Bkper Apps.
# Copy the fields you need to your app's bkper.yaml file.
#
# For a minimal working template, see:
# https://github.com/bkper/bkper-app-template
# =============================================================================
# -----------------------------------------------------------------------------
# APP IDENTITY
# -----------------------------------------------------------------------------
# The app id is permanent and cannot be changed after creation.
# Use lowercase letters, numbers, and hyphens only.
id: my-app
# Display name shown in the Bkper UI
name: My App
# Brief description of what the app does
description: A Bkper app that does something useful
# -----------------------------------------------------------------------------
# BRANDING
# -----------------------------------------------------------------------------
# App logo for light mode (SVG recommended, PNG/JPG supported)
logoUrl: https://example.com/logo.svg
# App logo for dark mode (required for proper theming)
logoUrlDark: https://example.com/logo-dark.svg
# App website or documentation URL
website: https://example.com
# -----------------------------------------------------------------------------
# OWNERSHIP
# -----------------------------------------------------------------------------
# Developer/company name
ownerName: Your Name
# Owner's logo/avatar URL
ownerLogoUrl: https://example.com/owner-logo.png
# Owner's website
ownerWebsite: https://yoursite.com
# Source code repository URL
repoUrl: https://github.com/you/my-app
# Whether the repository is private
repoPrivate: true
# Mark as deprecated (hides from app listings, existing installs continue working)
deprecated: false
# -----------------------------------------------------------------------------
# ACCESS CONTROL
# -----------------------------------------------------------------------------
# Who can update the app configuration and deploy new versions.
# Comma-separated list of Bkper usernames (not emails).
# Supports domain wildcards for registered custom domains: *@yourdomain.com
developers: victor, aldo, *@bkper.com
# Who can install and use the app.
# Same format as developers. Leave empty for public apps.
users: maria, *@acme.com
# -----------------------------------------------------------------------------
# MENU INTEGRATION (optional)
# -----------------------------------------------------------------------------
# When configured, adds a menu item to Bkper's "More" menu.
# Clicking opens a popup with the specified URL.
# Production menu URL (supports variable substitution)
menuUrl: https://${id}.bkper.app?bookId=${book.id}
# Development menu URL (used when developer runs the app)
menuUrlDev: http://localhost:8787?bookId=${book.id}
# Custom menu text (defaults to app name if not specified)
menuText: Open My App
# Popup dimensions in pixels
menuPopupWidth: 500
menuPopupHeight: 300
# -----------------------------------------------------------------------------
# Menu URL Variables
# -----------------------------------------------------------------------------
# The following variables can be used in menuUrl and menuUrlDev:
#
# ${book.id} - Current book ID
# ${book.properties.xxx} - Book property value (replace xxx with property key)
# ${account.id} - Selected account ID (in account context)
# ${account.properties.xxx} - Account property value
# ${group.id} - Selected group ID (in group context)
# ${group.properties.xxx} - Group property value
# ${transactions.ids} - Comma-separated selected transaction IDs
# ${transactions.query} - Current search query
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# EVENT HANDLING (optional)
# -----------------------------------------------------------------------------
# When configured, Bkper calls your webhook URL when subscribed events occur.
# Production webhook URL
webhookUrl: https://${id}.bkper.app/events
# Development webhook URL (auto-updated by bkper app dev)
webhookUrlDev: https://.trycloudflare.com/events
# API version for event payloads
apiVersion: v5
# Events to subscribe to (remove events you don't need)
events:
# Transaction
- TRANSACTION_CREATED
- TRANSACTION_POSTED
- TRANSACTION_CHECKED
- TRANSACTION_UNCHECKED
- TRANSACTION_UPDATED
- TRANSACTION_DELETED
- TRANSACTION_RESTORED
# Account
- ACCOUNT_CREATED
- ACCOUNT_UPDATED
- ACCOUNT_DELETED
# Group
- GROUP_CREATED
- GROUP_UPDATED
- GROUP_DELETED
# File
- FILE_CREATED
- FILE_UPDATED
# Query
- QUERY_CREATED
- QUERY_UPDATED
- QUERY_DELETED
# Comment
- COMMENT_CREATED
- COMMENT_DELETED
# Collaborator
- COLLABORATOR_ADDED
- COLLABORATOR_UPDATED
- COLLABORATOR_REMOVED
# Integration
- INTEGRATION_CREATED
- INTEGRATION_UPDATED
- INTEGRATION_DELETED
# Book
- BOOK_CREATED
- BOOK_UPDATED
- BOOK_DELETED
- BOOK_AUDITED
# -----------------------------------------------------------------------------
# FILE PATTERNS (optional)
# -----------------------------------------------------------------------------
# For file processing apps. When a file matching these patterns is uploaded,
# a FILE_CREATED event is triggered with the file content.
filePatterns:
- '*.ofx'
- '*.csv'
# -----------------------------------------------------------------------------
# PROPERTIES SCHEMA (optional)
# -----------------------------------------------------------------------------
# Defines autocomplete suggestions for custom properties in the Bkper UI.
# Helps users discover and use the correct property keys/values for your app.
propertiesSchema:
book:
keys:
- my_app_enabled
- my_app_config
values:
- 'true'
- 'false'
group:
keys:
- my_app_category
values:
- category_a
- category_b
account:
keys:
- my_app_sync_id
transaction:
keys:
- my_app_reference
# -----------------------------------------------------------------------------
# DEPLOYMENT CONFIGURATION (optional)
# -----------------------------------------------------------------------------
# For apps deployed to Bkper's Workers for Platforms infrastructure.
deployment:
# Web handler (serves UI and API)
web:
bundle: packages/web/server/dist
# assets: packages/web/client/dist # Static assets (when supported)
# Events handler (processes webhooks)
events:
bundle: packages/events/dist
# Platform services available to your app (one per type, auto-provisioned)
# See: https://developers.cloudflare.com/kv/
services:
- KV # Key-value storage
```
**Environment variables:**
- `BKPER_API_KEY` -- Optional. If not set, uses the Bkper API proxy with a managed API key. Set it for direct API access with your own quotas. Follow [these steps](https://bkper.com/docs/#rest-api-enabling) to enable.
Command reference
#### Authentication
- `auth login` - Authenticate with Bkper, storing credentials locally
- `auth logout` - Remove stored credentials
- `auth token` - Print the current OAuth access token to stdout
#### Agent Bridge (Pi passthrough)
- `agent -- ` - Run Pi CLI with Bkper defaults (system prompt/resources)
#### App Lifecycle
- `app init ` - Scaffold a new app from the template
- `app list` - List all apps you have access to
- `app sync` - Sync [bkper.yaml][bkper.yaml reference] configuration (URLs, description) to Bkper API
- `app build` - Build worker bundles for deployment
- `app deploy` - Deploy built artifacts to Cloudflare Workers for Platforms
- `-p, --preview` - Deploy to preview environment
- `--events` - Deploy events handler instead of web handler
- `app status` - Show deployment status
- `app undeploy` - Remove app from platform
- `-p, --preview` - Remove from preview environment
- `--events` - Remove events handler instead of web handler
- `--delete-data` - Permanently delete all associated data (requires confirmation)
- `--force` - Skip confirmation prompts (use with `--delete-data` for automation)
- `app dev` - Start the worker runtime for local development
- `--sp, --server-port ` - Server simulation port (default: `8787`)
- `--ep, --events-port ` - Events handler port (default: `8791`)
- `-w, --web` - Run only the web handler
- `-e, --events` - Run only the events handler
> **Note:** `sync` and `deploy` are independent operations. Use `sync` to update your app's URLs in Bkper (required for webhooks and menu integration). Use `deploy` to push code to Cloudflare. For a typical deployment workflow, run both: `bkper app sync && bkper app deploy`
#### App Installation
- `app install -b ` - Install an app on a book
- `app uninstall -b ` - Uninstall an app from a book
#### Secrets Management
- `app secrets put ` - Store a secret
- `-p, --preview` - Set in preview environment
- `app secrets list` - List all secrets
- `-p, --preview` - List from preview environment
- `app secrets delete ` - Delete a secret
- `-p, --preview` - Delete from preview environment
---
## Library
The `getOAuthToken` function returns a Promise that resolves to a valid OAuth token, for use with the [`bkper-js`](https://github.com/bkper/bkper-js) library:
```javascript
import { Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
```
## Documentation
- [Developer Docs]
- [App Template]
## Changelog
### Changelog
Source: https://bkper.com/changelog.md
See what's new in Bkper and what has changed.
## 2026
### March 2026
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Running `bkper` with no arguments now starts the embedded agent TUI for interactive terminals
- Added startup maintenance checks for agent mode
- Added `bkper agent -- ` passthrough command to run Pi CLI features with Bkper defaults
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.batchUpdateAccounts](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchupdateaccounts)
- Added [Book.batchDeleteAccounts](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchdeleteaccounts)
### February 2026
- Configuration file renamed from `bkperapp.yaml` to `bkper.yaml` for consistency with modern platform conventions
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Added `--format` flag with `table`, `json`, and `csv` output modes — replaces the `--json` flag
- CSV output follows RFC 4180 — raw values, all metadata, no truncation, ideal for spreadsheets and data pipelines
- Batch operations via stdin — pipe JSON or CSV data into create commands for bulk processing
- Added batch create for [Account](https://bkper.com/docs/api/bkper-js/classes/account/.md)s, [Group](https://bkper.com/docs/api/bkper-js/classes/group/.md)s, and [Transaction](https://bkper.com/docs/api/bkper-js/classes/transaction/.md)s — accepts JSON arrays or CSV via stdin
- Table-formatted output is now the default for all commands
- Added `-b, --book` option for scoping commands to a specific [Book](https://bkper.com/docs/api/bkper-js/classes/book/.md)
- Added `-p, --properties` repeatable flag for setting custom properties as `key=value` pairs
- [Transaction](https://bkper.com/docs/api/bkper-js/classes/transaction/.md) tables show formatted dates and values with IDs
- [Group](https://bkper.com/docs/api/bkper-js/classes/group/.md) tables render as indented trees showing hierarchy
- Single-item commands display as indented key-value pairs
- Removed MCP server — now maintained as a separate project
- Added [Book](https://bkper.com/docs/api/bkper-js/classes/book/.md) create command
- Added [Collection](https://bkper.com/docs/api/bkper-js/classes/collection/.md) commands: create, list, get, update, delete, add-book, remove-book
- Added [Transaction](https://bkper.com/docs/api/bkper-js/classes/transaction/.md) update command
- Renamed `balance get` to `balance list` for consistency
- Switched to PKCE-based OAuth flow — no client secret required
- Branded OAuth callback pages for a polished sign-in experience
- Local development now uses Cloudflare Tunnel for event handling — no cloud deployment needed during development
- Renamed `dev` environment to `preview` for clarity
- Added `--no-open` flag to suppress automatic browser launch during dev
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [User.getGivenName](https://bkper.com/docs/api/bkper-js/classes/user/.md#getgivenname)
- Added [BooksDataTableBuilder](https://bkper.com/docs/api/bkper-js/classes/booksdatatablebuilder/.md)
- Added [AccountsDataTableBuilder](https://bkper.com/docs/api/bkper-js/classes/accountsdatatablebuilder/.md)
- Added [GroupsDataTableBuilder](https://bkper.com/docs/api/bkper-js/classes/groupsdatatablebuilder/.md)
- Added [TransactionsDataTableBuilder](https://bkper.com/docs/api/bkper-js/classes/transactionsdatatablebuilder/.md)
- Added [Book.createAccountsDataTable](https://bkper.com/docs/api/bkper-js/classes/book/.md#createaccountsdatatable)
- Added [Book.createGroupsDataTable](https://bkper.com/docs/api/bkper-js/classes/book/.md#creategroupsdatatable)
- Added [Book.createTransactionsDataTable](https://bkper.com/docs/api/bkper-js/classes/book/.md#createtransactionsdatatable)
- Added [TransactionsDataTableBuilder.ids](https://bkper.com/docs/api/bkper-js/classes/transactionsdatatablebuilder/.md#ids)
- Added [TransactionsDataTableBuilder.properties](https://bkper.com/docs/api/bkper-js/classes/transactionsdatatablebuilder/.md#properties)
- Added [TransactionsDataTableBuilder.urls](https://bkper.com/docs/api/bkper-js/classes/transactionsdatatablebuilder/.md#urls)
- Added [TransactionsDataTableBuilder.recordedAt](https://bkper.com/docs/api/bkper-js/classes/transactionsdatatablebuilder/.md#recordedat)
- Added [AccountsDataTableBuilder.hiddenProperties](https://bkper.com/docs/api/bkper-js/classes/accountsdatatablebuilder/.md#hiddenproperties)
- Added [BooksDataTableBuilder.hiddenProperties](https://bkper.com/docs/api/bkper-js/classes/booksdatatablebuilder/.md#hiddenproperties)
- Added [GroupsDataTableBuilder.hiddenProperties](https://bkper.com/docs/api/bkper-js/classes/groupsdatatablebuilder/.md#hiddenproperties)
- Added [GroupsDataTableBuilder.tree](https://bkper.com/docs/api/bkper-js/classes/groupsdatatablebuilder/.md#tree)
- Added [TransactionsDataTableBuilder.hiddenProperties](https://bkper.com/docs/api/bkper-js/classes/transactionsdatatablebuilder/.md#hiddenproperties)
- Added [BalancesDataTableBuilder.hiddenProperties](https://bkper.com/docs/api/bkper-js/classes/balancesdatatablebuilder/.md#hiddenproperties)
### January 2026
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Added `app init` command to scaffold new apps from template
- Added `app deploy` and `app undeploy` commands for managing deployments
- Added `app status` to view current deployment information
- Added `app dev` and `app build` commands for local development and build workflows
- Added `app secrets` management — put, list, and delete secrets for apps
- Added `app sync` command to push `bkper.yaml` configuration to the platform
- Support for shared packages in monorepo setups with hot reload
- Asset file uploads included in deployments
- Migrated app configuration from `bkperapp.yaml` to `bkper.yaml`
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added billing footer with transaction counter and plan-related indicators
- Added usage chart to billing footer showing transaction counts for the last 12 months (Bkper Professional plans only)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [App.setUsers](https://bkper.com/docs/api/bkper-js/classes/app/.md#setusers)
- Added [App.getUsers](https://bkper.com/docs/api/bkper-js/classes/app/.md#getusers)
- Added [App.setDevelopers](https://bkper.com/docs/api/bkper-js/classes/app/.md#setdevelopers)
- Added [App.getDevelopers](https://bkper.com/docs/api/bkper-js/classes/app/.md#getdevelopers)
- Added [Config.agentIdProvider](https://bkper.com/docs/api/bkper-js/interfaces/config/.md#agentidprovider)
- Added [Billing](https://bkper.com/docs/api/bkper-js/classes/billing/.md)
- Added [Billing.getAdminEmail](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getadminemail)
- Added [Billing.getCheckoutUrl](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getcheckouturl)
- Added [Billing.getCounts](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getcounts)
- Added [Billing.getDaysLeftInTrial](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getdaysleftintrial)
- Added [Billing.getEmail](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getemail)
- Added [Billing.getHostedDomain](https://bkper.com/docs/api/bkper-js/classes/billing/.md#gethosteddomain)
- Added [Billing.getPlan](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getplan)
- Added [Billing.getPortalUrl](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getportalurl)
- Added [Billing.getTotalTransactionsThisMonth](https://bkper.com/docs/api/bkper-js/classes/billing/.md#gettotaltransactionsthismonth)
- Added [Billing.getTotalTransactionsThisYear](https://bkper.com/docs/api/bkper-js/classes/billing/.md#gettotaltransactionsthisyear)
- Added [Billing.hasStartedTrial](https://bkper.com/docs/api/bkper-js/classes/billing/.md#hasstartedtrial)
- Added [Billing.isEnabled](https://bkper.com/docs/api/bkper-js/classes/billing/.md#isenabled)
- Added [Billing.isPlanOverdue](https://bkper.com/docs/api/bkper-js/classes/billing/.md#isplanoverdue)
- Added [User.getBilling](https://bkper.com/docs/api/bkper-js/classes/user/.md#getbilling)
- Added [User.getUsername](https://bkper.com/docs/api/bkper-js/classes/user/.md#getusername)
- Removed `setUserEmails` from [App](https://bkper.com/docs/api/bkper-js/classes/app/.md). Use [App.setUsers](https://bkper.com/docs/api/bkper-js/classes/app/.md#setusers) instead
- Removed `setDeveloperEmail` from [App](https://bkper.com/docs/api/bkper-js/classes/app/.md). Use [App.setDevelopers](https://bkper.com/docs/api/bkper-js/classes/app/.md#setdevelopers) instead
- Removed `getBillingPortalUrl` from [Bkper](https://bkper.com/docs/api/bkper-js/classes/bkper/.md). Use [Billing.getPortalUrl](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getportalurl) instead
- Removed `getDaysLeftInTrial` from [User](https://bkper.com/docs/api/bkper-js/classes/user/.md). Use [Billing.getDaysLeftInTrial](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getdaysleftintrial) instead
- Removed `getPlan` from [User](https://bkper.com/docs/api/bkper-js/classes/user/.md). Use [Billing.getPlan](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getplan) instead
- Removed `hasBillingEnabled` from [User](https://bkper.com/docs/api/bkper-js/classes/user/.md). Use [Billing.isEnabled](https://bkper.com/docs/api/bkper-js/classes/billing/.md#isenabled) instead
- Removed `hasStartedTrial` from [User](https://bkper.com/docs/api/bkper-js/classes/user/.md). Use [Billing.hasStartedTrial](https://bkper.com/docs/api/bkper-js/classes/billing/.md#hasstartedtrial) instead
- Removed `isFree` from [User](https://bkper.com/docs/api/bkper-js/classes/user/.md). Use [Billing.getPlan](https://bkper.com/docs/api/bkper-js/classes/billing/.md#getplan) instead
## 2025
### December 2025
- [@bkper/web-design](https://www.npmjs.com/package/@bkper/web-design) - Published npm package for CSS design system
- [@bkper/web-auth](https://www.npmjs.com/package/@bkper/web-auth) - Published npm package for authentication SDK
### November 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Enhanced file upload experience with drag-and-drop support directly to accounts
- Improved file preview and download capabilities
- Added support for file custom properties (key/value pairs)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Bkper.getConfig](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#getconfig)
- Added [EventType.FILE\_UPDATED](https://bkper.com/docs/api/bkper-js/enumerations/eventtype/.md)
- Added [File.update](https://bkper.com/docs/api/bkper-js/classes/file/.md#update)
- Added [ResourceProperty](https://bkper.com/docs/api/bkper-js/classes/resourceproperty/.md)
- Added [ResourceProperty.getVisibleProperties](https://bkper.com/docs/api/bkper-js/classes/resourceproperty/.md#getvisibleproperties)
- Added [ResourceProperty.setVisibleProperty](https://bkper.com/docs/api/bkper-js/classes/resourceproperty/.md#setvisibleproperty)
- Added [ResourceProperty.setVisibleProperties](https://bkper.com/docs/api/bkper-js/classes/resourceproperty/.md#setvisibleproperties)
### October 2025
- NEW [Bkper Agent](https://bkper.com/apps/bookbot) rebuilt with advanced AI ✨ — now automates bank statement and invoice parsing with higher precision
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added drafts count display in transaction filters
- Added book delete option for book owners
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [File.getProperties](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#getproperties) to retrieve all custom properties from a file as key-value pairs
- Added [File.setProperties](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#setproperties) to set multiple custom properties on a file at once
- Added [File.getProperty](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#getproperty) to retrieve a specific custom property value from a file by key
- Added [File.setProperty](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#setproperty) to set a single custom property on a file with key-value pair
- Added [File.deleteProperty](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#deleteproperty) to remove a specific custom property from a file by key
- Files attached to transactions are now automatically tagged with upload method for better tracking
- [bkper-js](https://github.com/bkper/bkper-js)
- Files attached to transactions are now created internally when transaction is persisted
- Added [Transaction.removeFile](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#removefile)
- Added [Book.countTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#counttransactions)
- Added [Book.remove](https://bkper.com/docs/api/bkper-js/classes/book/.md#remove)
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Added smart transaction merging - combine multiple transactions intelligently based on date and account matching
- Simplified transaction creation - accounts are now optional, making it easier to record simple income and expenses
- Improved transaction data responses for better AI assistant integration
### September 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added book sharing settings: manage collaborators, permissions and invite people with custom email messages
- Added [balances audit status](https://help.bkper.com/en/articles/4412038-balances-audit) to chart of accounts menu
- Added resource-specific event filtering by selected transaction, account, or group
- Added integrated app launcher with collapsible sidebar for quick access to installed applications (desktop only)
- Improved property management with dedicated editor for extended descriptions and notes
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Streamlined transaction data for cleaner AI assistant responses
- Fixed credential storage to follow standard configuration directories
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Account.isBalanceVerified](https://bkper.com/docs/api/bkper-js/classes/account/.md#isbalanceverified)
- Added [App.getOwnerWebsiteUrl](https://bkper.com/docs/api/bkper-js/classes/app/.md#getownerwebsiteurl)
- Added [App.getReadme](https://bkper.com/docs/api/bkper-js/classes/app/.md#getreadme)
- Added [App.getRepositoryUrl](https://bkper.com/docs/api/bkper-js/classes/app/.md#getrepositoryurl)
- Added [App.getWebsiteUrl](https://bkper.com/docs/api/bkper-js/classes/app/.md#getwebsiteurl)
- Added [App.isInstallable](https://bkper.com/docs/api/bkper-js/classes/app/.md#isinstallable)
- Added [App.isRepositoryPrivate](https://bkper.com/docs/api/bkper-js/classes/app/.md#isrepositoryprivate)
- Added [Book.getCollaborators](https://bkper.com/docs/api/bkper-js/classes/book/.md#getcollaborators)
- Added [Book.getBacklog](https://bkper.com/docs/api/bkper-js/classes/book/.md#getbacklog)
- Added [Backlog](https://bkper.com/docs/api/bkper-js/classes/backlog/.md)
- Added [Backlog.getCount](https://bkper.com/docs/api/bkper-js/classes/backlog/.md#getcount)
- Added [Collaborator](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md)
- Added [Collaborator.json](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#json)
- Added [Collaborator.getId](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#getid)
- Added [Collaborator.getEmail](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#getemail)
- Added [Collaborator.getPermission](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#getpermission)
- Added [Collaborator.setEmail](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#setemail)
- Added [Collaborator.setPermission](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#setpermission)
- Added [Collaborator.create](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#create)
- Added [Collaborator.update](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#update)
- Added [Collaborator.remove](https://bkper.com/docs/api/bkper-js/classes/collaborator/.md#remove)
- Added [Group.isBalanceVerified](https://bkper.com/docs/api/bkper-js/classes/group/.md#isbalanceverified)
- Deprecated [Integration.getLogo](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getlogo)
- Added [Integration.getLogoUrl](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getlogourl)
- Added [Integration.getLogoUrlDark](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getlogourldark)
- Added [Resource](https://bkper.com/docs/api/bkper-js/classes/resource/.md)
- Added [Transaction.getCreatedBy](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#getcreatedby)
### August 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Enhanced file upload and management system with drag-and-drop support
- Added support to multiple file attachments with improved interface
- Added interactive data visualization with pie, line, and bar chart types (desktop only)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [BalancesReport.getBalancesUrl](https://bkper.com/docs/api/bkper-gs/interfaces/balancesreport/.md#getbalancesurl) to fetch balances directly from Cloud Storage for improved performance
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [File.getProperties](https://bkper.com/docs/api/bkper-js/classes/file/.md#getproperties)
- Added [File.setProperties](https://bkper.com/docs/api/bkper-js/classes/file/.md#setproperties)
- Added [File.getProperty](https://bkper.com/docs/api/bkper-js/classes/file/.md#getproperty)
- Added [File.setProperty](https://bkper.com/docs/api/bkper-js/classes/file/.md#setproperty)
- Added [File.deleteProperty](https://bkper.com/docs/api/bkper-js/classes/file/.md#deleteproperty)
### July 2025
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Added MCP server support for AI assistants and agents to interact with your Bkper books
- Added support for AI assistants to analyze your books with monthly and year-to-date balances
- Improved date filtering with more intuitive `before:` operator
- Added setup instructions for Claude Desktop and other AI tools
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added selected transactions counter
- Added evolved balances for permanent accounts
- Added book reload button
- Added search assistant with advanced filtering and suggestions
- Enhanced search bar experience with suggestions
- Improved optimistic UI approach with async loading and instant feedback
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Released version 3.37.0
- Fixed [BalancesDataTableBuilder](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md) to only expand all groups when filtering by group
- Updated [BalancesDataTableBuilder.formatDate](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#formatdate) to use ISO YYYY-MM-DD format
- Reverted time table transpose behavior in [BalancesDataTableBuilder.transpose](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#transpose)
- [bkper-js](https://github.com/bkper/bkper-js)
- **BREAKING CHANGE:** Refactored `Bkper` class from static methods to constructor-based pattern
- **BREAKING CHANGE:** Removed deprecated methods: `Transaction.remove()`, `Transaction.restore()`, `Account.getBalance()`, `Account.getBalanceRaw()`
- **MIGRATION:** Use `transaction.trash()` and `transaction.untrash()` instead of `remove()` and `restore()`
- **MIGRATION:** Use `Book.getBalancesReport()` instead of `Account.getBalance()` methods
- Added [Balance](https://bkper.com/docs/api/bkper-js/classes/balance/.md) class back for improved balance reporting
- Added [BalancesDataTableBuilder](https://bkper.com/docs/api/bkper-js/classes/balancesdatatablebuilder/.md) for building balance data tables
- Added [BalanceType](https://bkper.com/docs/api/bkper-js/enumerations/balancetype/.md) enum with TOTAL, PERIOD, and CUMULATIVE options
- Updated [Book.getDatePattern](https://bkper.com/docs/api/bkper-js/classes/book/.md#getdatepattern) to return default pattern ‘dd/MM/yyyy’ when not set
### June 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added enhanced date and amount input components with automatic book formatting
- Added book copy feature
- Improved query parser to [support search last modification date](https://help.bkper.com/en/articles/2569178-bkper-query-guide#:~:text=Search%20for%20last%20modification%20date%20(The%20last%20update%20in%20Activities)).
- [Google Sheets Add-on](https://bkper.com/apps/bkper-sheets)
- Combined balance Values of Hashtags and Accounts or hashtags and Groups (up to 3000 transactions)
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Introduced MCP server - connect AI assistants to your Bkper books with `bkper mcp start`
- Added book name filtering to quickly find specific books
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.copy](https://bkper.com/docs/api/bkper-js/classes/book/.md#copy)
- Added [Transaction.getUpdatedAt](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#getupdatedat)
- Added [Transaction.getUpdatedAtFormatted](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#getupdatedatformatted)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Group.isLocked](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#islocked) and [Group.setLocked](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#setlocked) for group access control
- Added [Collection.setName](https://bkper.com/docs/api/bkper-gs/interfaces/collection/.md#setname) and [Collection.update](https://bkper.com/docs/api/bkper-gs/interfaces/collection/.md#update) methods
- Added [Group.getParentGroupsChain](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#getparentgroupschain) for navigating parent Groups hierarchy
- Fixed group validation in [Account.getGroups](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#getgroups) method
### May 2025
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Group.isLocked](https://bkper.com/docs/api/bkper-js/classes/group/.md#islocked)
- Added [Group.setLocked](https://bkper.com/docs/api/bkper-js/classes/group/.md#setlocked)
- Added [Query](https://bkper.com/docs/api/bkper-js/classes/query/.md)
- Added [Query.json](https://bkper.com/docs/api/bkper-js/classes/query/.md#json)
- Added [Query.getId](https://bkper.com/docs/api/bkper-js/classes/query/.md#getid)
- Added [Query.getTitle](https://bkper.com/docs/api/bkper-js/classes/query/.md#gettitle)
- Added [Query.setTitle](https://bkper.com/docs/api/bkper-js/classes/query/.md#settitle)
- Added [Query.getQuery](https://bkper.com/docs/api/bkper-js/classes/query/.md#getquery)
- Added [Query.setQuery](https://bkper.com/docs/api/bkper-js/classes/query/.md#setquery)
- Added [Query.create](https://bkper.com/docs/api/bkper-js/classes/query/.md#create)
- Added [Query.update](https://bkper.com/docs/api/bkper-js/classes/query/.md#update)
- Added [Query.remove](https://bkper.com/docs/api/bkper-js/classes/query/.md#remove)
- Added [Book.getSavedQueries](https://bkper.com/docs/api/bkper-js/classes/book/.md#getsavedqueries)
- Added [Book.batchPostTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchposttransactions)
- Added [Book.batchCheckTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchchecktransactions)
- Added [Book.batchUncheckTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchunchecktransactions)
- Added [Book.batchUpdateTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchupdatetransactions)
- Added [Book.batchUntrashTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchuntrashtransactions)
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added transaction selection and batch actions (desktop only): post, check, uncheck, update, trash and restore multiple transactions at once
- Added context menu with installed apps, record by email and automation links
- Added account balance adjustment feature for permanent accounts
- Added saved queries section to chart of accounts menu
### April 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added account actions: edit, add to group, remove from group, delete, archive
- Added group actions: edit, add new group, add new account, hide, lock/unlock, delete
- Added account suggestions in transaction editor
- New [Learning Center](https://bkper.com/learn.md)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.batchCreateAccounts](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchcreateaccounts)
- Added [Book.batchCreateGroups](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchcreategroups)
### March 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added real-time presence indicators showing active users and bots/agents
- Released new [Inventory bot](https://bkper.com/apps/inventory-bot)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Agent.getLogoUrlDark](https://bkper.com/docs/api/bkper-js/classes/agent/.md#getlogourldark)
- Added [App.getFilePatterns](https://bkper.com/docs/api/bkper-js/classes/app/.md#getfilepatterns)
- Added [App.getLogoUrlDark](https://bkper.com/docs/api/bkper-js/classes/app/.md#getlogourldark)
- Added [App.getOwnerLogoUrl](https://bkper.com/docs/api/bkper-js/classes/app/.md#getownerlogourl)
- Added [App.getOwnerName](https://bkper.com/docs/api/bkper-js/classes/app/.md#getownername)
- Added [App.isPublished](https://bkper.com/docs/api/bkper-js/classes/app/.md#ispublished)
- Added [Message](https://bkper.com/docs/api/bkper-js/classes/message/.md)
- Added [Message.create](https://bkper.com/docs/api/bkper-js/classes/message/.md#create)
- Added [Message.deleteProperty](https://bkper.com/docs/api/bkper-js/classes/message/.md#deleteproperty)
- Added [Message.getAgent](https://bkper.com/docs/api/bkper-js/classes/message/.md#getagent)
- Added [Message.getCreatedAt](https://bkper.com/docs/api/bkper-js/classes/message/.md#getcreatedat)
- Added [Message.getContent](https://bkper.com/docs/api/bkper-js/classes/message/.md#getcontent)
- Added [Message.getId](https://bkper.com/docs/api/bkper-js/classes/message/.md#getid)
- Added [Message.getProperties](https://bkper.com/docs/api/bkper-js/classes/message/.md#getproperties)
- Added [Message.getProperty](https://bkper.com/docs/api/bkper-js/classes/message/.md#getproperty)
- Added [Message.getUser](https://bkper.com/docs/api/bkper-js/classes/message/.md#getuser)
- Added [Message.setContent](https://bkper.com/docs/api/bkper-js/classes/message/.md#setcontent)
- Added [Message.setProperties](https://bkper.com/docs/api/bkper-js/classes/message/.md#setproperties)
- Added [Message.setProperty](https://bkper.com/docs/api/bkper-js/classes/message/.md#setproperty)
- Added [Message.json](https://bkper.com/docs/api/bkper-js/classes/message/.md#json)
- Added [Transaction.getAgentName](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#getagentname)
- Added [Transaction.getAgentLogoUrl](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#getagentlogourl)
- Added [Transaction.getAgentLogoUrlDark](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#getagentlogourldark)
### February 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added balances to chart of accounts menu
- Added collection navigator
- Added book actions: rename, settings, properties
- Added drag and drop interface for moving accounts between groups (desktop only)
- Enhanced account and group management with in-context creation and editing
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [EventType](https://bkper.com/docs/api/bkper-js/enumerations/eventtype/.md) enum
- Added [BotResponseType](https://bkper.com/docs/api/bkper-js/enumerations/botresponsetype/.md) enum
- Added [Agent](https://bkper.com/docs/api/bkper-js/classes/agent/.md)
- Added [Agent.getId](https://bkper.com/docs/api/bkper-js/classes/agent/.md#getid)
- Added [Agent.getLogoUrl](https://bkper.com/docs/api/bkper-js/classes/agent/.md#getlogourl)
- Added [Agent.getName](https://bkper.com/docs/api/bkper-js/classes/agent/.md#getname)
- Added [Agent.json](https://bkper.com/docs/api/bkper-js/classes/agent/.md#json)
- Added [App.getDescription](https://bkper.com/docs/api/bkper-js/classes/app/.md#getdescription)
- Added [App.getEvents](https://bkper.com/docs/api/bkper-js/classes/app/.md#getevents)
- Added [App.getLogoUrl](https://bkper.com/docs/api/bkper-js/classes/app/.md#getlogourl)
- Added [App.getName](https://bkper.com/docs/api/bkper-js/classes/app/.md#getname)
- Added [App.hasEvents](https://bkper.com/docs/api/bkper-js/classes/app/.md#hasevents)
- Added [Book.batchReplayEvents](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchreplayevents)
- Added [Book.getApps](https://bkper.com/docs/api/bkper-js/classes/book/.md#getapps)
- Added [BotResponse](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md)
- Added [BotResponse.getAgentId](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md#getagentid)
- Added [BotResponse.getCreatedAt](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md#getcreatedat)
- Added [BotResponse.getEvent](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md#getevent)
- Added [BotResponse.getMessage](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md#getmessage)
- Added [BotResponse.getType](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md#gettype)
- Added [BotResponse.remove](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md#remove)
- Added [BotResponse.replay](https://bkper.com/docs/api/bkper-js/classes/botresponse/.md#replay)
- Added [Event.getAgent](https://bkper.com/docs/api/bkper-js/classes/event/.md#getagent)
- Added [Event.getBook](https://bkper.com/docs/api/bkper-js/classes/event/.md#getbook)
- Added [Event.getBotResponses](https://bkper.com/docs/api/bkper-js/classes/event/.md#getbotresponses)
- Added [Event.getCreatedAt](https://bkper.com/docs/api/bkper-js/classes/event/.md#getcreatedat)
- Added [Event.getId](https://bkper.com/docs/api/bkper-js/classes/event/.md#getid)
- Added [Event.getType](https://bkper.com/docs/api/bkper-js/classes/event/.md#gettype)
- Added [Event.getUser](https://bkper.com/docs/api/bkper-js/classes/event/.md#getuser)
- Added [Event.hasErrorResponse](https://bkper.com/docs/api/bkper-js/classes/event/.md#haserrorresponse)
- Added [User.getAvatarUrl](https://bkper.com/docs/api/bkper-js/classes/user/.md#getavatarurl)
### January 2025
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added search bar
- Added chart of accounts menu to transaction view
- Added events history and activity tracking
- Enhanced mobile experience with responsive design improvements
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [BalancesContainer](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md)
- Added [BalancesContainer.getName](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getname)
- Added [BalancesContainer.getNormalizedName](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getnormalizedname)
- Added [BalancesContainer.getGroup](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getgroup)
- Added [BalancesContainer.getAccount](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getaccount)
- Added [BalancesContainer.getParent](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getparent)
- Added [BalancesContainer.getDepth](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getdepth)
- Added [BalancesContainer.isCredit](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#iscredit)
- Added [BalancesContainer.isPermanent](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#ispermanent)
- Added [BalancesContainer.isFromAccount](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#isfromaccount)
- Added [BalancesContainer.isFromGroup](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#isfromgroup)
- Added [BalancesContainer.hasGroupBalances](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#hasgroupbalances)
- Added [BalancesContainer.getCumulativeBalance](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getcumulativebalance)
- Added [BalancesContainer.getCumulativeBalanceRaw](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getcumulativebalanceraw)
- Added [BalancesContainer.getCumulativeBalanceText](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getcumulativebalancetext)
- Added [BalancesContainer.getCumulativeBalanceRawText](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getcumulativebalancerawtext)
- Added [BalancesContainer.getPeriodBalance](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getperiodbalance)
- Added [BalancesContainer.getPeriodBalanceRaw](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getperiodbalanceraw)
- Added [BalancesContainer.getPeriodBalanceText](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getperiodbalancetext)
- Added [BalancesContainer.getPeriodBalanceRawText](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getperiodbalancerawtext)
- Added [BalancesContainer.getBalancesContainers](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getbalancescontainers)
- Added [BalancesContainer.getBalancesContainer](https://bkper.com/docs/api/bkper-js/interfaces/balancescontainer/.md#getbalancescontainer)
- Added [BalancesReport](https://bkper.com/docs/api/bkper-js/classes/balancesreport/.md)
- Added [BalancesReport.getBook](https://bkper.com/docs/api/bkper-js/classes/balancesreport/.md#getbook)
- Added [BalancesReport.getPeriod](https://bkper.com/docs/api/bkper-js/classes/balancesreport/.md#getperiod)
- Added [BalancesReport.getBalancesContainers](https://bkper.com/docs/api/bkper-js/classes/balancesreport/.md#getbalancescontainers)
- Added [BalancesReport.getBalancesContainer](https://bkper.com/docs/api/bkper-js/classes/balancesreport/.md#getbalancescontainer)
- Added [Book.getAutoPost](https://bkper.com/docs/api/bkper-js/classes/book/.md#getautopost)
- Added [Book.setAutoPost](https://bkper.com/docs/api/bkper-js/classes/book/.md#setautopost)
- Added [Group.isCredit](https://bkper.com/docs/api/bkper-js/classes/group/.md#iscredit)
- Added [Group.isMixed](https://bkper.com/docs/api/bkper-js/classes/group/.md#ismixed)
- Added [User.getPlan](https://bkper.com/docs/api/bkper-js/classes/user/.md#getplan)
- Added [User.hasBillingEnabled](https://bkper.com/docs/api/bkper-js/classes/user/.md#hasbillingenabled)
## 2024
### December 2024
- Released [Group Lock/Unlock](https://help.bkper.com/en/articles/8499533-using-groups#h_42583f6bb3) feature
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added advanced transaction editor enabling post/update actions
- Enhanced keyboard navigation and input handling throughout the app
- Introduced permission-based layouts for desktop and mobile devices
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.listEvents](https://bkper.com/docs/api/bkper-js/classes/book/.md#listevents)
- Added [EventList](https://bkper.com/docs/api/bkper-js/classes/eventlist/.md)
- Added [EventList.getCursor](https://bkper.com/docs/api/bkper-js/classes/eventlist/.md#getcursor)
- Added [EventList.getFirst](https://bkper.com/docs/api/bkper-js/classes/eventlist/.md#getfirst)
- Added [EventList.getItems](https://bkper.com/docs/api/bkper-js/classes/eventlist/.md#getitems)
- Added [EventList.size](https://bkper.com/docs/api/bkper-js/classes/eventlist/.md#size)
- Added [Group.isPermanent](https://bkper.com/docs/api/bkper-js/classes/group/.md#ispermanent)
- Added [Group.hasParent](https://bkper.com/docs/api/bkper-js/classes/group/.md#hasparent)
- Added [Group.getChildren](https://bkper.com/docs/api/bkper-js/classes/group/.md#getchildren)
- Added [Group.getDescendants](https://bkper.com/docs/api/bkper-js/classes/group/.md#getdescendants)
- Added [Group.getDescendantTreeIds](https://bkper.com/docs/api/bkper-js/classes/group/.md#getdescendanttreeids)
- Added [Group.hasChildren](https://bkper.com/docs/api/bkper-js/classes/group/.md#haschildren)
- Added [Group.isLeaf](https://bkper.com/docs/api/bkper-js/classes/group/.md#isleaf)
- Added [Group.isRoot](https://bkper.com/docs/api/bkper-js/classes/group/.md#isroot)
- Added [Group.getDepth](https://bkper.com/docs/api/bkper-js/classes/group/.md#getdepth)
- Added [Group.getRoot](https://bkper.com/docs/api/bkper-js/classes/group/.md#getroot)
- Added [Group.getRootName](https://bkper.com/docs/api/bkper-js/classes/group/.md#getrootname)
- Added [Group.hasAccounts](https://bkper.com/docs/api/bkper-js/classes/group/.md#hasaccounts)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Group.isLocked](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#islocked)
- Added [Group.setLocked](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#setlocked)
### November 2024
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added account and group management
- Added transaction actions (check, uncheck, delete, restore)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Transaction.trash](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#trash)
- Added [Transaction.untrash](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#untrash)
- Added [Transaction.getAmountFormatted](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#getamountformatted)
- Added [Transaction.isLocked](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#islocked)
- Removed `Transaction.remove` from [Transaction](https://bkper.com/docs/api/bkper-js/classes/transaction/.md)
- Removed `Transaction.restore` from [Transaction](https://bkper.com/docs/api/bkper-js/classes/transaction/.md)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Group.getParentGroupsChain](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#getparentgroupschain)
- Added [Collection.setName](https://bkper.com/docs/api/bkper-gs/interfaces/collection/.md#setname)
- Added [Collection.update](https://bkper.com/docs/api/bkper-gs/interfaces/collection/.md#update)
### October 2024
- Migrated Brazilian [Bank Connections](https://bkper.com/bank-connections/) to regulated **Open Finance**, with **OAuth2** authentication
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Added offline transaction recording
- Added upload of files and images
- Enhanced mobile drawer handling
- [bkper-js](https://github.com/bkper/bkper-js)
- Exposed `payload` property on all objects from [bkper-js](https://bkper.com/docs/bkper-js.md) interface
- Added [Collection.addBooks](https://bkper.com/docs/api/bkper-js/classes/collection/.md#addbooks)
- Added [Collection.create](https://bkper.com/docs/api/bkper-js/classes/collection/.md#create)
- Added [Collection.getOwnerUsername](https://bkper.com/docs/api/bkper-js/classes/collection/.md#getownerusername)
- Added [Collection.getPermission](https://bkper.com/docs/api/bkper-js/classes/collection/.md#getpermission)
- Added [Collection.getUpdatedAt](https://bkper.com/docs/api/bkper-js/classes/collection/.md#getupdatedat)
- Added [Collection.remove](https://bkper.com/docs/api/bkper-js/classes/collection/.md#remove)
- Added [Collection.removeBooks](https://bkper.com/docs/api/bkper-js/classes/collection/.md#removebooks)
- Added [Collection.setName](https://bkper.com/docs/api/bkper-js/classes/collection/.md#setname)
- Added [Collection.update](https://bkper.com/docs/api/bkper-js/classes/collection/.md#update)
- Added [Bkper.getBillingPortalUrl](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#getbillingportalurl)
- Added [Connection.getDateAddedMs](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getdateaddedms)
- Added [Connection.getLogo](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getlogo)
- Added [Connection.remove](https://bkper.com/docs/api/bkper-js/classes/connection/.md#remove)
- Added [Integration.getAddedBy](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getaddedby)
- Added [Integration.getAgentId](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getagentid)
- Added [Integration.getDateAddedMs](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getdateaddedms)
- Added [Integration.getLastUpdateMs](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getlastupdatems)
- Added [Integration.getLogo](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getlogo)
- Added [Integration.remove](https://bkper.com/docs/api/bkper-js/classes/integration/.md#remove)
- Added [TransactionList](https://bkper.com/docs/api/bkper-js/classes/transactionlist/.md) returned from [Book.listTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#listtransactions)
- Removed `TransactionIterator` from [Transaction](https://bkper.com/docs/api/bkper-js/classes/transaction/.md)
- Removed `newTransaction` from [Book](https://bkper.com/docs/api/bkper-js/classes/book/.md). Use [Transaction](https://bkper.com/docs/api/bkper-js/classes/transaction/.md) constructor instead
- Removed `newAccount` from [Book](https://bkper.com/docs/api/bkper-js/classes/book/.md). Use [Account](https://bkper.com/docs/api/bkper-js/classes/account/.md) constructor instead
- Removed `newGroup` from [Book](https://bkper.com/docs/api/bkper-js/classes/book/.md). Use [Group](https://bkper.com/docs/api/bkper-js/classes/group/.md) constructor instead
- Removed `newFile` from [Book](https://bkper.com/docs/api/bkper-js/classes/book/.md). Use [File](https://bkper.com/docs/api/bkper-js/classes/file/.md) constructor instead
### September 2024
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Enhanced overall layout and navigation
- Extracted [bkper-js](https://github.com/bkper/bkper-js) from [bkper-cli](https://github.com/bkper/bkper-cli) as a standalone library.
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Config.requestRetryHandler](https://bkper.com/docs/api/bkper-js/interfaces/config/.md#requestretryhandler)
- Added [Visibility](https://bkper.com/docs/api/bkper-js/enumerations/visibility/.md) enum
- Added [App.json](https://bkper.com/docs/api/bkper-js/classes/app/.md#json)
- Added [Bkper.getApps](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#getapps)
- Added [Bkper.getBooks](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#getbooks)
- Added [Bkper.getTemplates](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#gettemplates)
- Added [Bkper.newBook](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#newbook)
- Added [Book.getTotalTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#gettotaltransactions)
- Added [Book.getTotalTransactionsCurrentMonth](https://bkper.com/docs/api/bkper-js/classes/book/.md#gettotaltransactionscurrentmonth)
- Added [Book.getTotalTransactionsCurrentYear](https://bkper.com/docs/api/bkper-js/classes/book/.md#gettotaltransactionscurrentyear)
- Added [Book.getVisibility](https://bkper.com/docs/api/bkper-js/classes/book/.md#getvisibility)
- Added [Book.create](https://bkper.com/docs/api/bkper-js/classes/book/.md#create)
- Added [Collection.json](https://bkper.com/docs/api/bkper-js/classes/collection/.md#json)
- Added [Template](https://bkper.com/docs/api/bkper-js/classes/template/.md)
- Added [Template.getBookId](https://bkper.com/docs/api/bkper-js/classes/template/.md#getbookid)
- Added [Template.getBookLink](https://bkper.com/docs/api/bkper-js/classes/template/.md#getbooklink)
- Added [Template.getCategory](https://bkper.com/docs/api/bkper-js/classes/template/.md#getcategory)
- Added [Template.getDescription](https://bkper.com/docs/api/bkper-js/classes/template/.md#getdescription)
- Added [Template.getImageUrl](https://bkper.com/docs/api/bkper-js/classes/template/.md#getimageurl)
- Added [Template.getName](https://bkper.com/docs/api/bkper-js/classes/template/.md#getname)
- Added [Template.getSheetsLink](https://bkper.com/docs/api/bkper-js/classes/template/.md#getsheetslink)
- Added [Template.getTimesUsed](https://bkper.com/docs/api/bkper-js/classes/template/.md#gettimesused)
- Added [Template.json](https://bkper.com/docs/api/bkper-js/classes/template/.md#json)
- Added [User.getEmail](https://bkper.com/docs/api/bkper-js/classes/user/.md#getemail)
- Added [User.getHostedDomain](https://bkper.com/docs/api/bkper-js/classes/user/.md#gethosteddomain)
- Added [User.isFree](https://bkper.com/docs/api/bkper-js/classes/user/.md#isfree)
- Added [User.hasStartedTrial](https://bkper.com/docs/api/bkper-js/classes/user/.md#hasstartedtrial)
- Added [User.getDaysLeftInTrial](https://bkper.com/docs/api/bkper-js/classes/user/.md#getdaysleftintrial)
- Added [User.hasUsedConnections](https://bkper.com/docs/api/bkper-js/classes/user/.md#hasusedconnections)
- Added [User.json](https://bkper.com/docs/api/bkper-js/classes/user/.md#json)
- [Stock Bot](https://github.com/bkper/stock-bot)
- Added option to track realized results using single fair value accounting basis
- Added `stock_fair` book property to flag realized results tracking over fair values only
- [bkper-cli](https://github.com/bkper/bkper-cli)
- Added support to `bkperapp.yaml` file to define App properties
- Deprecated Apps Script Bot
- [Subledger Bot](https://github.com/bkper/bkper-subledger-bot)
- Added option to replicate transactions without having to set a child group for it
### August 2024
- [Mobile Web App](https://help.bkper.com/en/articles/2569192-bkper-mobile-web-app)
- Launched Bkper’s new Mobile Web App, introducing a modern, redesigned interface
- Added support to dark mode
- Added transaction listing and record features
### July 2024
- New design with dark mode
### April 2024
- [Stock Bot](https://github.com/bkper/stock-bot)
- Adjusted Realized Results service to calculate results on both accounting basis (historical and fair) by default
- Added `cost_hist` transaction property to pass historical cost information
### January 2024
- Added [Batch Edit Transactions](https://help.bkper.com/en/articles/8808887-batch-edit-transactions-drafts)
- Added **Batch Restore Transactions**
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.batchUpdateTransactions](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#batchupdatetransactions)
- Added [Transaction.setChecked](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setchecked)
- Added [Transaction.isLocked](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#islocked)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Transaction.setChecked](https://bkper.com/docs/api/bkper-js/classes/transaction/.md#setchecked)
## 2023
### December 2023
- [Google Sheets Add-on](https://bkper.com/apps/bkper-sheets)
- Added transaction ID generator tool
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [BotResponseType](https://bkper.com/docs/api/bkper-gs/enumerations/botresponsetype/.md)
- Added [BotResponse](https://bkper.com/docs/api/bkper-gs/interfaces/botresponse/.md)
- Added [BotResponse.getType](https://bkper.com/docs/api/bkper-gs/interfaces/botresponse/.md#gettype)
- Added [BotResponse.getAgentId](https://bkper.com/docs/api/bkper-gs/interfaces/botresponse/.md#getagentid)
- Added [BotResponse.getMessage](https://bkper.com/docs/api/bkper-gs/interfaces/botresponse/.md#getmessage)
- Added [Event.getBotResponses](https://bkper.com/docs/api/bkper-gs/interfaces/event/.md#getbotresponses)
### November 2023
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Event](https://bkper.com/docs/api/bkper-gs/interfaces/event/.md)
- Added [Event.getId](https://bkper.com/docs/api/bkper-gs/interfaces/event/.md#getid)
- Added [EventIterator](https://bkper.com/docs/api/bkper-gs/interfaces/eventiterator/.md)
- Added [EventIterator.getBook](https://bkper.com/docs/api/bkper-gs/interfaces/eventiterator/.md#getbook)
- Added [EventIterator.getContinuationToken](https://bkper.com/docs/api/bkper-gs/interfaces/eventiterator/.md#getcontinuationtoken)
- Added [EventIterator.hasNext](https://bkper.com/docs/api/bkper-gs/interfaces/eventiterator/.md#hasnext)
- Added [EventIterator.next](https://bkper.com/docs/api/bkper-gs/interfaces/eventiterator/.md#next)
- Added [EventIterator.setContinuationToken](https://bkper.com/docs/api/bkper-gs/interfaces/eventiterator/.md#setcontinuationtoken)
- Added [Book.getEvents](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getevents)
### October 2023
- Improved [copy book](https://help.bkper.com/en/articles/5649919-copy-transactions#h_df3c532255) feature allowing copy transactions from specific date
- [Stock Bot](https://bkper.com/apps/stock-bot)
- Added support for Bonds Interest accounts on auto mark-to-market service
- [Tax Bot](https://bkper.com/apps/sales-tax-bot)
- Added `tax_excluded_amount` property to allow override the excluded taxes calculated based on Group or Account `tax_excluded_rate` definition by a specific amount
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.countTransactions](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#counttransactions)
### August 2023
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Backlog](https://bkper.com/docs/api/bkper-gs/interfaces/backlog/.md)
- Added [Backlog.getCount](https://bkper.com/docs/api/bkper-gs/interfaces/backlog/.md#getcount)
- Added [Book.getBacklog](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getbacklog)
### July 2023
- Expanded [Bank Connections](https://bkper.com/blog/bkper-bank-connections-europe/.md) converage to Brazil
- [Tax Bot](https://bkper.com/apps/sales-tax-bot)
- Added Book `tax_copy_properties` property to allow copy properties from source to generated tax transaction
### June 2023
- Expanded [Bank Connections](https://bkper.com/blog/bkper-bank-connections-europe/.md) converage to Denmark, France, Germany, Ireland, Italy, Netherlands, Poland, Portugal, Spain and Sweden
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Bkper.getUser](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#getuser)
- Added [Bkper.setConfig](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#setconfig)
- Added [Book.batchTrashTransactions](https://bkper.com/docs/api/bkper-js/classes/book/.md#batchtrashtransactions)
- Added [Book.createIntegration](https://bkper.com/docs/api/bkper-js/classes/book/.md#createintegration)
- Added [Book.getIntegrations](https://bkper.com/docs/api/bkper-js/classes/book/.md#getintegrations)
- Added [Book.updateIntegration](https://bkper.com/docs/api/bkper-js/classes/book/.md#updateintegration)
- Added [Config](https://bkper.com/docs/api/bkper-js/interfaces/config/.md) interface
- Added [Connection](https://bkper.com/docs/api/bkper-js/classes/connection/.md)
- Added [Connection.clearTokenProperties](https://bkper.com/docs/api/bkper-js/classes/connection/.md#cleartokenproperties)
- Added [Connection.create](https://bkper.com/docs/api/bkper-js/classes/connection/.md#create)
- Added [Connection.deleteProperty](https://bkper.com/docs/api/bkper-js/classes/connection/.md#deleteproperty)
- Added [Connection.getAgentId](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getagentid)
- Added [Connection.getEmail](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getemail)
- Added [Connection.getId](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getid)
- Added [Connection.getIntegrations](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getintegrations)
- Added [Connection.getName](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getname)
- Added [Connection.getProperties](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getproperties)
- Added [Connection.getProperty](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getproperty)
- Added [Connection.getPropertyKeys](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getpropertykeys)
- Added [Connection.getType](https://bkper.com/docs/api/bkper-js/classes/connection/.md#gettype)
- Added [Connection.getUUID](https://bkper.com/docs/api/bkper-js/classes/connection/.md#getuuid)
- Added [Connection.json](https://bkper.com/docs/api/bkper-js/classes/connection/.md#json)
- Added [Connection.setAgentId](https://bkper.com/docs/api/bkper-js/classes/connection/.md#setagentid)
- Added [Connection.setName](https://bkper.com/docs/api/bkper-js/classes/connection/.md#setname)
- Added [Connection.setProperties](https://bkper.com/docs/api/bkper-js/classes/connection/.md#setproperties)
- Added [Connection.setProperty](https://bkper.com/docs/api/bkper-js/classes/connection/.md#setproperty)
- Added [Connection.setType](https://bkper.com/docs/api/bkper-js/classes/connection/.md#settype)
- Added [Connection.setUUID](https://bkper.com/docs/api/bkper-js/classes/connection/.md#setuuid)
- Added [Integration](https://bkper.com/docs/api/bkper-js/classes/integration/.md)
- Added [Integration.deleteProperty](https://bkper.com/docs/api/bkper-js/classes/integration/.md#deleteproperty)
- Added [Integration.getBookId](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getbookid)
- Added [Integration.getId](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getid)
- Added [Integration.getName](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getname)
- Added [Integration.getProperties](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getproperties)
- Added [Integration.getProperty](https://bkper.com/docs/api/bkper-js/classes/integration/.md#getproperty)
- Added [Integration.json](https://bkper.com/docs/api/bkper-js/classes/integration/.md#json)
- Added [Integration.setProperties](https://bkper.com/docs/api/bkper-js/classes/integration/.md#setproperties)
- Added [Integration.setProperty](https://bkper.com/docs/api/bkper-js/classes/integration/.md#setproperty)
- Added [User](https://bkper.com/docs/api/bkper-js/classes/user/.md)
- Added [User.getConnection](https://bkper.com/docs/api/bkper-js/classes/user/.md#getconnection)
- Added [User.getConnections](https://bkper.com/docs/api/bkper-js/classes/user/.md#getconnections)
- Added [User.getFullName](https://bkper.com/docs/api/bkper-js/classes/user/.md#getfullname)
- Added [User.getId](https://bkper.com/docs/api/bkper-js/classes/user/.md#getid)
- Added [User.getName](https://bkper.com/docs/api/bkper-js/classes/user/.md#getname)
- Deprecated [Bkper.setApiKey](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#setapikey)
- Deprecated [Bkper.setOAuthTokenProvider](https://bkper.com/docs/api/bkper-js/classes/bkper/.md#setoauthtokenprovider)
### January 2023
- Google Sheets Add-on
- Improved [Expanded group tree](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets#:~:text=on%20your%20data.-,BKPER_BALANCES_TOTAL,-Fetch%20the%20total) to allow more control on how to expand the group tree.
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Changed [BalancesDataTableBuilder.expanded](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#expanded) to also accept number of levels to expand
- Added [BalancesContainer.getDeph](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getdepth)
- Added [App](https://bkper.com/docs/api/bkper-gs/interfaces/app/.md)
- Added [App.getId](https://bkper.com/docs/api/bkper-gs/interfaces/app/.md#getid)
- Added [App.getName](https://bkper.com/docs/api/bkper-gs/interfaces/app/.md#getname)
- Added [App.getDescription](https://bkper.com/docs/api/bkper-gs/interfaces/app/.md#getdescription)
- Added [Book.addCollaborator](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#addcollaborator)
- Added [Book.removeCollaborator](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#removecollaborator)
- Added [Book.getApps](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getapps)
## 2022
### December 2022
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [BalancesDataTableBuilder.properties](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#properties)
### November 2022
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [BalancesContainer.addBalancesContainer](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#addbalancescontainer)
- Added [BalancesContainer.removeBalancesContainer](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#removebalancescontainer)
### October 2022
- Google Sheets Add-on
- New [Bkper Import Groups](https://help.bkper.com/en/articles/6581636-import-and-export-groups-quickly) from Google Sheets to Bkper
- [Tax Bot](https://bkper.com/apps/sales-tax-bot)
- Added `${account.name.origin}` expression to conditionally add account name when participates as origin in the transaction.
- Added `${account.name.destination}` expression to conditionally add account name when participates as destination in the transaction.
- Added `${account.contra.name.origin}` expression to conditionally add contra account name when participates as origin in the transaction.
- Added `${account.contra.name.destination}` expression to conditionally add contra account name when participates as destination in the transaction.
### September 2022
- Google Sheets Add-on
- Added [BKPER\_GROUPS](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets#:~:text=custom%20account%20properties.-,BKPER_GROUPS,-Fetch%20the%20Groups) function
- New [Bkper Export Groups](https://help.bkper.com/en/articles/6581636-import-and-export-groups-quickly) from Bkper to Google Sheets
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Account.getPropertyKeys](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#getpropertykeys)
- Added [AccountsDataTableBuilder.includeGroups](https://bkper.com/docs/api/bkper-gs/interfaces/accountsdatatablebuilder/.md#includegroups)
- Added [AccountsDataTableBuilder.includeProperties](https://bkper.com/docs/api/bkper-gs/interfaces/accountsdatatablebuilder/.md#includeproperties)
- Added [Book.createGroupsDataTable](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#creategroupsdatatable)
- Added [Group.getPropertyKeys](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#getpropertykeys)
- Added [GroupsDataTableBuilder](https://bkper.com/docs/api/bkper-gs/interfaces/groupsdatatablebuilder/.md)
- Added [GroupsDataTableBuilder.includeProperties](https://bkper.com/docs/api/bkper-gs/interfaces/groupsdatatablebuilder/.md#includeproperties)
- Added [GroupsDataTableBuilder.build](https://bkper.com/docs/api/bkper-gs/interfaces/groupsdatatablebuilder/.md#build)
- [bkper-js](https://github.com/bkper/bkper-js)
- Deprecated [Account.getBalance](https://bkper.com/docs/api/bkper-js/classes/account/.md#getbalance)
### July 2022
- [Exchange Bot](https://github.com/bkper/exchange-bot)
- Added `exc_aggregate` book property to use one single exchange account per currency
### June 2022
- Released [Group Hierarchy](https://bkper.com/blog/bkper-group-hierarchy/)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Group.getRoot](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#getroot)
- Added [BalancesContainer.getAccountBalancesContainers](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getaccountbalancescontainers)
- Added [BalancesReport.getAccountBalancesContainers](https://bkper.com/docs/api/bkper-gs/interfaces/balancesreport/.md#getaccountbalancescontainers)
### May 2022
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.parseDate](https://bkper.com/docs/api/bkper-js/classes/book/.md#parsedate)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.getTotalTransactions](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#gettotaltransactions)
- Added [Book.getTotalTransactionsCurrentMonth](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#gettotaltransactionscurrentmonth)
- Added [Book.getTotalTransactionsCurrentYear](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#gettotaltransactionscurrentyear)
- Added [Book.batchCheckTransactions](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#batchchecktransactions)
- Added [Book.batchUncheckTransactions](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#batchunchecktransactions)
- Added [Book.batchTrashTransactions](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#batchtrashtransactions)
- Added [Transaction.trash](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#trash)
- Added [Transaction.untrash](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#untrash)
- Deprecated [Transaction.remove](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#remove)
- Deprecated [Transaction.restore](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#restore)
### April 2022
- New [Billing Portal](https://help.bkper.com/en/articles/2569200-bkper-subscriptions)
- Added new [Book closing date](https://help.bkper.com/en/articles/5100445-book-closing-and-lock-dates) feature
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.getClosingDate](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getclosingdate)
- Added [Book.setClosingDate](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setclosingdate)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.getClosingDate](https://bkper.com/docs/api/bkper-js/classes/book/.md#getclosingdate)
- Added [Book.setClosingDate](https://bkper.com/docs/api/bkper-js/classes/book/.md#setclosingdate)
### March 2022
- Optional [copy transactions](https://help.bkper.com/en/articles/5649919-copy-transactions) upon copy a Book is now available to all book collaborators (including viewers)
- [Stock Bot](https://github.com/bkper/stock-bot)
- New feature: Forward Date Service. A simple and solid procedure to [close a period](https://help.bkper.com/en/articles/6000644-closing-a-period) and [lock](https://help.bkper.com/en/articles/5100445-book-closing-and-lock-dates) the Instruments Book
- Added input to run Realized Results calculations up to a specific date
- Added several `fwd_xxx` and `hist_xxx` properties to instruments transactions in order to track both historical and updated trading information
- Added `stock_historical` book property to calculate gains and losses over historical values
- [Exchange Bot](https://github.com/bkper/exchange-bot)
- Added `exc_historical` book property to calculate exchange updates over historical values
### February 2022
- Added support to `${group.xxx}` property filtering on context menuUrl at [bkperapp.json](https://bkper.com/docs/build/apps/configuration.md)
- Improved query parser to [support dates on ISO formats](https://help.bkper.com/en/articles/2569178-query-guide#:~:text=Dates%20can%20be%20used%20on%20Book%27s%20format%20or%2C%20preferably%2C%20on%20yyyy%2Dmm%2Ddd%20ISO%20format).
- Google Sheets Add-on
- Added [BKPER\_BALANCES\_TRIAL](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets#:~:text=the%20smallest%20amount.-,BKPER_BALANCES_TRIAL,-Fetch%20the%20trial) function
- `LIABILITY` and `OUTGOING` balances comes as negative on all formulas
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.deleteProperty](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#deleteproperty)
- Added [BalancesContainer.isPermanent](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#ispermanent)
- Added [Balance.getCumulativeBalanceRaw](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getcumulativebalanceraw)
- Added [Balance.getPeriodBalanceRaw](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getperiodbalanceraw)
- **BREAKING CHANGE:** : `LIABILITY` and `OUTGOING` balances comes as negative by default on [BalancesDataTableBuilder](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md).
## 2021
### December 2021
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Group.isCredit](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#iscredit)
- Added [Group.isPermanent](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#ispermanent)
- Added [Group.isMixed](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#ismixed)
- Added [Group.getType](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#gettype)
### November 2021
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.getPeriodStartMonth](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getperiodstartmonth)
- Added [Book.setPeriodStartMonth](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setperiodstartmonth)
- Added [Month](https://bkper.com/docs/api/bkper-gs/enumerations/month/.md)
### October 2021
- Optional [copy transactions](https://help.bkper.com/en/articles/5649919-copy-transactions) upon copy a Book
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.getGroupsByAccount](https://bkper.com/docs/api/bkper-js/classes/book/.md#getgroupsbyaccount)
### September 2021
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.parseDate](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#parsedate)
- Added [Book.parseAmount](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#parseamount)
- Added [Book.formatAmount](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#formatamount)
- Deprecated [Book.parseValue](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#parsevalue)
- Deprecated [Book.formatValue](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#formatvalue)
### July 2021
- Published [REST API v4](https://api.bkper.com)
- Cleaning up and optimizing [bkper-js](https://bkper.com/docs/bkper-js.md)
### May 2021
- [Exchange Bot](https://github.com/bkper/exchange-bot)
- Added `exc_base` true/false to book property to flag a book as a base book.
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Group.getParent](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#getparent)
- Added [Group.hasChildren](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#haschildren)
- Added [BalancesContainer.getAccount](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getaccount)
- Added [BalancesContainer.getGroup](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getgroup)
- Added [BalancesContainer.getParent](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getparent)
- Added [BalancesContainer.isFromAccount](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#isfromaccount)
- Added [BalancesContainer.isFromGroup](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#isfromgroup)
- Added [BalancesContainer.hasGroupBalances](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#hasgroupbalances)
- Added [BalancesContainer.getProperties](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getproperties)
- Added [BalancesContainer.getProperty](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getproperty)
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Group.getParent](https://bkper.com/docs/api/bkper-js/classes/group/.md#getparent)
- Added [Group.setParent](https://bkper.com/docs/api/bkper-js/classes/group/.md#setparent)
- **BREAKING CHANGE:** Removed **AccountsDataTableBuilder**
- **BREAKING CHANGE:** Removed **BalancesDataTableBuilder**
- **BREAKING CHANGE:** Removed **TransactionsDataTableBuilder**
- **BREAKING CHANGE:** Removed **BalancesReport**
- **BREAKING CHANGE:** Removed **Balance**
- **BREAKING CHANGE:** Removed **BalancesContainer**
### April 2021
- New [Book Lock Date](https://help.bkper.com/en/articles/5100445-book-closing-and-lock-dates) to prevent modification prior to a given date on a book.
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.getLockDate](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getlockdate)
- Added [Book.setLockDate](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setlockdate)
- Added [TransactionsDataTableBuilder.includeIds](https://bkper.com/docs/api/bkper-gs/interfaces/transactionsdatatablebuilder/.md#includeids)
- Added [BalancesContainer.getCumulativeBalanceRaw](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getcumulativebalanceraw)
- Added [BalancesContainer.getCumulativeBalanceRawText](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getcumulativebalancerawtext)
- Added [BalancesDataTableBuilder.raw](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#raw)
- Added [Account.getGetBalanceRaw](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#getbalanceraw)
- **BREAKING CHANGE:** : Removed raw param from [Account.getGetBalance](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#getbalance)
- **BREAKING CHANGE:** : Removed **Account.getCheckedBalane**
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.getLockDate](https://bkper.com/docs/api/bkper-js/classes/book/.md#getlockdate)
- Added [Book.setLockDate](https://bkper.com/docs/api/bkper-js/classes/book/.md#setlockdate)
- Added `ids` param to [BKPER\_TRANSACTION](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets) function
- [Exchange Bot](https://github.com/bkper/exchange-bot)
- Added `exc_code` to track the exchange base code used to convert the transaction.
- Added `exc_rate` to track the exchange base rate used to convert the transaction.
### March 2021
- New [Range Slider](https://bkper.com/blog/bkper-range-slider/) to improve account balances navigation and reconciliation
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Balance.getCumulativeCredit](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getcumulativecredit)
- Added [Balance.getCumulativeDebit](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getcumulativedebit)
- Added [Balance.getPeriodCredit](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getperiodcredit)
- Added [Balance.getPeriodDebit](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getperioddebit)
- Added [BalancesDataTableBuilder.trial](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#trial)
- Added [BalancesDataTableBuilder.period](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#period)
- Added [BalancesContainer.getCumulativeCredit](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getcumulativecredit)
- Added [BalancesContainer.getCumulativeCreditText](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getcumulativecredittext)
- Added [BalancesContainer.getCumulativeDebit](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getcumulativedebit)
- Added [BalancesContainer.getCumulativeDebitText](https://bkper.com/docs/api/bkper-gs/interfaces/balancescontainer/.md#getcumulativedebittext)
- Added [Transaction.getPropertyKeys](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getpropertykeys)
- Added [TransactionsDataTableBuilder.includeProperties](https://bkper.com/docs/api/bkper-gs/interfaces/transactionsdatatablebuilder/.md#includeproperties)
- **BREAKING CHANGE:** : Removed **BalanceCheckedType**
- [bkper-js](https://github.com/bkper/bkper-js)
- **BREAKING CHANGE:** : Removed **BalanceCheckedType**
- Added `properties` param to [BKPER\_TRANSACTION](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets) function
- Added `trial` param to [BKPER\_BALANCES\_TOTAL](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets) function
### February 2021
- New [Subledger Bot](https://github.com/bkper/subledger-bot) to connect books into Ledger-Subledger relationship
- [Tax Bot](https://bkper.com/apps/sales-tax-bot)
- Added `${account.contra.name}` expression to allow dynamically insert contra account name to tax transactions
- [bkper-js](https://github.com/bkper/bkper-js)
- Added [Book.getPeriod](https://bkper.com/docs/api/bkper-js/classes/book/.md#getperiod)
- Added [Book.setPeriod](https://bkper.com/docs/api/bkper-js/classes/book/.md#setperiod)
- Added [Book.getPeriodStartMonth](https://bkper.com/docs/api/bkper-js/classes/book/.md#getperiodstartmonth)
- Added [Book.setPeriodStartMonth](https://bkper.com/docs/api/bkper-js/classes/book/.md#setperiodstartmonth)
- Added [Book.getPageSize](https://bkper.com/docs/api/bkper-js/classes/book/.md#getpagesize)
- Added [Book.setPageSize](https://bkper.com/docs/api/bkper-js/classes/book/.md#setpagesize)
### January 2021
- [bkper-js](https://www.npmjs.com/package/bkper) client library published
- Github App deprecated in favor of the [bkper-js](https://www.npmjs.com/package/bkper)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Amount](https://bkper.com/docs/api/bkper-gs/interfaces/amount/.md)
- Added [bkper-gs.newAmount](https://bkper.com/docs/api/bkper-gs/interfaces/bkperapp/.md#newamount)
- **BREAKING CHANGE:** : All number params and returns now wrapped in Amount class for arbitrary precision aritimethic
- [Tax Bot](https://github.com/bkper/tax-bot)
- Add support to `tax_included_amount` transaction property to override included taxes
- Deprecated `tax_rate` account and group property to split into included and excluded taxes
- Added `tax_excluded` account and group property
- Added `tax_included` account and group property
- [Exchange Bot](https://github.com/bkper/exchange-bot)
- Calculate and mirror `tax_included_amount` when present on transaction
- [Stock Bot](https://github.com/bkper/stock-bot)
- Added `stock_book` property flag to allow quantities with more than 0 fraction digits
## 2020
### December 2020
- [Exchange Bot](https://github.com/bkper/exchange-bot)
- Added `exc_code` to groups to match accounts
- Allow exchange update of non-permanent accounts
- Apply book settings and properties update on all connected books
- [Stock Bot](https://github.com/bkper/stock-bot)
- Performing Mark to Market operations upon closing, with `price` and `open_quantity` properties on financial transactions
- Fixing rounding issues on Realized Results calculations
- [Bkper CSV App](https://github.com/bkper/bkper-csv-app) now handle import upon FILE\_CREATED event
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.getFile](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getfile)
- Added [Book.setName](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setname)
- Added [Book.setDatePattern](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setdatepattern)
- Added [Book.setDecimalSeparator](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setdecimalseparator)
- Added [Book.setFractionDigits](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setfractiondigits)
- Added [Book.setProperties](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setproperties)
- Added [Book.setProperty](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#setproperty)
- Added [Book.setTimeZone](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#settimezone)
- Added [Book.update](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#update)
- [Report Menu App](https://bkper.com/apps/report-menu-app) deprecated
### November 2020
- [Tax Bot](https://github.com/bkper/tax-bot)
- Deprecated `tax_skip` Book property
- Added `tax_round` Transaction property
- [Exchange Bot](https://github.com/bkper/exchange-bot) ignores transactions generated from [Tax Bot](https://github.com/bkper/tax-bot) by default
- [Stock Bot](https://github.com/bkper/stock-bot)
- Splitted `price` instrument transaction property into `purchase_price` and `sale_price`
- Added `original_amount`, `sale_amount` and `gain_amount` instrument transaction property
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.newFile](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#newfile)
- Added [File.getSize](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#getsize)
- Added [File.getContent](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#getcontent)
- Added [File.getBlob](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#getblob)
- Added [File.setContent](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#setcontent)
- Added [File.setBlob](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#setblob)
- Added [File.setContentType](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#setcontenttype)
- Added [File.setName](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#setname)
- Added [File.create](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md#create)
- Added [Transaction.getAgentId](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getagentid)
- Added [Transaction.addFile](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#addfile)
- REST API
- Added [/files GET](https://api.bkper.com/docs/bkper.app/1/routes/bkper/v3/books/%7BbookId%7D/files/%7Bid%7D/get)
- Added [/files POST](https://api.bkper.com/docs/bkper.app/1/routes/bkper/v3/books/%7BbookId%7D/files/post)
### October 2020
- New [Record Transaction Properties feature](https://www.youtube.com/watch?v=FcVhOCBIlBY&feature=emb_title) from [Google Sheets Add-on](https://help.bkper.com/en/articles/2569151-bkper-add-on-for-google-sheets)
- New [Stock Bot](https://bkper.com/apps/stock-bot)
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Book.audit](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#audit)
- Added [Book.batchCreateTransactions](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#batchcreatetransactions)
- Added [Book.batchCreateAccounts](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#batchcreateaccounts)
- Added [Book.batchCreateGroups](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#batchcreategroups)
- Added [Book.parseValue](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#parsevalue)
- Added [Account.deleteProperty](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#deleteproperty)
- Added [Group.deleteProperty](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#deleteproperty)
- Added [Transaction.deleteProperty](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#deleteproperty)
- Improved [Transaction.setDate](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setdate) to accept Date object
- Improved [Transaction.setAmount](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setamount) to accept string
- Deprecated [Book.record](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#record)
- Deprecated [Book.createGroups](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#creategroups)
- Deprecated [Book.createAccounts](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#createaccounts)
### September 2020
- Added [custom properties](https://help.bkper.com/en/articles/3666485-custom-properties) to transactions
- Added [Balances Verification](https://help.bkper.com/en/articles/4412038-balances-verification) status to accounts on menu
- Retired hashtag balances. Hashtags works only for transaction indexing
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Transaction.getProperties](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getproperties)
- Added [Transaction.getProperty](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getproperty)
- Added [Transaction.setProperty](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setproperty)
- Added [Transaction.setProperties](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setproperties)
- Added [Group.isHidden](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#ishidden)
- Added [Group.setHidden](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#sethidden)
### August 2020
- Published the [REST API](https://bkper.com/docs/.md#rest-api)
- Published [bkper-api-types](https://www.npmjs.com/package/@bkper/bkper-api-types)
- Improved BKPER\_BALANCES\_TOTAL [Function](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets) to support `hideNames` param
- [Exchange Bot](https://bkper.com/apps/exchange-bot)
- Sync Transaction edit/delete/restore operations
- Sync Account create/update/delete operations
- Sync Group create/update/delete operations
- Apply Gain/Loss update on all connected books
- Allow optional `exc_account` group property to set the Gain/Loss Exchange Accounts
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [File](https://bkper.com/docs/api/bkper-gs/interfaces/file/.md)
- Added [Book.getTransaction](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#gettransaction)
- Added [Book.newTransaction](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#newtransaction)
- Added [Book.newAccount](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#newaccount)
- Added [Book.newGroup](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#newgroup)
- Added [Account.setName](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#setname)
- Added [Account.isArchived](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#isarchived)
- Added [Account.setArchived](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#setarchived)
- Added [Account.hasTransactionPosted](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#hastransactionposted)
- Added [Account.setType](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#settype)
- Added [Account.setProperty](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#setproperty)
- Added [Account.setProperties](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#setproperties)
- Added [Account.addGroup](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#addgroup)
- Added [Account.setGroups](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#setgroups)
- Added [Account.removeGroup](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#removegroup)
- Added [Account.create](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#create)
- Added [Account.update](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#update)
- Added [Account.delete](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#delete)
- Added [Group.setName](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#setname)
- Added [Group.setProperty](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#setproperty)
- Added [Group.setProperties](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#setproperties)
- Added [Group.create](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#create)
- Added [Group.update](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#update)
- Added [Group.delete](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#delete)
- Added [Transaction.getFiles](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getfiles)
- Added [Transaction.setCreditAccount](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setcreditaccount)
- Added [Transaction.from](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#from)
- Added [Transaction.setDebitAccount](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setdebitaccount)
- Added [Transaction.to](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#to)
- Added [Transaction.setDescription](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setdescription)
- Added [Transaction.setUrls](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#seturls)
- Added [Transaction.addUrl](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#addurl)
- Added [Transaction.getRemoteIds](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getremoteids)
- Added [Transaction.addRemoteId](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#addremoteid)
- Added [Transaction.create](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#create)
- Added [Transaction.post](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#post)
- Added [Transaction.update](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#update)
- Added [Transaction.check](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#check)
- Added [Transaction.uncheck](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#uncheck)
- Added [Transaction.remove](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#remove)
- Added [Transaction.restore](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#restore)
- Added [Transaction.isChecked](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#ischecked)
- Added [Transaction.isTrashed](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#istrashed)
- Added [Transaction.getDate](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getdate)
- Added [Transaction.setDate](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#setdate)
- Added [Transaction.getDateObject](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getdateobject)
- Added [Transaction.getDateValue](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getdatevalue)
- Added [Transaction.getDateFormatted](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getdateformatted)
- Added [Transaction.getCreatedAt](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getcreatedat)
- Added [Transaction.getCreatedAtFormatted](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getcreatedatformatted)
- Added [Transaction.getCreatedAtFormatted](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getcreatedatformatted)
- Deprecated [BalancesDataTableBuilder.hideNames](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#hidenames)
- Deprecated [Transaction.getInformedDateValue](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getinformeddatevalue)
- Deprecated [Transaction.getInformedDateText](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getinformeddatetext)
- Deprecated [Transaction.getPostDate](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getpostdate)
- Deprecated [Transaction.getPostDateText](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getpostdatetext)
- Deprecated [Book.createAccount](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#createaccount)
- Deprecated [Account.isActive](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#isactive)
### July 2020
- New [Bkper Import Accounts](https://help.bkper.com/en/articles/4273612-import-and-export-accounts-quickly) from Google Sheets to Bkper
- New [Bkper Export Accounts](https://help.bkper.com/en/articles/4273612-import-and-export-accounts-quickly) from Bkper to Google Sheets
- Improved [Exchange Bot](https://bkper.com/apps/exchange-bot) to associate books via Collections instead of `exc_books` property
- Added `hideDates` param to [functions](https://help.bkper.com/en/articles/3370084-bkper-functions-for-google-sheets) BKPER\_BALANCES\_CUMULATIVE and BKPER\_BALANCES\_PERIOD
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Collection](https://bkper.com/docs/api/bkper-gs/interfaces/collection/.md)
- Added [AccountType](https://bkper.com/docs/api/bkper-gs/enumerations/accounttype/.md)
- Added [Account.getType](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#gettype)
- Added [AccountsDataTableBuilder](https://bkper.com/docs/api/bkper-gs/interfaces/accountsdatatablebuilder/.md)
- Added [Book.createAccountsDataTable](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#createaccountsdatatable)
- Added [Book.createAccounts](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#createaccounts)
- Added [Book.createGroups](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#creategroups)
- Added [Book.getCollection](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getcollection)
- Added [BalancesDataTableBuilder.hideDates](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md#hidedates)
### June 2020
- Improved [Edit Account](https://help.bkper.com/en/articles/2569150-accounts-create-edit-archive-etc) from transaction screen
- Added [properties](https://help.bkper.com/en/articles/3666485-custom-properties-on-books-and-accounts) to Groups
- New [Tax Bot](https://bkper.com/apps/sales-tax-bot) now also works with properties set on Groups
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Group.getProperties](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#getproperties)
- Added [Group.getProperty](https://bkper.com/docs/api/bkper-gs/interfaces/group/.md#getproperty)
- Added [Account.getGroups](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#getgroups)
- Added [Book.round](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#round)
### May 2020
- New [Exchange Bot](https://bkper.com/apps/exchange-bot)
- New [HttpRequestApp library](https://github.com/bkper/http-request-app)
- New [ExchangeApp library](https://github.com/bkper/exchange-app)
### April 2020
- Improved [Developer Documentation](https://bkper.com/docs.md)
- Open Sourced [Google Sheets Add-on](https://github.com/bkper/bkper-sheets) for Bkper
- New [Bkper Developer GitHub App](https://bkper.com/docs.md#github-app) to create Apps and Bots from GitHub repositories
- New [Bots](https://help.bkper.com/en/articles/3873607-bkper-bots-installation) insfrastructure
- New [Tax Bot](https://bkper.com/apps/sales-tax-bot)
### March 2020
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [bkper-gs.setApiKey](https://bkper.com/docs/api/bkper-gs/interfaces/bkperapp/.md#setapikey)
- Added [OAuthTokenProvider](https://bkper.com/docs/api/bkper-gs/interfaces/oauthtokenprovider/.md) interface to allow custom OAuth token providers
- Using [ScripApp](https://developers.google.com/apps-script/reference/script/script-app#getoauthtoken) as the default OAuth token provider
- Added [bkper-gs.setOAuthTokenProvider](https://bkper.com/docs/api/bkper-gs/interfaces/bkperapp/.md#setoauthtokenprovider)
- [bkper-gs](https://bkper.com/docs/bkper-gs.md) scriptId changed to `1hMJszJGSUVZDB3vmsWrUZfRhY1UWbhS0SQ6Lzl06gm1zhBF3ioTM7mpJ`
### February 2020
- Add/Remove url links on transactions
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [Account.getProperties](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#getproperties)
- Added [Account.getProperty](https://bkper.com/docs/api/bkper-gs/interfaces/account/.md#getproperty)
- Added [Book.getProperties](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getproperties)
- Added [Book.getProperty](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getproperty)
### January 2020
- Books and Accounts [custom Pproperties](https://help.bkper.com/en/articles/3666485-custom-properties)
- New icons on transactions attachments and links
- Infinite scroll on transactions list
## 2019
### November 2019
- Unified Bkper Sheets Add-on into a single [Gooble Workspace Marketplace](https://workspace.google.com/marketplace/app/bkper/360398463400) listing
- Expanded [Bank Connections](https://bkper.com/bank-connections.md) converage to Ireland, United Kingdom, France and Spain
- Improved [Bkper Functions](https://bkper.com/blog/turn-google-sheets-into-a-powerful-accounting-tool/.md) to fetch balances according to **is:checked** and **is:unchecked** query operator
- [bkper-gs](https://github.com/bkper/bkper-gs)
- Added [BalanceCheckedType](https://bkper.com/docs/api/bkper-gs/interfaces/balancecheckedtype/.md) enum
- Added [BalancesReport.getBalanceCheckedType](https://bkper.com/docs/api/bkper-gs/interfaces/balancesreport/.md#getbalancecheckedtype)
- Added [Balance.getCheckedCumulativeBalance](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getcheckedcumulativebalance)
- Added [Balance.getUncheckedCumulativeBalance](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getuncheckedcumulativebalance)
- Added [Balance.getCheckedPeriodBalance](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getcheckedperiodbalance)
- Added [Balance.getUncheckedPeriodBalance](https://bkper.com/docs/api/bkper-gs/interfaces/balance/.md#getuncheckedperiodbalance)
- Inproved trash bin to order by deletion date by default
- Published this changelog page
### October 2019
- Released [Bkper Functions](https://bkper.com/blog/turn-google-sheets-into-a-powerful-accounting-tool/.md) for Google Sheets
- New [System Status](https://bkper.com/status.md) page
- New [Templates](https://bkper.com/templates.md) page
- Forms Add-on shutdown
### September 2019
- Allow user to delete [comments](https://help.bkper.com/en/articles/2569164)
- [bkper-gs types](https://www.npmjs.com/package/@bkper/bkper-gs-types) for typescript development
### August 2019
- [Bkper email integration](https://help.bkper.com/en/articles/3212470-record-transactions-by-email)
- [New API reference](https://bkper.com/docs.md) page
### July 2019
- Launched Bkper Bank Connections
### June 2019
- Launched Bkper on [Google Cloud Platform Marketplace](https://console.cloud.google.com/marketplace/details/bkper-public/bkper)
- Improved [accounts menu](https://help.bkper.com/en/articles/3066045-accounts-menu)
### April 2019
- **Shutdown** of our referral program and the Bkper Gold Plan
### March 2019
- New [**Ultradox**](https://www.ultradox.com/) integration
### January 2019
- New [automations page](https://help.bkper.com/en/articles/2569132-automations)
## 2018
### December 2018
- New [Help Center](https://help.bkper.com/) layout and better connection with our users through Intercom messenger
### October 2018
- New [Merge transactions](https://help.bkper.com/en/articles/2667277-merge-transactions) feature
- New Drag and Drop feature
- Allow Multiple [attachments](https://help.bkper.com/en/articles/2569169-attachments-links)
### August 2018
- New [templates](https://help.bkper.com/en/articles/3412269-bkper-templates) dashboard
### May 2018
- Custom sharing email logo white labeled for Business customers
### April 2018
- See who is online on Book
- Tracking transaction creators by username instead of email
- [Comments](https://help.bkper.com/en/articles/2569164) on transactions
- Improved search autocomplete
- Docs Add-on shutdown
- Forms Add-on Added highlight and log on Google Sheets for responses successfully recorded on Bkper
### March 2018
- Added [Activities](https://help.bkper.com/en/articles/3019515-track-user-activities) for all other resources - Book, Accounts, Groups - and Collaborators
- Released Referral program, with Bkper Gold Plan
## 2017
### June 2017
- Released [Activities](https://help.bkper.com/en/articles/3019515-track-user-activities) to track changes on transactions
### March 2017
- Autopost is default on newly created books
### February 2017
- Changed support structure
- Improvements on Ultradox integration
- Added date format yyyy/mm/dd
### January 2017
- Updated pricing details
## 2016
### November 2016
- [Pluga.co](https://pluga.co) Integration
### September 2016
- Batch operations (check, post, revert)
- Balance sidebar Slider for non-permanent accounts (income/expense type)
- Several UX improvements on form
- Improvements on recording, editing and posting transactions flow
- UX improvement for check/uncheck
### August 2016
- Several UX improvements on creating groups
- Several UX improvements
- Bug fix: copy paste in Excel on Firefox
- Bug fix: Drive integration pre-fix
- Improvements on recording and posting
- Sheet Add-on Bug fix: fetch balances with gaps on dates/periods with no balance change
### July 2016
- New weekly summary email
- Several improvements on list books
- Zapier out of beta
### June 2016
- Bugfix: registration duplicates
- Deprecated recurring transactions
- Partner console (already deprecated)
- Sheets Add-on:
- Fetch serve Attachment Url and Urls
- Auto update only update if book has been updated
### May 2016
- Expansible accounts menu
- Apply new group to selected accounts
- Apply account types in batch
- Validate account types per group
- Groups can only have one account type Mixed
- Groups by account types Assets together with Liabilities and Revenue with Expenses Use account types instead of Permanent Debit and Credit
- Bookbot finds accounts that start with the same word
- Bugfix: queries with group with many accounts
- Zapier Integration: added Account description, group and account balance to outgoing zaps
- Add-ons Bugfix: queries with more than one account, presentation format
### April 2016
- Lowercase recognition of accounts in post form
- Account types instead of permanent and non permanent accounts
- Results for mixed groups Groups account type validation
- Batch account type edit Bugfix: delete groups Resize balance menu on transaction window
### March 2016
- Evolved Balances for non-permanent accounts
- Added [Integration with Zapier](https://zapier.com/zapbook/bkper)
- Migrated Google Drive Inbox to Integrations
- Applied Checked & Unchecked to Charts and balances
- Bugfix: Lowercase does not auto complete in Advanced
- Discontinued bkper Gold subscription
- Add-ons [Added Auto Record Feature](https://help.bkper.com/en/articles/2569151-bkper-add-on-for-google-sheets)
### February 2016
- Added bkper **For Work** package (now Business Plan)
- Migrated from Google + Login to Google Accounts Login
- Added Google Drive listing to install bkper and create Books from within Drive
- Hashtags now are copied when you copy a Book
- Add-ons Bugfix: Add-ons wasn’t opening for some browsers versions/vendors
- [bkper-gs](https://github.com/bkper/bkper-gs):
- Added [Transaction.getUrls](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#geturls)
### January 2016
- Display group balances on the left hand menu
- Fixed Issue [#45](https://github.com/bkper/bkper-issues/issues/45)
- Bugfix: Report period balance and cumulative balance are misaligned
- Fixed Issue [#46](https://github.com/bkper/bkper-issues/issues/46)
- Bugfix: Horizontal line on charts completing period
- Add-ons Migrated to IFRAME Sandbox mode according Google Apps Script [Migration Guide](https://developers.google.com/apps-script/migration/iframe)
## 2015
### December 2015
- Added book Time Zone - [forum question](https://groups.google.com/forum/#!topic/bkper/ogJypdifbZQ)
- [bkper-gs](https://github.com/bkper/bkper-gs):
- Added [Transaction.getInformedDateText()](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getinformeddatetext)
- Added [Transaction.getInformedDateValue()](https://bkper.com/docs/api/bkper-gs/interfaces/transaction/.md#getinformeddatevalue)
- Added [Book.getTimeZone()](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#gettimezone)
- Added [Book.getTimeZoneOffset()](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#gettimezoneoffset)
### November 2015
- Launched Bkper Gold plan
- Bugfix: #Deactivated in other languages
- Bugfix: Language translation in Book Listing
### October 2015
- New [trash bin feature](https://help.bkper.com/en/articles/2569191-delete-drafts-and-revert-transactions)
### September 2015
- New feature: One click remove saved queries on the web
- Improvement: Increased font size on the web
- Improved Integration’s: Now all integration’s are placed together for a better vizualization
### August 2015
- New feature: Public books. Now you can publish your books on the web
- New feature: Create accounts on Advanced posting page
- Autocomplete now suggests accounts and transaction descriptions
### July 2015
- New feature: Google Contacts integration on the sharing settings page
### June 2015
- New feature: Record Only permission
- New feature: Edit transaction attachment - [Issue 1](https://github.com/bkper/bkper-issues/issues/1)
### May 2015
- Fixed fraction digits error - Part of [Issue 29](https://github.com/bkper/bkper-issues/issues/29)
- [bkper-gs](https://github.com/bkper/bkper-gs):
- Added [Book.getFractionDigits](https://bkper.com/docs/api/bkper-gs/interfaces/book/.md#getfractiondigits) - Part of [Issue 29](https://github.com/bkper/bkper-issues/issues/2)
- Added [BalanceReport](https://bkper.com/docs/api/bkper-gs/interfaces/balancesreport/.md)
- Added [BalancesDataTableBuilder](https://bkper.com/docs/api/bkper-gs/interfaces/balancesdatatablebuilder/.md)
### March 2015
- [bkper-gs](https://github.com/bkper/bkper-gs):
- Renamed Ledger object to Book
- Added bkper-gs.openById
- Added bkper-gs.listBooks
- Deprecated bkper-gs.openLedgerById
- Deprecated bkper-gs.listLedgers
- Added Account.getDescription
- Added Ledger.formatValue
- Changing from “Ledger” to “Book”
- Added configurable fraction digits on Ledgers
- Added Outgoing WebHooks
- Added Incoming WebHooks
- Sheets Add-on:
- Added Auto-update feature
- Added Update feature
- Fetch transactions and cumulative/period balances
### February 2015
- Bugfix: Hashtags now works for oriental languages
- Ability to remove #hashtags from index - Part of [Issue 12](https://github.com/bkper/bkper-issues/issues/12)
- [Bookbot](https://help.bkper.com/en/articles/2569152-bkper-bookbot) improved - considering same description prior to same hashtags
- Batch delete drafts - [Issue 14](https://code.google.com/p/bkper-issues/issues/detail?id=14)
- Bugfix: Data and user changed when user confirm the draft - [Issue 15](https://code.google.com/p/bkper-issues/issues/detail?id=15)
## 2014
### December 2014
- Added Charts toggle button
- Charts and Transactions rendered on same screen - [Issue 3](https://github.com/bkper/bkper-issues/issues/3)
- Released Google Drive Integration - Related to [Issue 10](https://github.com/bkper/bkper-issues/issues/10)
### November 2014
- Added [OFX](http://www.ofx.net/) import support - [Issue 10](https://github.com/bkper/bkper-issues/issues/10)
- Added “group:” and multiple “acc:” filters support to Transactions query - [Issue 3](https://github.com/bkper/bkper-issues/issues/3)
- Google Docs Add-on
- Added transactions tab - [Issue 7](https://github.com/bkper/bkper-issues/issues/7)
- Added Autosend pdf report feature - [Issue 7](https://github.com/bkper/bkper-issues/issues/7)
- [bkper-gs](https://github.com/bkper/bkper-gs):
- Added “timeZone” optional param to Ledger.record
- Removed “referencesToTransactionId” param from Ledger.record
### October 2014
- Recurring Transactions [Issue 2](https://github.com/bkper/bkper-issues/issues/2)
- Google Forms Add-on released
- Supporting Dutch language
- Supporting Spanish and Catalan languages
- Ledger settings sets Date Pattern and Decimal Separator instead of locale
- Google Docs Add-on
- Added Update statements feature - [Issue 7](https://github.com/bkper/bkper-issues/issues/7)
- [bkper-gs](https://github.com/bkper/bkper-gs):
- Added BalancesDataTableBuilder.formatDate
- Added BalancesDataTableBuilder.formatValue
- Added BalancesDataTableBuilder.buildChartDataTable
- Account.get
- Balance gets representative balace by default
- Transaction.getAccountBalance gets representative balance by defaultAdded Transaction.getOther
- AccountName(account)
- Added Ledger.getDatePattern
- Added Ledger.getDecimalSeparator
- Deprecated Ledger.getLocale
- List Balances
- List Transactions
- Record Transactions
### September 2014
- [bkper-gs](https://github.com/bkper/bkper-gs):
- Added “representative” param to Account.getBalance
- Added Transaction.getOtherAccount(account)
- Added Transaction.getCreditAmount() and Transaction.getDebitAmount()
- Added “representative” param to Transaction.getAccountBalance
- Added Transaction.getAttachmentUrl
- Removed Ledger.getTransactionById
## Canonical Sources
- https://bkper.com/llms.txt
- https://bkper.com/docs/llms-full.txt
- https://bkper.com/apps/llms-full.txt
- https://bkper.com/changelog.md