Skip to content

Invoices

Invoices are formal billing documents with auto-generated invoice numbers, due dates, and line items.

Invoice Lifecycle

Status Meaning
IDLE Created but not yet published. Can be edited; items can be added/removed.
ACTIVE Published and ready for payment. Editing is locked.
PROCESSING A payment attempt is in progress.
PAID Payment confirmed. Invoice is closed.
CANCELED Canceled and no longer payable.

Create Invoice

POST /v1/invoices/create

Request Body

Field Type Required Description
counterparty_id integer Yes ID of the counterparty being invoiced
currency string Yes ISO 4217 currency code (e.g. USD, LRD)
note string Yes Description or note for this invoice
fee_bearer enum Yes PAYER or PAYEE
as_payment_link boolean Yes Whether the invoice can be shared as a payment link
reference_id string | null No Your internal reference ID
due_date datetime | null No ISO 8601 payment due date

Code Examples

curl -X POST "https://api.heydollr.app/v1/invoices/create" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "counterparty_id": 7,
    "currency":        "USD",
    "note":            "Consulting services – June 2025",
    "fee_bearer":      "PAYER",
    "as_payment_link": true,
    "due_date":        "2025-06-30T23:59:00Z"
  }'
import requests

BASE_URL = "https://api.heydollr.app"
headers  = {"Authorization": "Bearer YOUR_ACCESS_TOKEN", "Content-Type": "application/json"}

response = requests.post(
    f"{BASE_URL}/v1/invoices/create",
    headers=headers,
    json={
        "counterparty_id": 7,
        "currency":        "USD",
        "note":            "Consulting services – June 2025",
        "fee_bearer":      "PAYER",
        "as_payment_link": True,
        "due_date":        "2025-06-30T23:59:00Z",
    },
)
invoice = response.json()
print("Invoice ID:", invoice["id"])
print("Invoice Number:", invoice["invoice_number"])
const BASE_URL = "https://api.heydollr.app";
const TOKEN    = "YOUR_ACCESS_TOKEN";

const response = await fetch(`${BASE_URL}/v1/invoices/create`, {
  method: "POST",
  headers: {
    Authorization:  `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    counterparty_id: 7,
    currency:        "USD",
    note:            "Consulting services – June 2025",
    fee_bearer:      "PAYER",
    as_payment_link: true,
    due_date:        "2025-06-30T23:59:00Z",
  }),
});
const invoice = await response.json();
console.log("Invoice ID:", invoice.id);
console.log("Invoice Number:", invoice.invoice_number);
$ch = curl_init("https://api.heydollr.app/v1/invoices/create");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "counterparty_id" => 7,
        "currency"        => "USD",
        "note"            => "Consulting services – June 2025",
        "fee_bearer"      => "PAYER",
        "as_payment_link" => true,
        "due_date"        => "2025-06-30T23:59:00Z",
    ]),
]);
$invoice = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "Invoice Number: " . $invoice["invoice_number"];
import java.net.URI;
import java.net.http.*;
import java.net.http.HttpRequest.BodyPublishers;

HttpClient client = HttpClient.newHttpClient();

String body = """
    {
      "counterparty_id": 7,
      "currency":        "USD",
      "note":            "Consulting services – June 2025",
      "fee_bearer":      "PAYER",
      "as_payment_link": true,
      "due_date":        "2025-06-30T23:59:00Z"
    }
    """;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.heydollr.app/v1/invoices/create"))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .header("Content-Type", "application/json")
    .POST(BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    payload := map[string]interface{}{
        "counterparty_id": 7,
        "currency":        "USD",
        "note":            "Consulting services – June 2025",
        "fee_bearer":      "PAYER",
        "as_payment_link": true,
        "due_date":        "2025-06-30T23:59:00Z",
    }
    body, _ := json.Marshal(payload)

    req, _ := http.NewRequest("POST",
        "https://api.heydollr.app/v1/invoices/create",
        bytes.NewBuffer(body),
    )
    req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)
    fmt.Println(string(data))
}

Add Invoice Item

POST /v1/invoices/{invoice_id}/items/add

Items can only be added while the invoice is in IDLE status.

Field Type Required Description
name string Yes Name or description of the line item
currency string Yes ISO 4217 currency code
qty integer Yes Quantity (minimum 1)
amount number Yes Unit price (min 0.01 for decimals, 1 for integers)

Code Examples

curl -X POST "https://api.heydollr.app/v1/invoices/101/items/add" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name":     "Strategy Session",
    "currency": "USD",
    "qty":      2,
    "amount":   150.00
  }'
invoice_id = 101
response = requests.post(
    f"{BASE_URL}/v1/invoices/{invoice_id}/items/add",
    headers=headers,
    json={
        "name":     "Strategy Session",
        "currency": "USD",
        "qty":      2,
        "amount":   150.00,
    },
)
item = response.json()
print("Item ID:", item["id"])
const invoiceId = 101;
const response = await fetch(`${BASE_URL}/v1/invoices/${invoiceId}/items/add`, {
  method: "POST",
  headers: {
    Authorization:  `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name:     "Strategy Session",
    currency: "USD",
    qty:      2,
    amount:   150.00,
  }),
});
const item = await response.json();
console.log("Item ID:", item.id);
$invoiceId = 101;
$ch = curl_init(
    "https://api.heydollr.app/v1/invoices/{$invoiceId}/items/add"
);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "name"     => "Strategy Session",
        "currency" => "USD",
        "qty"      => 2,
        "amount"   => 150.00,
    ]),
]);
$item = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "Item ID: " . $item["id"];
int invoiceId = 101;
String body = """
    {
      "name":     "Strategy Session",
      "currency": "USD",
      "qty":      2,
      "amount":   150.00
    }
    """;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(
        "https://api.heydollr.app/v1/invoices/"
        + invoiceId + "/items/add"
    ))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .header("Content-Type", "application/json")
    .POST(BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
invoiceId := 101
payload := map[string]interface{}{
    "name":     "Strategy Session",
    "currency": "USD",
    "qty":      2,
    "amount":   150.00,
}
body, _ := json.Marshal(payload)

url := fmt.Sprintf(
    "https://api.heydollr.app/v1/invoices/%d/items/add",
    invoiceId,
)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()

data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))

