# Web Integration
TIP
The anybill web SDK is based on async/await syntax (opens new window). Although it is technically possible to use Promise based syntax we recommend the async/await syntax in conjunction with try/catch.
# Getting Started
# Resolving the SDK
The anybill SDK for web is hosted in a private npm registry (anybill-npm) that has also access to the public npm registry. This means there is no need to install peer dependecies as they get resolved in the registry itself.
That said here is how to resolve the SDK with scoped access from the anybill-npm registry:
- Add a
.npmrc
file to the root directory of your project containing the following:
/anybill.jfrog.io/artifactory/api/npm/anybill_web_sdk/:_authToken = <AUTH_TOKEN>
email = youremail@email.com
always-auth = true
@anybill:registry = https://anybill.jfrog.io/artifactory/api/npm/anybill_web_sdk/
SECRET
This file should not be checked into version control!
- Now you can install modules via:
npm:
npm install @anybill/base
yarn:
yarn add @anybill/base
# Error handling
The anybill web SDK aims to provider the developer with easily understandable and catchable errors. The following two paragraphs introduce the used error model and how to work with it.
# Error object
The error object is based on the internal Error
object (opens new window). It has the following structure:
class AnybillError extends Error {
status: number;
timestamp: string;
path?: string;
details?: any;
}
/// Example error handling
async function getQRData() {
try {
const res = await AuthProvider.instance.getQRCodeData();
/// Present qr code to user
} catch (ex) {
const error = ex as AnybillError;
switch (error.status) {
case 400:
/// handle bad request error
break;
case 401:
/// refetch credentials
break;
case 500:
/// handle server error
break;
}
}
}
All errors thrown by the Anybill SDK methods are of type AnybillError
, making them easily parsable. The simplest way to handle specific errors is by checking the status
property, which reflects the API response code or 0
if the error occurs before a request is sent. For additional context on the error, refer to the details
parameter.
# Usage
# Initialization
To initialize the SDK with your clientId you must call the initialize
method from the ApiConfig
class. Furthermore this method allows you to change the api environment for testing puposes.
import { ApiConfig } from "@anybill/base";
ApiConfig.initialize(
"your-client_id",
ApiEnvironment.TEST_API_URL
);
# Authentication
To authenticate the anybill SDK you can link an anybill user to your user account by using the linked token user. For detailed instructions, refer to the Partner Platform API documentation.
- Get a token from the anybill Partner API by linking you account system to an anybill id.
- Login with the anybill sdk
import { AuthProvider } from "@anybill/base";
try {
await AuthProvider.instance.loginTokenUser(accessToken, refreshToken);
} catch (ex) {
const error = ex as AnybillError;
switch (error.status) {
case 400:
/// handle bad request error
break;
case 401:
/// refetch credentials
break;
case 500:
/// handle server error
break;
}
}
TIP
When using the Token Based Login you'll have to check for a failing Refresh Token Call on the first anybill API Call you invoke by catching a 401 error. When the error is triggered you'll have to retrieve new authentication information from the anybill Partner Platform API.

