Send your first invoice
SLTax360 files surplus lines tax for the policies your system writes.
- You send each policy transaction from your system: a new policy, a renewal, an endorsement or a cancellation.
- We prepare and submit the state filing. The licensed broker stays responsible for the filing.
- You start small. Six fields are enough for the first call. Add more data later.
You need an API key. It looks like sltax_t2_ followed by 32 letters and digits. If you do not have one, get a free test key: our team sets up a separate test account for you. Put your key in an environment variable called SLTAX_API_KEY, so it stays out of your code.
curl https://api.sltax360.com/api/v1/auth/me \
-H "Authorization: Bearer $SLTAX_API_KEY"
A 200 reply with your key name and tier means the key works. A 401 means the key is missing or wrong.
curl -X POST https://api.sltax360.com/api/v1/invoices \
-H "Authorization: Bearer $SLTAX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"policy_number": "DEMO-0001",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"net_premium": 12500.00,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01"
}'
The reply is 201 Created. Your ids and times will be different:
{
"success": true,
"data": {
"id": 12832,
"policy_number": "DEMO-0001",
"invoice_number": null,
"invoice_date": "2026-10-01",
"insured_name": "Harbor Point Marine LLC",
"state": { "id": 45, "code": "TX", "name": "Texas" },
"type": { "id": 1, "name": "New" },
"lob": null,
"net_premium": 12500,
"commission": null,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01",
"status": "new",
"filed": false,
"paid": false,
"created": "2026-09-23 11:55:21",
"company": null,
"policy_id": 6909,
"policy_fee": 0,
"stamps_fee": 0,
"service_fee": 0,
"notes": null,
"fees": [],
"coverages": [],
"insurers": [],
"documents": []
},
"meta": {
"timestamp": "2026-09-23T16:55:21Z",
"request_id": "req_070f04a750ae11ebefd69589",
"response_time_ms": 9
}
}
data.id: you use it to read the status and to add documents.
Idempotency-Key. Do your tests on a test account: get a free test key. To check a body without storing anything, send it to POST /api/v1/invoices/preview. If a create times out, check first with GET /api/v1/invoices?policy_number=DEMO-0001 before you send it again. That list shows every transaction on the policy, so compare the type, effective_date and net_premium.
The integration ladder
Climb only as far as you need. Each step works on its own.
| Step | What you do | What you get |
|---|---|---|
| 0. Hello | GET /auth/me with your key. |
Proof that the key works, with its tier and rate limit. |
| 1. First invoice | POST /invoices with the 6 required fields. |
201 with an invoice id. Our team does the rest. |
| 2. Send what you have | Add the address, coverages, insurers, fees and documents. See Step 2. | Fewer questions from our team before we can file. |
| 3. Use our lists | Read our reference lists (states, lines of business, coverages, fee types, document types, company search) and send our exact codes and ids. | Fewer codes for our team to match by hand. The lists change rarely, so you can cache them. |
| 4. Go further | POST /invoices/preview before you create, GET /invoices/{id} for status, PUT /invoices/{id}/documents/{docUUID} for late documents, POST /invoices/batch for bulk. |
Checks before you send, status read back, and bulk sends (Premium tier). |
First invoice in your language
Each example sends the same 6-field invoice and prints the new invoice id. They all read your key from SLTAX_API_KEY.
curl -X POST https://api.sltax360.com/api/v1/invoices \
-H "Authorization: Bearer $SLTAX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"policy_number": "DEMO-0001",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"net_premium": 12500.00,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01"
}'
const response = await fetch("https://api.sltax360.com/api/v1/invoices", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SLTAX_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
policy_number: "DEMO-0001",
insured_name: "Harbor Point Marine LLC",
state_code: "TX",
net_premium: 12500.00,
effective_date: "2026-10-01",
expiration_date: "2027-10-01",
}),
});
const result = await response.json();
if (response.status === 201) {
console.log("Created invoice", result.data.id, "status:", result.data.status);
} else {
console.error(response.status, result.error.message, JSON.stringify(result.error.details));
}
import os
import requests
response = requests.post(
"https://api.sltax360.com/api/v1/invoices",
headers={"Authorization": f"Bearer {os.environ['SLTAX_API_KEY']}"},
json={
"policy_number": "DEMO-0001",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"net_premium": 12500.00,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01",
},
timeout=30,
)
result = response.json()
if response.status_code == 201:
print("Created invoice", result["data"]["id"], "status:", result["data"]["status"])
else:
print(response.status_code, result["error"]["message"], result["error"].get("details"))
<?php
$payload = [
'policy_number' => 'DEMO-0001',
'insured_name' => 'Harbor Point Marine LLC',
'state_code' => 'TX',
'net_premium' => 12500.00,
'effective_date' => '2026-10-01',
'expiration_date' => '2027-10-01',
];
$ch = curl_init('https://api.sltax360.com/api/v1/invoices');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SLTAX_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$result = json_decode($body, true);
if ($status === 201) {
echo "Created invoice {$result['data']['id']} status: {$result['data']['status']}\n";
} else {
echo "$status {$result['error']['message']}\n";
echo json_encode($result['error']['details'] ?? null), "\n";
}
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("SLTAX_API_KEY"));
var payload = """
{
"policy_number": "DEMO-0001",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"net_premium": 12500.00,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01"
}
""";
var response = await client.PostAsync(
"https://api.sltax360.com/api/v1/invoices",
new StringContent(payload, Encoding.UTF8, "application/json"));
var body = await response.Content.ReadAsStringAsync();
using var json = JsonDocument.Parse(body);
if ((int)response.StatusCode == 201)
{
var data = json.RootElement.GetProperty("data");
Console.WriteLine($"Created invoice {data.GetProperty("id")} status: {data.GetProperty("status")}");
}
else
{
Console.WriteLine($"{(int)response.StatusCode} {body}");
}
Step 2: send what you have
All of these fields are optional. Send the ones your system has. The more you send, the less our team must ask you.
| Field | What it is | Rule |
|---|---|---|
policy_number | Your policy number (required). | Send the same policy_number on every transaction of a policy: the new policy, each endorsement and the cancellation. That is how we link them. |
type_code | The kind of transaction. | Exactly NEW, RENEWAL, ENDORSEMENT or CANCELLATION, in capitals. NEW if you leave it out. Any other value is an error. Audits, reinstatements and rewrites cannot be sent through the API yet. |
insured_address | Where the risk is: line1, line2, city, zip. | The state comes from state_code. type_id is 2 (garaging, the default) or 1 (billing). |
coverages[] | Each coverage: code and amount (its premium). | Codes differ by state, and GET /coverages does not show each code's state yet. Check your codes for a state with POST /invoices/preview. Our list does not have codes for every state: if no code fits, send your own code and a title. If you also send limits[], their premium values must add up to amount. |
insurers[] | The insurance companies: company_id and percent or amount. | company_id is our id. Find it with GET /companies/search?q= and a name or NAIC code. One insurer with no percent means 100%. |
lob_id | Line of business. | Our id from GET /lobs. An unknown id is an error, so leave it out if you are not sure. |
fees[] | Fees and taxes you billed: type and amount. | Up to 25 items. Codes from GET /reference/fee-types. Create does not calculate the tax. Send the tax you billed as items too, with the code that preview returns in tax_calculation.line_items[].code (for example sl_tax and stamping_fee). To work the figures out first, use POST /invoices/preview. |
invoice_number, invoice_date | Your own invoice reference and date. | invoice_date is the effective date if you leave it out. |
commission, policy_limit, class_code | Extra policy details. | Optional. policy_limit cannot be negative. If we hold no such class_code for the state, create stores the invoice without it and returns a warning. Preview does not check class codes yet. |
documents[] | Files such as the declarations page: type and docUUID. | A reference to a file in your own document store, not the file itself. Up to 10 per request. Talk to us first, because we must connect to your document store. |
Endorsements and cancellations
- Send the same
policy_numberas the original policy, withtype_codeENDORSEMENTorCANCELLATION. - Send the date the change takes effect as
effective_date, and the policy's expiration date asexpiration_date. The state filing useseffective_dateas the date of the change. - Known limit today: the API has one date pair, so the stored policy record takes these dates, and its start date then shows the date of the change. On accounts with the new features, send the policy term instead, and the date of the change in
transaction_effective_date. - Every amount is the amount of the change, not the policy total:
net_premium, coverage amounts, insurer amounts and the tax you billed on the change. Amounts that return premium are negative. - Use preview to work out the tax on the change. Unlike the calculator,
POST /invoices/previewaccepts negative amounts and returns negative tax lines for a return of premium. - On read-back,
type.nameisNew,Renewal,EndorsementorCancelled.
{
"policy_number": "DEMO-0002",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"type_code": "ENDORSEMENT",
"net_premium": 1200.00,
"effective_date": "2027-01-15",
"expiration_date": "2027-10-01",
"coverages": [
{ "code": "9334", "amount": 1200.00 }
],
"insurers": [
{ "company_id": 167, "percent": 100 }
],
"fees": [
{ "type": "sl_tax", "amount": 58.20 },
{ "type": "stamping_fee", "amount": 0.48 }
]
}
A cancellation has the same shape, with "type_code": "CANCELLATION" and negative amounts, for example "net_premium": -6250.00.
{
"policy_number": "DEMO-0002",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"type_code": "NEW",
"net_premium": 12500.00,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01",
"insured_address": {
"line1": "100 Harbor Drive",
"city": "Galveston",
"zip": "77550"
},
"coverages": [
{ "code": "9334", "amount": 12500.00 }
],
"insurers": [
{ "company_id": 167, "percent": 100 }
],
"fees": [
{ "type": "policy_fee_company", "amount": 150.00 }
]
}
The company_id above is only an example. Ids belong to your account, so always look them up with GET /companies/search.
POST /invoices/preview: it lists each unknown code in validation.errors.
Features on new accounts
These features are optional, and we switch them on per account. New integrations can ask for them when they request a key. On an account without them, the API ignores the extra fields and the header, exactly as described above.
| Feature | What you send | What you get |
|---|---|---|
| Safe retries | An Idempotency-Key header on POST /invoices: your own id for this request, up to 255 characters, no spaces. | The same key and the same body within 24 hours return the first 201 again, with the header Idempotent-Replayed: true. No second invoice. The same key with a different body is a 409. A 422 does not use up the key. |
| Carrier by NAIC or name | insurers[].naic or insurers[].company_name instead of company_id (also inside groups by line of business). | We find the company for you. A company_id, when sent, always wins. No match is a 422 that names the value we looked for. |
| Line of business by name | lob_name, for example "General Liability", when you do not send lob_id. | We find the line of business. An unknown name is not an error: the invoice is stored without one, and warnings says so. |
| Transaction date | transaction_effective_date (YYYY-MM-DD) on an endorsement or cancellation. Keep effective_date and expiration_date as the policy term. | We store it as the date of the change, and the policy keeps its real term. The reply shows transaction_effective_date. |
| The state's answer | Nothing extra: call GET /api/v1/invoices/{id}. | A filing object: state_status (not_sent, sent, accepted, confirmed, rejected or refused), updated_at, confirmation_number, submission_number, and message with the reason for a rejection. The latest answer counts. |
| Coverage warnings | Nothing extra. | warnings lists each coverage code that we could not match, so you can fix your codes. |
curl -X POST https://api.sltax360.com/api/v1/invoices \
-H "Authorization: Bearer $SLTAX_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: DEMO-0001-new-2026-10-01" \
-d '{
"policy_number": "DEMO-0001",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"net_premium": 12500.00,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01"
}'
{
"policy_number": "DEMO-0002",
"insured_name": "Harbor Point Marine LLC",
"state_code": "TX",
"type_code": "ENDORSEMENT",
"net_premium": 1200.00,
"effective_date": "2026-10-01",
"expiration_date": "2027-10-01",
"transaction_effective_date": "2027-01-15",
"lob_name": "General Liability",
"coverages": [
{ "code": "9334", "amount": 1200.00 }
],
"insurers": [
{ "naic": "19437", "percent": 100 }
],
"fees": [
{ "type": "sl_tax", "amount": 58.20 },
{ "type": "stamping_fee", "amount": 0.48 }
]
}
"filing": {
"state_status": "not_sent",
"updated_at": null,
"confirmation_number": null,
"submission_number": null,
"message": null,
"api_error": null
}
Common errors and the fix
These are the errors partners really hit, taken from our request log. A 422 reply lists the problems in error.details.fields. Insurer and coverage errors are listed under insurers or coverages, and the message names the item, for example insurers[0].
| Message | What it means | The fix |
|---|---|---|
insurers[0].amount is required and must be a number | You grouped insurers by line of business (lob with companies), and a group has no amount. | Add amount to every group. |
Sum of insurers LOB amounts (10000) does not equal net_premium (12500) | The group amounts do not add up to the premium. | Make the group amount values add up to net_premium (1 cent tolerance). |
coverages[0] (GL): amount 12500.00 does not equal the sum of its limits[].premium (10000.00) | You sent limits[], and their premiums do not add up to the coverage amount. | Make them add up, or leave out limits[] and send amount only. |
insurers[0].company_id is required and must be an integer | An insurer has no company id. | Look up the id with GET /companies/search?q= and the company name or NAIC code. |
Must be one of: NEW, RENEWAL, ENDORSEMENT, CANCELLATION | type_code is not one of the four values, or not in capitals. | Send one of the four values exactly, or leave it out for NEW. |
Referenced line_of_businesses not found | lob_id is not one of our ids. | Use an id from GET /lobs, or leave lob_id out. |
Must be a valid date | A date is not in YYYY-MM-DD form. | Send dates like 2026-10-01. |
Must be a valid state_code | state_code is not a US state. | Send the 2-letter code, for example TX. DC is also accepted. |
This field is required | One of the 6 required fields is missing. | Send policy_number, insured_name, state_code, net_premium, effective_date and expiration_date. |
On POST /invoices/preview, problems with the data itself come back in a 200 reply, inside validation.errors. The most common ones:
| Preview message | What it means | The fix |
|---|---|---|
State PA is not supported for filing | Your account has no direct electronic filing for this state. | Nothing is wrong with your data. POST /invoices still accepts it. Ask us how we file that state for you. |
Net premium cannot be zero | The premium is 0. | Send the real premium. POST /invoices does not block a zero premium, so check it on your side. |
Coverage code 'GL' not found for state TX | The code is not in our coverage list for that state. | Use a code from GET /coverages. Our list does not have codes for every state; if none fits, send your own code and a title. See the note in Step 2. |
What happens after you send
- The invoice is stored in your SLTax360 account. Our team reviews it and fills any gaps.
- We prepare and submit the state filing. Direct electronic filing exists in 25+ states. In other states we prepare the filing for the state's own process. The licensed broker stays responsible for the filing.
- You read the status with
GET /api/v1/invoices/{id}:status:new,sent,success,errororre-submitted.filed:trueonce the status issent,successorre-submitted.paid: alwaysfalsetoday. Do not use it yet.created: server time, US Central, without a time zone in the value.
GET /api/v1/invoices/{id} also returns filing with the state's confirmation number or the reason for a rejection. On other accounts these are not returned (ask us, with the invoice id). Not available yet: webhooks (we do not call you when the status changes) and a list of class codes. Read the status on a schedule, for example once a day. For tests, use a free test account, or POST /invoices/preview, which stores nothing (it still counts toward your hourly limit).
Words you will see
You do not need to know insurance to connect. These are the terms the API uses.
- Surplus lines
- Insurance from a company that is not licensed in the state. It is allowed for risks that licensed companies do not cover. The state taxes it, and each policy must be filed with the state.
- Admitted insurer
- An insurance company that is licensed in the state. Its policies do not need a surplus lines filing.
- Premium
- The price of the policy. In the API:
net_premium. - Endorsement
- A change to a policy during its term, for example a new vehicle. It can add premium or return premium (a negative amount). Send it with
type_codeENDORSEMENT. - Renewal and cancellation
- A renewal is the next term of a policy (
RENEWAL). A cancellation ends a policy early and usually returns premium (CANCELLATION). - NAIC code
- A 5-digit number that identifies an insurance company in the US. Use it to find our
company_idwithGET /companies/search. - Stamping fee
- A small fee that some states charge on top of the tax. It pays for the state office that checks the filings.
- Line of business
- The kind of insurance, for example general liability or commercial auto. In the API:
lob_id, fromGET /lobs. - Coverage code
- A short code for one coverage in the policy. States use it to see what was insured. Codes differ by state.
Tools
- Interactive reference: Swagger UI. Click Authorize, paste your key, then use Try it out. Every call there is real.
- OpenAPI 3.0 spec: openapi.json, to generate a client in your language.
- Postman collection: sltax360-api.postman_collection.json. It follows the ladder above. Set
api_keybefore you run it. - Help: email support@sltax360.com with the
request_idfrom the reply.
Authentication
Send your API key as a Bearer token in the Authorization header of every request.
Authorization: Bearer sltax_t2_your_api_key_here
Key format and tiers
A key is sltax_, then the tier (t1, t2 or t3), then 32 lowercase letters and digits. Our team issues keys. POST /auth/token only checks a key; it does not create one. Your key also decides which SLTax360 account your data goes to.
| Tier | Calls per hour | What the key can do |
|---|---|---|
t1 Basic | 100 | Read data and preview invoices. It cannot create invoices. |
t2 Standard | 1,000 | Everything in Basic, plus create, update and delete invoices and documents. |
t3 Premium | 5,000 | Everything in Standard, plus POST /invoices/batch (up to 500 invoices per call). |
The tax calculator (POST /calculator/estimate) also needs the calculator scope on your key. Ask us if you need it.
Base URL
Use https://api.sltax360.com/api/v1 for every endpoint: invoices, documents, reference data, key checks and the calculator. Your key selects your account, so you do not need a subdomain of your own.
http:// is redirected. When a client follows that redirect, a POST becomes a GET, so your invoice is not sent.
Response Format
All responses use a consistent JSON envelope with success, data/error, and meta fields.
Success Response
{
"success": true,
"data": { /* endpoint-specific data */ },
"meta": {
"timestamp": "2026-09-23T16:55:21Z",
"request_id": "req_070f04a750ae11ebefd69589",
"response_time_ms": 45
}
}
Error Response
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": { /* field-level errors when applicable */ }
},
"meta": { /* same as success */ }
}
Meta Object
| Field | Description |
|---|---|
timestamp | ISO 8601 timestamp of the response |
request_id | Unique request identifier for debugging. Include this in support requests. |
response_time_ms | Server-side processing time in milliseconds |
Error Codes
| HTTP Status | Error Code | Description |
|---|---|---|
400 | BAD_REQUEST | The request body is empty or is not valid JSON. |
401 | UNAUTHORIZED | The API key is missing, wrong, revoked or expired. |
403 | FORBIDDEN | Your key cannot do this. For example, a Basic (t1) key cannot create invoices, and the calculator needs the calculator scope. |
403 | TIER_REQUIRED | The operation needs a higher tier, for example POST /invoices/batch needs Premium (t3). |
404 | NOT_FOUND | The resource or the endpoint does not exist. |
405 | METHOD_NOT_ALLOWED | Wrong HTTP method, for example POST to /invoices/{id}/documents. Use PUT /invoices/{id}/documents/{docUUID}. |
409 | CONFLICT | The state has accepted the invoice (status success), so it cannot be changed or deleted. Also returned when a company with that name already exists. |
422 | VALIDATION_ERROR | The data failed a rule. Check error.details.fields, and see Common errors. |
429 | RATE_LIMIT_EXCEEDED | Too many calls this hour. Wait the number of seconds in the Retry-After header. |
500 | INTERNAL_ERROR | Unexpected server error. Contact support with the request_id. |
Validation Error Example
A real reply to POST /invoices with "type_code": "Renewal" and an insurer group without amount:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"fields": {
"type_code": ["Must be one of: NEW, RENEWAL, ENDORSEMENT, CANCELLATION"],
"insurers": ["insurers[0].amount is required and must be a number"]
}
}
},
"meta": {
"timestamp": "2026-09-23T16:58:25Z",
"request_id": "req_747bd15702f4aec469d62a87",
"response_time_ms": 5
}
}
On some accounts, our team keeps a rejected invoice so it is not lost. On those accounts the reply also has error.details.invoice_id. When you send the corrected invoice, it replaces the kept one.
Rate Limits
Each key has an hourly limit. The count starts again at the start of each clock hour. Every call counts, including previews and reference lists.
Response Headers
These headers come with every reply to a call that has a valid key.
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum calls allowed per hour |
X-RateLimit-Remaining | Calls left in the current hour |
X-RateLimit-Reset | Unix timestamp when the count starts again |
Limits by Tier
| Tier | Calls per hour |
|---|---|
t1 Basic | 100 |
t2 Standard | 1,000 |
t3 Premium | 5,000 |
Documents
Some states need supporting files before they accept a filing, for example the declarations page or an SL2 form. You do not upload files to us. You send a reference (docUUID) to a file in your own document store. Once we have connected to your document store, we fetch the file from there. Talk to us before you start, because that connection is set up once per partner.
Two ways to send a reference
- With the invoice: add a
documents[]array toPOST /invoices. - Later:
PUT /invoices/{id}/documents/{docUUID}. Use this when a document arrives after the invoice. It also works after the invoice is filed.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| PUT | /invoices/{id}/documents/{docUUID} |
Add a document, or change its type or file name. 201 when it is new, 200 when it already exists. Safe to retry. |
| GET | /invoices/{id}/documents |
List the documents on an invoice. |
| GET | /invoices/{id}/documents/{doc_id or docUUID} |
One document, with a fresh download link. |
| DELETE | /invoices/{id}/documents/{doc_id or docUUID} |
Remove one document. Replies 204 No Content. |
Rules
| Field | Rule |
|---|---|
type | Required. A short code of letters, digits, underscore or hyphen, up to 50 characters. The usual values are declaration_page, sl2_form, lloyds_syndicates, policy_endorsement, quote, policy, invoice, subjectivity and other (see GET /reference/document-types). We store the code in lowercase. Only these types go to the state with a filing: declaration_page, sl2_form, declinations_form, lloyds_syndicates, policy_endorsement and ecp_form. Other codes are kept for our team, but they are not sent to the state. |
docUUID | Required. Your id for the file, up to 256 characters. On the PUT path it is always your docUUID. |
filename | Optional, up to 255 characters. |
mime_type | Optional: application/pdf, image/png, image/jpeg or image/jpg. |
| Per request | Up to 10 documents in documents[] on POST /invoices. |
PUT treats the path value as your docUUID, so a number there creates a new document with that number as its reference. GET and DELETE accept either value. A docUUID made only of digits is read as our id there.
Add a document later: PUT /invoices/{id}/documents/{docUUID}
curl -X PUT "https://api.sltax360.com/api/v1/invoices/12832/documents/9f3c1a2e-5d6b-4a7c-8e9f-0a1b2c3d4e5f" \
-H "Authorization: Bearer $SLTAX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "declaration_page",
"filename": "dec-page.pdf",
"mime_type": "application/pdf"
}'
{
"success": true,
"data": {
"id": 6,
"doc_type": "declaration_page",
"file_name": "dec-page.pdf",
"mime_type": "application/pdf",
"file_size": null,
"is_excluded": false,
"external_doc_uuid": "9f3c1a2e-5d6b-4a7c-8e9f-0a1b2c3d4e5f",
"fetch_status": "pending",
"url": null,
"url_expires_in_seconds": null,
"added": "2026-09-23 11:58:25"
},
"meta": { /* timestamp, request_id, response_time_ms */ }
}
Send references with the invoice
"documents": [
{
"type": "declaration_page",
"docUUID": "9f3c1a2e-5d6b-4a7c-8e9f-0a1b2c3d4e5f",
"filename": "dec-page.pdf",
"mime_type": "application/pdf"
}
]
List, read and delete
curl "https://api.sltax360.com/api/v1/invoices/12832/documents" \
-H "Authorization: Bearer $SLTAX_API_KEY"
curl "https://api.sltax360.com/api/v1/invoices/12832/documents/9f3c1a2e-5d6b-4a7c-8e9f-0a1b2c3d4e5f" \
-H "Authorization: Bearer $SLTAX_API_KEY"
curl -X DELETE "https://api.sltax360.com/api/v1/invoices/12832/documents/9f3c1a2e-5d6b-4a7c-8e9f-0a1b2c3d4e5f" \
-H "Authorization: Bearer $SLTAX_API_KEY"
Document fields in replies
The same object comes back from GET and PUT, and in the documents[] field of GET /invoices/{id}.
| Field | Type | Description |
|---|---|---|
id | integer | Our document id. You can use it on GET and DELETE. |
doc_type | string | The type you sent. |
file_name | string | The file name you sent, or the name from your document store after the fetch. |
mime_type | string or null | The file type. It can be null until the file is fetched. |
file_size | integer or null | Size in bytes. Null until the file is fetched. |
is_excluded | boolean | True when our team has set the document aside. |
external_doc_uuid | string or null | Your docUUID. Null for files our team added by email or upload. |
fetch_status | string | For your references: pending, fetching, fetched or failed. none for files our team added by email or upload. |
url | string or null | A download link that works for 60 minutes. Null until the file is fetched. |
url_expires_in_seconds | integer or null | 3600 when url is set. |
added | datetime | When the document was first recorded. |
url field. It stops working after one hour. Call GET /invoices/{id}/documents/{docUUID} when you need a fresh link.
Interactive Reference: Invoices and Data
POST /invoices · POST /invoices/preview · GET /invoices/{id} · documents · GET /companies/search · GET /lobs · reference lists
Invoices, documents, policies, insureds, companies and reference data.
api.sltax360.com/api/v1. Click Authorize and paste your key, then use Try it out on any endpoint. Every call here is real: a create makes a real invoice. Use POST /invoices/preview to test.