Tax Payment Walkthrough

Money will not be submitted to the tax authority in your sandbox environment, so it’s the best way to test your integration before going to production. You can force a Quarterly Tax Payment to resolve to a specific status in your sandbox environment to test various scenarios by passing the amount specified in the testing in the sandbox environment guide. This is especially useful when testing Webhooks for different statuses.

There are three steps to create your first Quarterly Tax Payment:

1. Create a User

A User is the individual for whom you will be submitting the tax payment. To create a User, you can follow the Creating a User guide.

2. Create a Payment Method

❗️

KYC verification required

When creating a paymentMethod in Abound, you are certifying that you have verified the owner of the account by adhering to federal KYC requirements. Reach out to Abound support if you have any questions.

A Payment Method represents the bank account from which the tax payment will be charged. For taxPayments to the IRS, Payment Method can be any checking or savings account that has routing and account numbers and supports ACH.

However, for taxPayments submitted to an individual state the Payment Method must be a checking account that supports digital checks.

Below is an example of how to create a Payment Method that is associated with the user you created in the previous step.

📘

paymentMethod for Tax Payments

IRS Tax Payments may come from a paymentMethod whose "accountClass" is either "checking" or "savings"

State Quarterly Tax Payments must be associated with a paymentMethod whose "accountClass" is "checking".

curl \
  --request POST \
  --url https://sandbox-api.withabound.com/v2/users/<<testUserId>>/paymentMethods \
  --header 'Authorization: Bearer <<apiKey>>' \
  --header 'Content-Type: application/json' \
  --data '{
    "paymentMethod": {
      "accountNumber": "1234567890",
      "routingNumber": "121042882",
      "accountType": "personal",
      "accountClass": "checking"
    }
  }'
const { default: Abound, Environment } = require("@withabound/node-sdk");

const abound = new Abound({
  appId: "<<sandbox_app_id>>",
  appSecret: "<<sandbox_app_secret>>",
  environment: Environment.SANDBOX,
  apiVersion: "v2",
});

(async () => {
  const response = await abound.paymentMethods.create(
    "<<testUserId>>",
    {
      accountNumber: "1234567890",
      routingNumber: "121042882",
      accountType: "personal",
      accountClass: "checking",
    }
  );

  console.log(response);
})();
import requests

url = "https://sandbox-api.withabound.com/v2/users/<<testUserId>>/paymentMethods"

payload = {"paymentMethod": {
        "accountNumber": "1234567890",
        "routingNumber": "121042882",
        "accountType": "personal",
        "accountClass": "checking"
    }}
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer <<apiKey>>"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
// import com.squareup.okhttp.*;
// import com.google.gson.JsonObject;

OkHttpClient client = new OkHttpClient();

JsonObject requestBody = new JsonObject();
JsonObject paymentMethod = new JsonObject();

paymentMethod.addProperty("accountNumber", "1234567890");
paymentMethod.addProperty("routingNumber", "121042882");
paymentMethod.addProperty("accountType", "personal");
paymentMethod.addProperty("accountClass", "checking");

requestBody.add("paymentMethod", paymentMethod);

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, requestBody.toString());
Request request = new Request.Builder()
  .url("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/paymentMethods")
  .post(body)
  .addHeader("Accept", "application/json")
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer <<apiKey>>")
  .build();

Response response = client.newCall(request).execute();
package main

import (
    "bytes"
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://sandbox-api.withabound.com/v2/users/<<testUserId>>/paymentMethods"

    var requestBody = []byte(`{
        "paymentMethod": {
            "accountNumber": "1234567890",
            "routingNumber": "121042882",
            "accountType": "personal",
            "accountClass": "checking"
        }
    }`)

    req, _ := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))

    req.Header.Add("Accept", "application/json")
    req.Header.Add("Content-Type", "application/json")
    req.Header.Add("Authorization", "Bearer <<apiKey>>")

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}
// using RestSharp;

var client = new RestClient("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/paymentMethods");
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer <<apiKey>>");
request.AddJsonBody(new {
  paymentMethod = new {
    accountNumber = "1234567890",
    routingNumber = "121042882",
    accountType = "personal",
    accountClass = "checking"
  }
});
IRestResponse response = client.Execute(request);
require 'uri'
require 'net/http'
require 'openssl'
require 'json'