Update Invoice Item

PUT /v1/invoices/{invoice_id}/items/{id}/update
Field Type Required Description
name string | null No New item name
qty integer | null No New quantity
amount number | null No New unit price

Remove Invoice Item

DELETE /v1/invoices/{invoice_id}/items/{id}/remove

Returns an empty object {} on success.

Publish Invoice

PUT /v1/invoices/publish/{id}

Transitions the invoice from IDLE to ACTIVE. No request body required.

Code Examples

curl -X PUT "https://api.heydollr.app/v1/invoices/publish/101" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
invoice_id = 101
response = requests.put(
    f"{BASE_URL}/v1/invoices/publish/{invoice_id}",
    headers=headers,
)
print("Status:", response.json()["status"])  # ACTIVE
const invoiceId = 101;
const response = await fetch(`${BASE_URL}/v1/invoices/publish/${invoiceId}`, {
  method: "PUT",
  headers: { Authorization: `Bearer ${TOKEN}` },
});
const invoice = await response.json();
console.log("Status:", invoice.status); // ACTIVE
$invoiceId = 101;
$ch = curl_init(
    "https://api.heydollr.app/v1/invoices/publish/{$invoiceId}"
);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => ["Authorization: Bearer YOUR_ACCESS_TOKEN"],
]);
$invoice = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "Status: " . $invoice["status"]; // ACTIVE
int invoiceId = 101;
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(
        "https://api.heydollr.app/v1/invoices/publish/" + invoiceId
    ))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .PUT(BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
invoiceId := 101
url := fmt.Sprintf(
    "https://api.heydollr.app/v1/invoices/publish/%d",
    invoiceId,
)
req, _ := http.NewRequest("PUT", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()

data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))

Update Invoice

PUT /v1/invoices/update/{id}

Only available while the invoice is in IDLE status.

Field Type Required Description
reference_id string | null No Your internal reference
note string | null No Updated description
fee_bearer string | null No PAYER or PAYEE
due_date datetime | null No Updated due date

List Invoices

GET /v1/invoices/list
Query Param Type Required Description
currency string | null No Filter by ISO 4217 currency code
status string | null No Filter by status: IDLE, ACTIVE, PROCESSING, PAID, CANCELED

Code Examples

curl "https://api.heydollr.app/v1/invoices/list?status=ACTIVE" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
response = requests.get(
    f"{BASE_URL}/v1/invoices/list",
    headers=headers,
    params={"status": "ACTIVE"},
)
for inv in response.json():
    print(inv["invoice_number"], inv["total_amount"])
const response = await fetch(`${BASE_URL}/v1/invoices/list?status=ACTIVE`, {
  headers: { Authorization: `Bearer ${TOKEN}` },
});
const invoices = await response.json();
invoices.forEach(inv => console.log(inv.invoice_number, inv.total_amount));
$ch = curl_init(
    "https://api.heydollr.app/v1/invoices/list?status=ACTIVE"
);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ["Authorization: Bearer YOUR_ACCESS_TOKEN"],
]);
$invoices = json_decode(curl_exec($ch), true);
curl_close($ch);
foreach ($invoices as $inv) {
    echo $inv["invoice_number"] . "\n";
}
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(
        "https://api.heydollr.app/v1/invoices/list?status=ACTIVE"
    ))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .GET()
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
req, _ := http.NewRequest("GET",
    "https://api.heydollr.app/v1/invoices/list?status=ACTIVE",
    nil,
)
req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()

data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))

Retrieve Invoice

GET /v1/invoices/retrieve/{id}
GET /v1/invoices/retrieve/number/{invoice_number}

Both return InvoiceDetailResponse, which includes line items and the linked counterparty.

Retrieve Invoice Receipt

Receipts are available after an invoice has been paid. They include full payment details: amounts, fees, FX rate, provider, and line items.

GET /v1/invoices/receipt/{id}
GET /v1/invoices/receipt/number/{invoice_number}

Cancel Invoice

DELETE /v1/invoices/cancel/{id}

A canceled invoice cannot be reactivated. No request body required.