# Getting user information
After logging in an anybill user with the received token, user information can be acquired using following methods:
import { AuthProvider } from "@anybill/auth";
// User Model including id (anybill Id), externalId (usually your id) and more
const user = await AuthProvider.instance.getUserData();
// Data object which can be displayed as QR Code to receive receipts by scanning of the users device
const userQRCodeData = await AuthProvider.instance.getQRCodeData();
# Retrieving receipts
The anybill SDK offers two distinct approaches for fetching user receipts:
Direct API Access: Use the
ReceiptProvider.getReceipts()
method to directly access the API. This approach allows you to implement custom fetching and pagination logic based on your specific requirements.Optimized SDK Caching Process: Leverage the SDK's built-in caching and optimized pagination for efficient receipt retrieval by using the
initiateReceiptQuery()
andcontinueReceiptQuery()
methods. This approach simplifies the retrieval process and reduces the need for manual pagination handling.
Detailed information about both approaches is provided below:
Direct API Access
The getReceipts()
method allows you to retrieve user receipts with pagination support. The result includes the receipts, the total count of available receipts, and a continuation token that can be used to fetch subsequent batches.
You can customize the request with the following parameters:
take: Specifies the number of receipts to fetch in each batch. The default and maximum value is 100.
continuationToken: A nullable token used for paginating through the query results. If
null
, a new query is initiated. To continue fetching from the previous result, use thecontinuationToken
provided in the last response.orderBy: Specifies the field used for ordering the receipts. Currently, only
Date
is available.orderDirection: Defines the sort direction for the receipts, either
Ascending
orDescending
.
TIP
Important:
Due to database restrictions, you must specify the orderBy
and orderDirection
parameters for every page of the query.
Also, remember to reset the continuationToken
if you modify any query parameters.
try {
const continuationList = await ReceiptProvider.instance.getReceipts({
take: 100,
orderBy: UserReceiptOrderByFieldDto.Date,
orderDirection: OrderByDirectionDto.Descending,
});
/// handle receipts: continuationList.receipts
/// save continuation token to fetch the next batch of receitps: continuationList.continuationToken;
} catch (ex) {
/// handle error
}
Optimized SDK Caching Process
The anybill SDK offers an optimized receipt pagination process, providing efficient querying and display of receipts.
Similar to direct API access, you can customize the query with the following parameters:
- take: Specifies the number of receipts to retrieve in each batch, with a maximum of 100 by default.
- orderBy: Specifies the field for ordering receipts. Currently, only
Date
is supported. - orderDirection: Defines the sort direction for receipts, either
Ascending
orDescending
.
TIP
Note on Pagination and Sorting
The continuation token and query management are handled internally by the SDK, so there is no need for manual handling to load additional pages.
If you wish to change the sorting or direction of the receipt list, use the initiateReceiptQuery()
method again.
Fetch first page / Update receipt list
The initiateReceiptQuery
method resets any existing query. We recommend calling this method in the following scenarios to ensure an up-to-date receipt list:
Initial Display of Receipt List
When the receipt list is displayed for the first time in a session (e.g., when the user navigates to the receipt list view), this method should be called to display the latest receipt data.New Receipt Received
If a new receipt is issued while the user is in the app, the list should be refreshed upon notification of the new receipt (e.g., triggered by a webhook event). This ensures the receipt list reflects the latest transactions.Manual User Update
For scenarios where a user manually refreshes the list, such as through a "pull-to-refresh" gesture or a refresh button, use this method to re-fetch the latest data for the first page.Change in Sort Order
When changing the sorting parameters of the receipt list (e.g., switching the sort order), call this method with the new parameters. This will reset the cache to reflect the updated sorting criteria.
try {
const continuationList = await ReceiptProvider.instance.initiateReceiptQuery({
take: 100,
orderBy: UserReceiptOrderByFieldDto.Date,
orderDirection: OrderByDirectionDto.Descending,
});
/// handle receipts: continuationList.receipts
} catch (ex) {
/// handle error
}
Fetch next page
To retrieve the next batch of receipts in the existing query, use continueReceiptQuery()
. This method automatically applies the previously retrieved continuation token to fetch the subsequent set of receipts.
try {
const continuationList = await ReceiptProvider.instance.continueReceiptQuery();
/// handle receipts: continuationList.receipts
} catch (ex) {
/// handle error
}
Querying for single receipts by id can be achieved with the getReceiptByID
method of the ReceiptProvider
import { ReceiptsProvider } from "@anybill/base";
const singleReceipt = await ReceiptProvider.instance
.getReceiptByID("receipt-id");
# Downloading user receipts
The Receipt
utility has different methods of providing a PDF version of a receipt.
Following three functions are available and should be used according to your project setup:
import { ReceiptProvider } from "@anybill/base";
// best for client side use
const objectURL = await ReceiptProvider.instance
.getReceiptPDFasObjectURL(receiptId);
// flexible usage
const blob = await ReceiptProvider.instance
.getReceiptPDFasBlob(receiptId);
// best for server side use
const file = await ReceiptProvider.instance
.getReceiptPDFasFile(receiptId);
ObjectURL memory
ObjectURLs generated with getReceiptPDFasObjectURL
are not automagically revoked!
To do so use URL.revokeObjectURL
(opens new window) after using the URL.
File name
The File
returned by getReceiptPDFasFile
has a name with template:
`receipt-export_${new Date().toLocaleDateString()}.pdf`
# Deleting users receipts
Using the ReceiptProvider
utility you can delete either a single receipt or multiple receipts at once by calling following methods with the corresponding receiptIds.
import { ReceiptProvider } from "@anybill/base";
// Delete a single receipt
await ReceiptProvider.instance.deleteReceipt(receiptId);
// Delete multiple receipts at once
await ReceiptProvider.instance.deleteReceipts([receiptId1, receiptId2]);
# Mark a receipt as favourite
User receipts can be marked as favourite using following function:
import { ReceiptProvider } from "@anybill/base";
// Toggle isFavourite flag
await ReceiptProvider.instance.toggleIsFavourite(receiptId);
Receipt Model
Boolean value ReceiptDto.misc.isFavourite
determines whether a receipt is marked as favourite.
# Update receipt note
Using the ReceiptProvider.updateReceiptNote()
method, a custom note can be set for a receipt which can be retrieved in the ReceiptDto.Misc.Note
field.
This field can later on be used for querying and filtering the receipt list.
import { ReceiptProvider } from "@anybill/base";
// Update note flag
await ReceiptProvider.instance.updateReceiptNote(
receiptId,
note
);