url = URI("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/paymentMethods")
requestBody = {
  paymentMethod: {
    accountNumber: '1234567890',
    routingNumber: '121042882',
    accountType: 'personal',
    accountClass: 'checking'
  }
}

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Accept"] = 'application/json'
request["Content-Type"] = 'application/json'
request["Authorization"] = 'Bearer <<apiKey>>'
request.body = requestBody.to_json

response = http.request(request)
puts response.read_body

3. Create a Quarterly Tax Payment

The Quarterly Tax Payment represents the actual submission of money from the Payment Method to the IRS (or other government entity) on behalf of a User.

Determine the appropriate Tax Payment amount to submit as a Quarterly Tax Payment is easy by using the Taxes endpoint.

Submitting a Federal Tax Payment

Below is an example of the creation of a Quarterly Tax Payment for the User, where the funds are pulled from the Payment Method returned in the previous step and designated by the paymentMethodId.

curl \
  --request POST \
  --url https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments \
  --header 'Authorization: Bearer <<apiKey>>' \
  --header 'Content-Type: application/json' \
  --data '{
    "taxPayment": {
      "amount": 87.34,
      "period": "Q2",
      "year": "2020",
      "entity": "IRS",
      "paymentMethodId": "<<testPaymentMethodId>>"
    }
  }'
const { default: Abound, Environment } = require("@withabound/node-sdk");

const abound = new Abound({
  appId: "<<sandbox_app_id>>",
  appSecret: "<<sandbox_app_secret>>",
  environment: Environment.SANDBOX,
  apiVersion: "v2",
});

(async () => {
  const response = await abound.taxPayments.create(
    "<<testUserId>>",
    {
      amount: 87.34,
      period: "Q2",
      year: "2020",
      entity: "IRS",
      paymentMethodId:
        "<<testPaymentMethodId>>",
    }
  );

  console.log(response);
})();
import requests

url = "https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments"

payload = {"taxPayment": {
        "amount": 87.34,
        "period": "Q2",
        "year": "2020",
        "entity": "IRS",
        "paymentMethodId": "<<testPaymentMethodId>>"
    }}
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer <<apiKey>>"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
// import com.squareup.okhttp.*;
// import com.google.gson.JsonObject;

OkHttpClient client = new OkHttpClient();

JsonObject requestBody = new JsonObject();
JsonObject taxPayment = new JsonObject();

taxPayment.addProperty("amount", 87.34);
taxPayment.addProperty("period", "Q2");
taxPayment.addProperty("year", "2020");
taxPayment.addProperty("entity", "IRS");
taxPayment.addProperty("paymentMethodId", "<<testPaymentMethodId>>");

requestBody.add("taxPayment", taxPayment);

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, requestBody.toString());
Request request = new Request.Builder()
  .url("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments")
  .post(body)
  .addHeader("Accept", "application/json")
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer <<apiKey>>")
  .build();

Response response = client.newCall(request).execute();
package main

import (
    "bytes"
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments"

    var requestBody = []byte(`{
        "taxPayment": {
            "amount": 87.34,
            "period": "Q2",
            "year": "2020",
            "entity": "IRS",
            "paymentMethodId": "<<testPaymentMethodId>>"
        }
    }`)

    req, _ := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))

    req.Header.Add("Accept", "application/json")
    req.Header.Add("Content-Type", "application/json")
    req.Header.Add("Authorization", "Bearer <<apiKey>>")

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}
// using RestSharp;

var client = new RestClient("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments");
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer <<apiKey>>");
request.AddJsonBody(new {
  taxPayment = new {
    amount = 87.34,
    period = "Q2",
    year = "2020",
    entity = "IRS",
    paymentMethodId = "<<testPaymentMethodId>>"
  }
});
IRestResponse response = client.Execute(request);
require 'uri'
require 'net/http'
require 'openssl'
require 'json'

