Generate PDF url
curl --request POST \
--url https://api.altera.co/sales/pdfUrl \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"invoiceId": 12679
}
'import requests
url = "https://api.altera.co/sales/pdfUrl"
payload = { "invoiceId": 12679 }
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({invoiceId: 12679})
};
fetch('https://api.altera.co/sales/pdfUrl', 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.altera.co/sales/pdfUrl",
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([
'invoiceId' => 12679
]),
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.altera.co/sales/pdfUrl"
payload := strings.NewReader("{\n \"invoiceId\": 12679\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.altera.co/sales/pdfUrl")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"invoiceId\": 12679\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.altera.co/sales/pdfUrl")
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 \"invoiceId\": 12679\n}"
response = http.request(request)
puts response.read_body{
"result": "OK",
"data": "<string>"
}{
"result": "Error",
"errorMessage": "This tag cannot be deleted, it has been used in at least one invoice. You can disable it so it won't appear on the suggestion lists.",
"errorMessagePL": "Ta kategoria nie może zostać usunięta ponieważ została użyta w przynajmniej jednej fakturze. Możesz ją zablokować aby nie pojawiała się na liście sugerowanych."
}{
"result": "Error",
"errorCode": "KEY_EXPIRED",
"errorMessage": "API key has expired"
}{
"result": "Error",
"errorCode": "PDF_NOT_READY",
"errorMessage": "Invoice PDF is not ready. Try again later."
}Sales
Generate PDF url
Returns a pre-signed PDF URL for one invoice, valid for 5 minutes. A company-owned PDF still being generated returns 409 PDF_NOT_READY with Retry-After: 2; retry within a bounded budget. Invalid or unavailable invoice selection returns 400. Pending PDF requests do not change status. A successful request changes an ISSUED sales document, including a pro forma, to SENT even if the URL is never downloaded. DRAFT remains DRAFT. SENT is not proof of email delivery.
POST
/
sales
/
pdfUrl
Generate PDF url
curl --request POST \
--url https://api.altera.co/sales/pdfUrl \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"invoiceId": 12679
}
'import requests
url = "https://api.altera.co/sales/pdfUrl"
payload = { "invoiceId": 12679 }
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({invoiceId: 12679})
};
fetch('https://api.altera.co/sales/pdfUrl', 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.altera.co/sales/pdfUrl",
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([
'invoiceId' => 12679
]),
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.altera.co/sales/pdfUrl"
payload := strings.NewReader("{\n \"invoiceId\": 12679\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.altera.co/sales/pdfUrl")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"invoiceId\": 12679\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.altera.co/sales/pdfUrl")
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 \"invoiceId\": 12679\n}"
response = http.request(request)
puts response.read_body{
"result": "OK",
"data": "<string>"
}{
"result": "Error",
"errorMessage": "This tag cannot be deleted, it has been used in at least one invoice. You can disable it so it won't appear on the suggestion lists.",
"errorMessagePL": "Ta kategoria nie może zostać usunięta ponieważ została użyta w przynajmniej jednej fakturze. Możesz ją zablokować aby nie pojawiała się na liście sugerowanych."
}{
"result": "Error",
"errorCode": "KEY_EXPIRED",
"errorMessage": "API key has expired"
}{
"result": "Error",
"errorCode": "PDF_NOT_READY",
"errorMessage": "Invoice PDF is not ready. Try again later."
}Request one invoice
Send the singularinvoiceId field, rather than an invoiceIds array:
{
"invoiceId": 12345
}
data. The URL expires after 5 minutes.
PDF readiness
Altera generates the PDF asynchronously after saving. When the invoice belongs to the API key’s company and its PDF is still being prepared, the endpoint returns HTTP409 with errorCode: "PDF_NOT_READY" and Retry-After: 2. Wait at least the indicated number of seconds before retrying. Use a bounded retry budget; there is no fixed readiness deadline.
{
"result": "Error",
"errorCode": "PDF_NOT_READY",
"errorMessage": "Invoice PDF is not ready. Try again later."
}
400 still indicates invalid input or an invoice unavailable in the API key’s company. Do not retry that response as a PDF-readiness signal. The document status does not change while the PDF is pending.
Status change
A successful call changes anISSUED sales document to SENT, including pro formas. The status changes when the URL is returned, even if nobody downloads it. A DRAFT remains DRAFT.
SENT does not prove an email was sent or received. The public endpoint currently has no option to suppress this status change, and no separate mark-as-sent endpoint is exposed.Authorizations
OpenApi Key created within Altera.app for a certain company
Body
application/json
Required range:
x >= 1Was this page helpful?

