Invoices
Create, read and list billing invoices using a profile-scoped server key.
On this page
Create an invoice
/v1/profiles/{profileId}/invoicesAuthentication: Bearer key · Required scope: invoices.write
Returns 201 for a new invoice, or 200 for an exact replay. Save billing details first; otherwise the response is 409 billing_details_required.
Choose amountUsd, or the complete chainId + token + amount set. Do not send both pricing forms. Store and profile token switches apply.
| Field | Details |
|---|---|
profileIdpath · required UUID | The profile that owns your API key. |
import { Forwend } from "forwend";
const forwend = new Forwend({
apiKey: process.env.FORWEND_KEY!,
profileId: process.env.FORWEND_PROFILE_ID!,
baseUrl: process.env.FORWEND_API_URL!,
});
const invoice = await forwend.invoices.create(
{ amountUsd: "1250.00", metadata: { order_id: "1042" } },
{ idempotencyKey: "order-1042" },
);
const latest = await forwend.invoices.get(invoice.invoiceId);Request headers
| Field | Details |
|---|---|
Authorizationheader · required | Bearer followed by your server-only API key. |
Content-Typeheader · required | application/json for a create request. |
Idempotency-Keyheader · required for create | 1–255 UTF-8 bytes. Reuse the same key and normalized body for a retry. |
Create request body
| Field | Details |
|---|---|
amountUsdstring · pricing option | Positive USD decimal string, representable exactly by every accepted token. Example: 1250.00. |
chainId, token, amountinteger, address, string · pricing option | Fixed token: network ID, enabled token contract and positive integer base units. For 6 decimals, 1250000000 represents 1250 tokens. |
storeIdUUID · optional | Merchant store. Defaults to the first store; a store-scoped key must use its own store. |
title, note, referencestrings · optional | Title ≤200 characters, payer note ≤2000, single-line reference ≤100. |
expiresIninteger · optional | 900–31536000 seconds. Defaults to one hour or the store default, unless dueDate is set. |
dueDate, supplyDateYYYY-MM-DD · optional | Payment due date and work delivery date. With dueDate but no expiresIn, checkout closes at the end of the 60th UTC day after it. |
clientobject · optional | name, email, address, country and taxId for the invoice’s customer. |
linesarray · optional | Up to 100 {description, quantity, unitPrice} entries. Quantity is a positive decimal string with ≤2 decimals. Unit price uses the chosen pricing unit; items must add up exactly. |
metadataobject · optional | Up to 20 single-line string values. See request rules for key and value limits. |
returnUrlstring · optional | HTTPS return URL, without userinfo. For a merchant, it must use a store allowed origin. HTTP return URLs are not accepted. |
remindersboolean · optional | Requires dueDate and client.email when true. |
agreedValueobject · optional | {currency, amount, date}: agreed fiat value, decimal string in that currency. This records an agreement, not a currency conversion. |
repeatobject · optional | Monthly billing schedule with optional endDate. Requires the repeating-invoice prerequisites, including dueDate. |
replacesstring · optional | Invoice being revised. Cancellation checks apply; the replaced invoice must belong to the profile. |
senderNamestring · optional | Name shown for a request without issuer billing details; up to 100 characters. |
Read an invoice
/v1/profiles/{profileId}/invoices/{invoiceId}Authentication: Bearer key · Required scope: invoices.read
Returns 200 with the invoice detail. No request body. An unknown or inaccessible invoice returns 404 invoice_not_found.
| Field | Details |
|---|---|
profileIdpath · required UUID | The profile that owns your API key. |
invoiceIdpath · required string | Invoice identifier returned by create. |
List invoices
/v1/profiles/{profileId}/invoicesAuthentication: Bearer key · Required scope: invoices.read
Returns 200 with {items, nextCursor}, newest first. nextCursor is null on the last page. No request body.
| Field | Details |
|---|---|
profileIdpath · required UUID | The profile that owns your API key. |
limitquery · integer | 1–100; default 50. |
cursorquery · string | The previous response’s nextCursor. Omit for the first page. |
statusquery · string | Optional: open, confirming, paid, settled, expired or canceled. This list filter differs from paymentStatus; paid also includes settled invoices. |
statequery · string | Optional: waiting, confirming, partially_paid, paid, overpaid, expired or canceled. This derived payment state differs from the raw paymentStatus. |
qquery · string | Optional search text. Omit when unused; a present but blank q is rejected. |
Invoice response
Responses can add fields. Ignore unknown fields and read paymentStatus independently from settlementStatus.
Create conflicts include 409 idempotency_conflict and billing_details_required. Invalid JSON or headers return 400 malformed_request.
| Field | Details |
|---|---|
invoiceId, payToken, numberstring, string | null, integer | null | Identifiers and document number. Hosted payment uses the returned payToken. |
chainId, token, amountinteger, address, string | Token identity and amount in integer base units. |
paymentStatus, confirmingstring, boolean | Recorded payment status and whether observed transfers await confirmation. |
settlementStatus, refundStatusstrings | Settlement and held-money handling are separate from payment status. |
livemodeboolean | false on the verified test networks. |
receiveAddress, recipientaddresses | Payment contract address and settlement destination. |
expiresAt, closesAt, createdAtRFC 3339 timestamps | Original expiry, current close and creation time. |
metadata, client, store, optionsobjects / array | Creator metadata, customer/store detail and token options. Detail reads include deposit and settlement records. |
Errors
Responses use {error: {code, message}}. Missing or invalid credentials return 401; missing scope or a different profile returns 403. Objects outside the caller’s store or mode are hidden with 404.
Invalid values return 422 invalid_value. Rate limiting returns 429 rate_limited with Retry-After. A starting network can return 503 network_not_ready; an unexpected server error returns 500 internal.