url = URI("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments")
requestBody = {
  taxPayment: {
    amount: 87.34,
    period: 'Q2',
    year: '2020',
    entity: 'IRS',
    paymentMethodId: '<<testPaymentMethodId>>'
  }
}

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Accept"] = 'application/json'
request["Content-Type"] = 'application/json'
request["Authorization"] = 'Bearer <<apiKey>>'
request.body = requestBody.to_json

response = http.request(request)
puts response.read_body

Submitting a State Tax Payment

Submitting a tax payment for a specific state is as simple as passing the two-character state code in the entity field. The following code snippet provides an example of how to initiate a tax payment to California (notice the "entity": "CA").

❗️

State Tax Payment amount

State tax payments require passing the amount as a whole number.

curl \
  --request POST \
  --url https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments \
  --header 'Authorization: Bearer <<apiKey>>' \
  --header 'Content-Type: application/json' \
  --data '{
    "taxPayment": {
      "amount": 877,
      "period": "Q3",
      "year": "2020",
      "entity": "CA",
      "paymentMethodId": "<<testPaymentMethodId>>"
    }
  }'
const { default: Abound, Environment } = require("@withabound/node-sdk");

const abound = new Abound({
  appId: "<<sandbox_app_id>>",
  appSecret: "<<sandbox_app_secret>>",
  environment: Environment.SANDBOX,
  apiVersion: "v2",
});

(async () => {
  const response = await abound.taxPayments.create(
    "<<testUserId>>",
    {
      amount: 877,
      period: "Q3",
      year: "2020",
      entity: "CA",
      paymentMethodId:
        "<<testPaymentMethodId>>",
    }
  );

  console.log(response);
})();
import requests

url = "https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments"

payload = {"taxPayment": {
        "amount": 877,
        "period": "Q3",
        "year": "2020",
        "entity": "CA",
        "paymentMethodId": "<<testPaymentMethodId>>"
    }}
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer <<apiKey>>"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
// import com.squareup.okhttp.*;
// import com.google.gson.JsonObject;

OkHttpClient client = new OkHttpClient();

JsonObject requestBody = new JsonObject();
JsonObject taxPayment = new JsonObject();

taxPayment.addProperty("amount", 877);
taxPayment.addProperty("period", "Q3");
taxPayment.addProperty("year", "2020");
taxPayment.addProperty("entity", "CA");
taxPayment.addProperty("paymentMethodId", "<<testPaymentMethodId>>");

requestBody.add("taxPayment", taxPayment);

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, requestBody.toString());
Request request = new Request.Builder()
  .url("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments")
  .post(body)
  .addHeader("Accept", "application/json")
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer <<apiKey>>")
  .build();

Response response = client.newCall(request).execute();
package main

import (
    "bytes"
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments"

    var requestBody = []byte(`{
        "taxPayment": {
            "amount": 877,
            "period": "Q3",
            "year": "2020",
            "entity": "CA",
            "paymentMethodId": "<<testPaymentMethodId>>"
        }
    }`)

    req, _ := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))

    req.Header.Add("Accept", "application/json")
    req.Header.Add("Content-Type", "application/json")
    req.Header.Add("Authorization", "Bearer <<apiKey>>")

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}
// using RestSharp;

var client = new RestClient("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments");
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer <<apiKey>>");
request.AddJsonBody(new {
  taxPayment = new {
    amount = 877,
    period = "Q3",
    year = "2020",
    entity = "CA",
    paymentMethodId = "<<testPaymentMethodId>>"
  }
});
IRestResponse response = client.Execute(request);
require 'uri'
require 'net/http'
require 'openssl'
require 'json'

url = URI("https://sandbox-api.withabound.com/v2/users/<<testUserId>>/taxPayments")
requestBody = {
  taxPayment: {
    amount: 877,
    period: 'Q3',
    year: '2020',
    entity: 'CA',
    paymentMethodId: '<<testPaymentMethodId>>'
  }
}

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Accept"] = 'application/json'
request["Content-Type"] = 'application/json'
request["Authorization"] = 'Bearer <<apiKey>>'
request.body = requestBody.to_json

response = http.request(request)
puts response.read_body

4. Monitor a Tax Payment

After your tax payment has been submitted, Abound uses webhooks to inform your backend when the tax payment has been updated. Read our Webhooks guide to learn more.


Did this page help you?