curl --request POST \
--url https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"fiscalYear": 2026,
"answers": [
{
"fieldId": "Q17",
"value": "1000000"
}
]
}
'import requests
url = "https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee"
payload = {
"fiscalYear": 2026,
"answers": [
{
"fieldId": "Q17",
"value": "1000000"
}
]
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({fiscalYear: 2026, answers: [{fieldId: 'Q17', value: '1000000'}]})
};
fetch('https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'fiscalYear' => 2026,
'answers' => [
[
'fieldId' => 'Q17',
'value' => '1000000'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee"
payload := strings.NewReader("{\n \"fiscalYear\": 2026,\n \"answers\": [\n {\n \"fieldId\": \"Q17\",\n \"value\": \"1000000\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"fiscalYear\": 2026,\n \"answers\": [\n {\n \"fieldId\": \"Q17\",\n \"value\": \"1000000\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"fiscalYear\": 2026,\n \"answers\": [\n {\n \"fieldId\": \"Q17\",\n \"value\": \"1000000\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"doolaCompanyId": "2Ns8vJqZ1lQwErTyUiOpAsDfGhJ",
"state": "WY",
"entityType": "LLC",
"fiscalYear": 2026,
"filingRequired": true,
"pricingType": "FIXED",
"needsInput": false,
"inputFieldIds": [
"Q16",
"Q17"
],
"amount": 202.35,
"currency": "USD",
"formula": "Assets: $1,000,000.00 x 0.0002",
"message": "Fixed state fee"
}Quote the annual report fee for a company
Returns what the company’s state charges for its annual report. Most states price from data doola already holds, so the amount comes back on the first call. Wyoming prices from asset figures only the customer knows: call this with no answers to be told which fields to collect, then call again with them. Nothing is stored and nothing is charged. Read filingRequired before amount: a state that files no annual report and one that files it free of charge both quote 0. Returns 404 when the company does not exist or is not owned by the calling partner.
curl --request POST \
--url https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"fiscalYear": 2026,
"answers": [
{
"fieldId": "Q17",
"value": "1000000"
}
]
}
'import requests
url = "https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee"
payload = {
"fiscalYear": 2026,
"answers": [
{
"fieldId": "Q17",
"value": "1000000"
}
]
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({fiscalYear: 2026, answers: [{fieldId: 'Q17', value: '1000000'}]})
};
fetch('https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'fiscalYear' => 2026,
'answers' => [
[
'fieldId' => 'Q17',
'value' => '1000000'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee"
payload := strings.NewReader("{\n \"fiscalYear\": 2026,\n \"answers\": [\n {\n \"fieldId\": \"Q17\",\n \"value\": \"1000000\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"fiscalYear\": 2026,\n \"answers\": [\n {\n \"fieldId\": \"Q17\",\n \"value\": \"1000000\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.test.doola.com/v1/partner/companies/{companyId}/compliance/annual-report/fee")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"fiscalYear\": 2026,\n \"answers\": [\n {\n \"fieldId\": \"Q17\",\n \"value\": \"1000000\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"doolaCompanyId": "2Ns8vJqZ1lQwErTyUiOpAsDfGhJ",
"state": "WY",
"entityType": "LLC",
"fiscalYear": 2026,
"filingRequired": true,
"pricingType": "FIXED",
"needsInput": false,
"inputFieldIds": [
"Q16",
"Q17"
],
"amount": 202.35,
"currency": "USD",
"formula": "Assets: $1,000,000.00 x 0.0002",
"message": "Fixed state fee"
}Authorizations
Partner API key. Send the raw key as the Authorization header value — e.g. dk_test_… in sandbox or dk_live_… in production. Generate and rotate keys in the doola Partner Portal.
Path Parameters
doola company ID (KSUID).
Body
Figures to price the annual report from. Every member is optional.
Fiscal year the quote is for. Echoed back unchanged; the state fee does not vary by year today.
2000 <= x <= 21002026
Answers to the fields a prior call named in inputFieldIds, each field at most once. A field the state does not price from is ignored. Omit to be told which fields are needed; send an empty list to declare them all zero.
Show child attributes
Show child attributes
Response
Either the fee, or the fields still to collect. needsInput says which; filingRequired says whether there is a report to file at all.
What the company's state charges for its annual report.
doola company ID (KSUID).
"2Ns8vJqZ1lQwErTyUiOpAsDfGhJ"
US state the report is filed in.
"WY"
Entity type the quote applies to.
LLC, CCorp "LLC"
Fiscal year the quote was requested for.
2026
Whether the state requires an annual report at all. False comes with an amount of 0 and pricingType NO_REPORT: nothing to file and nothing to pay. Do not read a 0 amount on its own - a FREE state also charges nothing, but the report still has to be filed.
true
How the state arrives at the fee. FIXED is a set amount, DYNAMIC is computed, FREE is filed at no charge, NO_REPORT means no report is filed.
FIXED, FREE, DYNAMIC, NO_REPORT "FIXED"
True when the state prices from figures the customer must declare and none were supplied. Collect the fields in inputFieldIds and call again.
false
Fields to collect before the fee can be quoted, null unless needsInput.
["Q16", "Q17"]
The state fee, null when needsInput. Zero when filingRequired is false, and zero for a FREE state that is filed at no charge.
202.35
Currency of the amount. Always USD; state fees are never billed in anything else.
USD "USD"
How the amount was arrived at, for states that compute it.
"Assets: $1,000,000.00 x 0.0002"
Plain-language note about the fee.
"Fixed state fee"