Invoice a customer quickstart

View as Markdown

Learn how to send an invoice to a customer using the Tabs API. In this guide you’ll make a couple API calls and build a working example that you can adapt for your integration.

Get your API key

You can create an API key from the app. All requests require your key in the Authorization header.

Step 1: Create the customer

A customer in Tabs represents the business you’re billing. At minimum, provide a business name, but additional details are used in other workflows.

Create a customer using the POST /v3/customers endpoint, swapping in your API key:

$curl -X POST https://integrators.prod.api.tabsplatform.com/v3/customers
$ -H "Authorization: YOUR_API_KEY"
$ -H "Content-Type: application/json"
$ -d '{
> "name": "Acme Corp",
> "primaryBillingContactEmail": "jordan.lee@acme.com",
> "billingAddress": {
> "line1": "123 Main Street",
> "city": "San Francisco",
> "state": "CA",
> "postalCode": "94105",
> "country": "US"
> }
> }'

Customer creation is processed asynchronously. Look up the customer with a filtered GET /v3/customers call to retrieve its id:

$curl "https://integrators.prod.api.tabsplatform.com/v3/customers?filter=name:eq:Acme Corp&page=1&limit=50"
$ -H "Authorization: YOUR_API_KEY"
1{
2 "payload": {
3 "data": [
4 {
5 "id": "cust_abc123",
6 "name": "Acme Corp",
7 "defaultCurrency": "USD",
8 "primaryBillingContactEmail": "jordan.lee@acme.com",
9 "billingAddress": {
10 "line1": "123 Main Street",
11 "city": "San Francisco",
12 "state": "CA",
13 "postalCode": "94105",
14 "country": "US"
15 },
16 "lastUpdatedAt": "2025-01-15T12:00:00Z"
17 }
18 ],
19 "limit": 50,
20 "totalItems": 1,
21 "currentPage": 1
22 },
23 "success": true,
24 "message": "string",
25 "error": null
26}

Save the returned id — you’ll use it in subsequent steps.

Tabs can automatically create customers by syncing with your CRM or ERP. If the customers exist already, try the GET /v3/customers endpoint to retrieve a customer id.

Step 2: Create the contract

Every billing relationship in Tabs starts with a contract. A contract defines the billing arrangement with the customer. It also links the customer to a named agreement and serves as the container for any billing terms and schedules you attach later.

To create a contract (in Tabs) for a customer, call the POST /v3/contracts endpoint. Use your API key and the customer ID returned in Step 1.

$curl -X POST https://integrators.prod.api.tabsplatform.com/v3/contracts
$ -H "Authorization: YOUR_API_KEY"
$ -H "Content-Type: application/json"
$ -d '{
> "name": "Acme Corp — Services Agreement 2025",
> "customerId": "cust_abc123"
> }'

Tabs returns a response like:

1{
2 "id": "cont_xyz789",
3 "name": "Acme Corp — Services Agreement 2025",
4 "status": "ACTIVE",
5 "customerId": "cust_abc123",
6 "createdAt": "2025-01-15T12:05:00Z",
7 "lastUpdatedAt": "2025-01-15T12:05:00Z"
8}

Again, save the returned id, which represents the contract. The contract starts in an unprocessed state—it won’t generate invoices until you mark it as processed in Step 4.

Step 3: Add a billing term

A billing term defines what you’re charging, how much it costs, and how often. For a one-off invoice, create a billing term with isRecurring set to false. Tabs generates a single invoice for the full amount when you mark the contract as processed in Step 4.

Create the billing term on the contract by calling the POST /v3/contracts/{contractId}/billing-terms endpoint:

$curl -X POST https://integrators.prod.api.tabsplatform.com/v3/contracts/cont_xyz789/billing-terms
$ -H "Authorization: YOUR_API_KEY"
$ -H "Content-Type: application/json"
$ -d '{
> "name": "Professional Services — February 2025",
> "description": "One-time engagement fee for February deliverables",
> "billingStartDate": "2025-02-01",
> "isRecurring": false,
> "interval": "NONE",
> "intervalFrequency": 1,
> "invoiceDateStrategy": "FIRST_OF_PERIOD",
> "netPaymentTerms": 30,
> "quantity": 1,
> "billingType": "FLAT",
> "pricingType": "SIMPLE",
> "pricing": [
> {
> "tier": 1,
> "amount": 5000.00,
> "amountType": "TOTAL_INVOICE",
> "tierMinimum": 0
> }
> ]
> }'

Tabs returns a response like:

1{
2 "payload": {
3 "id": "bt_def456",
4 "contractId": "cont_xyz789",
5 "billingTermGroupId": "btg_001",
6 "name": "Professional Services — February 2025",
7 "billingStartDate": "2025-02-01",
8 "billingEndDate": "2025-02-01",
9 "isRecurring": false,
10 "billingType": "FLAT",
11 "pricingType": "SIMPLE",
12 "netPaymentTerms": 30,
13 "createdAt": "2025-01-15T12:10:00Z"
14 },
15 "success": true,
16 "message": "Billing term created successfully",
17 "error": null
18}

Step 4: Mark the contract as processed

Creating a billing term defines what to bill, but Tabs doesn’t generate the invoice until the contract is processed. Mark the contract as processed with the POST /v3/contracts/{contractId}/actions endpoint:

$curl -X POST https://integrators.prod.api.tabsplatform.com/v3/contracts/cont_xyz789/actions
$
$ -H "Authorization: YOUR_API_KEY"
$
$ -H "Content-Type: application/json"
$
$ -d '{"action": "MARK_AS_PROCESSED"}'

Tabs sets the contract status to PROCESSED and generates a draft invoice for the billing term. The invoice has an issueDate of 2025-02-01 and a dueDate 30 days later (2025-03-03), based on the netPaymentTerms you specified.

You can change an invoice while it’s in draft state.

Step 5: Send the invoice

The final step is to send the invoice to the customer. First, fetch the invoice to review its details. Use the customer ID to scope the lookup with a filtered GET /v3/invoices call:

$curl "https://integrators.prod.api.tabsplatform.com/v3/invoices?filter=customerId:eq:cust_abc123&page=1&limit=50"
$ -H "Authorization: YOUR_API_KEY"

Tabs returns a response like:

1{
2 "payload": {
3 "data": [
4 {
5 "id": "inv_ghi012",
6 "customerId": "cust_abc123",
7 "status": "DRAFT",
8 "issueDate": "2025-02-01",
9 "dueDate": "2025-03-03",
10 "total": 5000.00,
11 "balanceRemaining": 5000.00,
12 "lineItems": [
13 {
14 "id": "li_001",
15 "name": "Professional Services — February 2025",
16 "description": "One-time engagement fee for February deliverables",
17 "quantity": 1,
18 "unitPrice": 5000.00,
19 "total": 5000.00
20 }
21 ]
22 }
23 ],
24 "limit": 50,
25 "totalItems": 1,
26 "currentPage": 1
27 },
28 "success": true,
29 "message": "string",
30 "error": null
31}

When you’re ready to send the invoice, use the invoice actions endpoint to transition it from DRAFT to SENT. Sending is asynchronous, and at least one of sendToErp or sendToCustomer must be true:

$curl -X POST "https://integrators.prod.api.tabsplatform.com/v3/customers/cust_abc123/invoices/inv_ghi012/actions"
$ -H "Authorization: YOUR_API_KEY"
$ -H "Content-Type: application/json"
$ -d '{"action": "SEND", "sendToErp": true, "sendToCustomer": true}'

Tabs queues a background job and returns a job reference:

1{
2 "message": "Invoice send job created, jobId: 9f8b7c6d-1234-4a56-b789-0a1b2c3d4e5f, please check the job status via /jobs/9f8b7c6d-1234-4a56-b789-0a1b2c3d4e5f"
3}

Once the job completes, the invoice transitions from DRAFT to SENT. In a complete integration, you can set up payment options through Stripe and Plaid.

Next steps

From here, you can: