Calculating taxes and generating reports on behalf of your connected accounts

This guide demonstrates how to calculate taxes and generate tax reports on behalf of your connected accounts.
👩‍🎓
For demonstration purposes, we’ll build a home-rental marketplace that connects homeowners to people looking for a place to rent. You can use the concepts covered in this guide in other applications as well.

1. Creating a connected account

When a user (seller or service provider) signs up on your platform, create a user account (referred to as a connected account) so you can calculate sales tax on their behalf.
⇒ In our home-rental example, the connected account represents the homeowner.
The two different types of connected accounts are:
  • Standard account: A Quaderno account controlled directly by the account holder (i.e., your platform’s user). A user with a Standard account has a relationship with Quaderno, is able to log in to the Quaderno Dashboard, can manage taxes and transactions on their own, and can disconnect their account from your platform.
  • Custom account: This account is almost completely invisible to the account holder and Quaderno will have no direct contact with them. Custom accounts require the most integration effort and are suitable for platforms who want to control the entire user experience.
 
The process to create connected accounts varies depending on the account's type. You have more information in the following guides:

2. Setting up tax IDs

Before collecting taxes in any tax jurisdiction, users need to be registered with the jurisdiction's tax authorities and get a tax ID.
Quaderno uses the account's tax IDs to calculate the right tax rates.
 
⚠️
If you're using Standard accounts, each user will be responsible to set up their own tax IDs in their Quaderno account. But if you're using Custom accounts, then you need to provide your users the UI to set up their tax IDs via the API call shown here.
 
You can use our Tax ID API to create a tax ID on behalf of your connected accounts:
curl https://quadernoapp.com/api/tax_ids \
  -u {{YOUR_SECRET_KEY}}: \
  -d jurisdiction_id=99 \
  -d value=IE999999 \
  -H "Authorization: Bearer {{access_token}}"
You can also use the Tax ID API to set up your own Quaderno account taxes, by using your API Key instead your user's access_token.

3. Calculating tax rates

⇒ Every time the homeowner makes a sale, your platform must calculate the exact tax rate that needs to be applied to the transaction before taking the payment.
That tax rate is based on the customer's location (country and postal code) and the product's tax code.
 
You can use our Tax Rates API to calculate tax rates during the checkout process:
curl https://quadernoapp.com/api/tax_rates/calculate?to_country=US&to_postal_code=90210&tax_code=service \
  -H "Authorization: Bearer {{access_token}}"
The Tax Rates API can be used with a connected account or for your own account, depending on the wheter you're using the Authorization header or not.

4. Tracking sales & refunds

Every time your platform processes either a sale or a refund, you need to send the transaction's data to Quaderno in order to both issue invoices and credit notes, as well as generate tax reports.
Use our Transaction API to track all your sales and refunds in Quaderno:
curl https://quadernoapp.com/api/transactions \
  -u {{YOUR_SECRET_KEY}}: \
  -d type="sale" \
  -d currency="USD" \
  -d customer[id]=456987213 \ 
  -d items[0][description]="E-book" \
  -d items[0][amount]=9.99 \
  -d payment[method]="credit_card" \ 
  -d payment[processor]="stripe" \
  -d payment[processor_id]="ch_1IMFwhB2xq6voISLLk4I1KeE"  
  -H "Authorization: Bearer {{access_token}}"
A Transaction represents a paid sale or refund.
 
📌
To comply with tax legislations around the world, we highly recommend that you always send the location evidences with the evidence param, so that Quaderno can store those for you. Learn more in the API reference. It's also a good idea to use the processor parameter as kind of an "user-agent" to help us track any issues, as well as processor_id and po_number so that you can match API calls with your own platform transactions and Product Orders in the future.
 
Open this toggle to see an example response as reference
💡
Store the returned document's id in your database. It'll help you connect transactions and documents.
{
  "id": 1975799,
  "contact": {
    "id": 1223359,
    "city": null,
    "country": "ES",
    "created_at": 1622457526,
    "email": null,
    "first_name": "Alba",
    "full_name": "Alba Pozo",
    "kind": "person",
    "language": "ES",
    "last_name": "Pozo",
    "notes": null,
    "permalink": "http://your-sandbox-url.sandbox-quadernoapp.com/billing/b8ff2e93df81d939b9c88f6ae9878cb8c6653e2a?otp=813451",
    "phone_1": null,
    "postal_code": null,
    "processor": null,
    "processor_id": null,
    "region": null,
    "street_line_1": null,
    "street_line_2": null,
    "tax_id": null,
    "web": null
  },
  "created_at": 1622457526,
  "currency": "EUR",
  "custom_metadata": {
    "prueba": "ssss"
  },
  "discount_cents": 0,
  "issue_date": "2021-05-31",
  "items": [
    {
      "id": 5848824,
      "created_at": 1622457526,
      "description": "pizza",
      "discount_cents": 0,
      "discount_rate": 0.0,
      "product_code": null,
      "quantity": 1.0,
      "subtotal_cents": 907,
      "tax_code": "standard",
      "tax_country": "US",
      "tax_name": "Sales tax",
      "tax_rate": 10.25,
      "tax_region": "CA",
      "taxable_part": "100.0",
      "total_amount_cents": 1000,
      "unit_price": 9.07
    }
  ],
  "notes": null,
  "number": "00002",
  "payments": [
    {
      "id": 1380030,
      "amount_cents": 1000,
      "created_at": 1622457527,
      "date": "2021-05-31",
      "payment_method": "credit_card",
      "processor": null,
      "processor_id": null
    }
  ],
  "pdf": "http://sandbox-quadernoapp.com/invoice/06484c5cf93cf877aa850629c58b3e4207270560.pdf?otp=813451&q=1622457527",
  "permalink": "http://sandbox-quadernoapp.com/invoice/06484c5cf93cf877aa850629c58b3e4207270560?otp=813451&q=1622457527",
  "po_number": "AAAA",
  "processor": null,
  "processor_id": null,
  "state": "paid",
  "subtotal_cents": 907,
  "tags": "a, b, c",
  "taxes": [
    {
      "amount_cents": 93,
      "country": "US",
      "label": "Sales tax (10.25%)",
      "rate": 10.25,
      "region": "CA",
      "tax_code": "standard"
    }
  ],
  "total_cents": 1000,
  "type": "Invoice"
}

5. Generating tax reports

Every quarter (or every month), the homeowner will need to file taxes in all the jurisdictions they're registered. Quaderno can help generating tax reports with all the information needed.
Our Reporting API works asynchronously. This means you'll create a Request object, and then you'll be able to get the report when it's ready with the Request ID provided:
# Making a report request:
curl https://quadernoapp.com/api/reporting/requests \
  -u {{YOUR_SECRET_KEY}}: \
  -H "Authorization: Bearer {{access_token}}"
  -d report_type="tax_summary" \
  -d parameters[from_date]="2021-05-01" \
  -d parameters[from_date]="2021-05-31"

			# Quaderno will respond to that curl with:
			{
			  "id": 456987213, # Use this Request ID to get the Report when it's ready
			  "completed_at": 1612351337,
			  "created_at": 1612351337,
			  "parameters": {
			    "from_date": "2021-05-01",
			    "to_date": "2021-05-31"
			  },
			  "report_type": "tax_summary",
			  "report_url": null,
			  "state": "succeeded"
			}
		
# Finally, get the Report with:
curl https://quadernoapp.com/api/reporting/requests/REQUEST_ID \
  -u {{YOUR_SECRET_KEY}}: \
  -H "Authorization: Bearer {{access_token}}"
 
To avoid polling, we recommend subscribing to our reporting.request.suceeded webhook event, like so:
curl https://quadernoapp.com/api/webhooks \
  -u {{YOUR_SECRET_KEY}}: \
  -H "Authorization: Bearer {{access_token}}" \
  -d url="http://homeowner-app.com/notifications" \
  -d event_types[]="reporting.request.suceeded" \
  -d event_types[]="reporting.request.failed" \
Subscribing to Reporting Requests Example. Check Creating webhooks guide and event types for more info.