View as Markdown

llms.txt

No such blueprint

This instance publishes no blueprint at that address. The catalog lists every one it does publish.

Back to the blueprints

Blueprints Full integrations

Invoice a customer and get paid

Create a customer, write them an invoice, issue it, and record the payment when it arrives, so you know what the platform does at each stage of an invoice's life.

Signed in, you can run this blueprint against your own sandbox merchant one call at a time, with the values from each call threaded into the next. Sign in to run it.

9 steps, 6 API callsInvoicingCustomersPayments

Samples use {{API_KEY}} for your API key and {{BASE_URL}} for this instance's API address. Anything else in double braces is a value an earlier step gave you.

Set up the customer

1. Read the merchant id off a sandbox sale

API call

POST /api/transactions

Every invoicing call names the merchant it bills as, and your key belongs to exactly one. There is no call that answers with that id on its own, so read it off the first merchant-scoped record your key creates: here, a card sale at the amount the sandbox always approves. If you have already run another flow on this site, the merchantId on any of its responses is the same value.

Reference for this operation

Values this step gives you

  • {{merchantId}} The merchant the sale belongs to, from the response body's merchantId property. Every invoicing call below bills as this merchant.
cURL

curl -X POST "{{BASE_URL}}/api/transactions" \
  -H "api-key: {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "transactionType": "Sale",
    "cardData": {
      "cardNumber": "4111111111111111",
      "nameOnCard": "Jane Doe",
      "expirationMonth": 12,
      "expirationYear": 2030,
      "cvv": 123
    },
    "invoiceData": {
      "amounts": { "base": 10.00, "total": 10.00 }
    }
  }'
.NET

using var http = new HttpClient { BaseAddress = new Uri("{{BASE_URL}}") };
http.DefaultRequestHeaders.Add("api-key", "{{API_KEY}}");

var response = await http.PostAsJsonAsync("/api/transactions", new
{
    transactionType = "Sale",
    cardData = new
    {
        cardNumber = "4111111111111111",
        nameOnCard = "Jane Doe",
        expirationMonth = 12,
        expirationYear = 2030,
        cvv = 123
    },
    invoiceData = new
    {
        amounts = new { @base = 10.00m, total = 10.00m }
    }
});

response.EnsureSuccessStatusCode();

var sale = await response.Content.ReadFromJsonAsync<JsonElement>();
var merchantId = sale.GetProperty("merchantId").GetString();

What this step answers with

Abridged to the properties this step depends on. A real response carries more.

HTTP 200

{
  "id": "9f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
  "merchantId": "3a7b1c9d-2e4f-4a6b-8c8d-9e0f1a2b3c4d",
  "transactionType": "Sale",
  "resultCode": "Ok",
  "authorizedAmount": 10.00
}

2. Create the customer you are invoicing

API call

POST /api/customers

An invoice is addressed to a customer record, so the customer comes first. Give the address list exactly one default entry with a street line, a city, a state and a postal code; the list may be left empty, but a partial address is refused. Keep the id: it's the recipient of the invoice below, and it's also how a customer portal or a payment link knows whose invoice it's showing.

Reference for this operation

Values this step gives you

  • {{customerId}} The id of the created customer, from the response body's id property. The invoice names it as its recipient.
cURL

curl -X POST "{{BASE_URL}}/api/customers" \
  -H "api-key: {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "{{merchantId}}",
    "name": "Jane Doe",
    "isActive": true,
    "contactDetail": {
      "primaryContactName": "Jane Doe",
      "emailAddress": "jane.doe@example.com",
      "phone": "5555550123",
      "addresses": [
        {
          "address1": "100 Main Street",
          "city": "Minneapolis",
          "state": "MN",
          "zip": "55401",
          "isDefault": true
        }
      ]
    }
  }'
.NET

var created = await http.PostAsJsonAsync("/api/customers", new
{
    merchantId,
    name = "Jane Doe",
    isActive = true,
    contactDetail = new
    {
        primaryContactName = "Jane Doe",
        emailAddress = "jane.doe@example.com",
        phone = "5555550123",
        addresses = new[]
        {
            new
            {
                address1 = "100 Main Street",
                city = "Minneapolis",
                state = "MN",
                zip = "55401",
                isDefault = true
            }
        }
    }
});

created.EnsureSuccessStatusCode();

var customer = await created.Content.ReadFromJsonAsync<JsonElement>();
var customerId = customer.GetProperty("id").GetString();

What this step answers with

Abridged to the properties this step depends on. A real response carries more.

HTTP 200

{
  "id": "7b2c4d6e-8f0a-4c3d-9e5f-6a7b8c9d0e1f",
  "merchantId": "{{merchantId}}",
  "name": "Jane Doe",
  "isActive": true
}

Write the invoice

3. Create the invoice as a draft

API call

POST /api/invoicing/invoices

Send the biller, the recipient, the currency, the terms and the lines. The platform answers with a draft: totals are computed, the status is Draft, and there is no invoice number yet. A draft is the one stage you can still edit, so this is where your own review or approval step belongs. Lines need only a description, a quantity and a unit price; link one to a catalog product when you sell the same thing again and again, and leave productId off when you don't.

Reference for this operation

Values this step gives you

  • {{invoiceId}} The id of the draft, from the response body's id property. Every later call addresses the invoice by it; the invoice number is for people and isn't assigned until issue.
cURL

curl -X POST "{{BASE_URL}}/api/invoicing/invoices" \
  -H "api-key: {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "billerId": "{{merchantId}}",
    "billerType": "Merchant",
    "recipientId": "{{customerId}}",
    "recipientType": "Customer",
    "currency": "USD",
    "paymentTermsValue": "Net30",
    "recipientSnapshot": {
      "name": "Jane Doe",
      "email": "jane.doe@example.com"
    },
    "lineItems": [
      { "description": "Website redesign", "quantity": 1, "unitPrice": 1200.00 },
      { "description": "Managed hosting, monthly", "quantity": 12, "unitPrice": 25.00 }
    ]
  }'
.NET

var drafted = await http.PostAsJsonAsync("/api/invoicing/invoices", new
{
    billerId = merchantId,
    billerType = "Merchant",
    recipientId = customerId,
    recipientType = "Customer",
    currency = "USD",
    paymentTermsValue = "Net30",
    recipientSnapshot = new { name = "Jane Doe", email = "jane.doe@example.com" },
    lineItems = new[]
    {
        new { description = "Website redesign", quantity = 1m, unitPrice = 1200.00m },
        new { description = "Managed hosting, monthly", quantity = 12m, unitPrice = 25.00m }
    }
});

drafted.EnsureSuccessStatusCode();

var draft = await drafted.Content.ReadFromJsonAsync<JsonElement>();
var invoiceId = draft.GetProperty("id").GetString();
var status = draft.GetProperty("status").GetString(); // "Draft"

What this step answers with

Abridged to the properties this step depends on. A real response carries more.

HTTP 200

{
  "id": "8c0d2e4f-6a7b-4c9d-8e1f-2a3b4c5d6e7f",
  "billerId": "{{merchantId}}",
  "billerType": "Merchant",
  "recipientId": "{{customerId}}",
  "recipientType": "Customer",
  "status": "Draft",
  "invoiceNumber": null,
  "currency": "USD",
  "paymentTermsValue": "Net30",
  "issueDate": null,
  "dueDate": null,
  "subtotal": 1500.00,
  "taxTotal": 0.00,
  "grandTotal": 1500.00,
  "amountPaid": 0.00,
  "balanceDue": 1500.00,
  "paidAt": null,
  "isLocked": false,
  "lineItems": [
    {
      "description": "Website redesign",
      "quantity": 1,
      "unitPrice": 1200.00,
      "lineTotal": 1200.00
    },
    {
      "description": "Managed hosting, monthly",
      "quantity": 12,
      "unitPrice": 25.00,
      "lineTotal": 300.00
    }
  ]
}

4. Issue the invoice

API call

POST /api/invoicing/invoices/{{invoiceId}}/issue

Issuing is the point of no return. The platform assigns the invoice number from the biller's sequence, stamps the issue date, computes the due date from the Net 30 terms, freezes the biller and recipient snapshots, and locks the document: the status is Issued and an update from here on is refused. The body is empty; the invoice id in the route is the whole request. Do this when the invoice is final, and not before.

Reference for this operation

Values this step gives you

    cURL

    curl -X POST "{{BASE_URL}}/api/invoicing/invoices/{{invoiceId}}/issue" \
      -H "api-key: {{API_KEY}}"
    .NET

    var issuing = await http.PostAsync(
        $"/api/invoicing/invoices/{invoiceId}/issue", content: null);
    
    issuing.EnsureSuccessStatusCode();
    
    var issued = await issuing.Content.ReadFromJsonAsync<JsonElement>();
    var invoiceNumber = issued.GetProperty("invoiceNumber").GetString();
    var balanceDue = issued.GetProperty("balanceDue").GetDecimal();

    What this step answers with

    Abridged to the properties this step depends on. A real response carries more.

    HTTP 200

    {
      "id": "{{invoiceId}}",
      "billerId": "{{merchantId}}",
      "billerType": "Merchant",
      "recipientId": "{{customerId}}",
      "recipientType": "Customer",
      "status": "Issued",
      "invoiceNumber": "INV-00001",
      "currency": "USD",
      "paymentTermsValue": "Net30",
      "issueDate": "2026-02-04T18:22:43.062Z",
      "dueDate": "2026-03-06T18:22:43.062Z",
      "subtotal": 1500.00,
      "taxTotal": 0.00,
      "grandTotal": 1500.00,
      "amountPaid": 0.00,
      "balanceDue": 1500.00,
      "paidAt": null,
      "isLocked": true,
      "lineItems": [
        {
          "description": "Website redesign",
          "quantity": 1,
          "unitPrice": 1200.00,
          "lineTotal": 1200.00
        },
        {
          "description": "Managed hosting, monthly",
          "quantity": 12,
          "unitPrice": 25.00,
          "lineTotal": 300.00
        }
      ]
    }

    Get paid

    5. Record the payment

    API call

    POST /api/invoicing/invoices/{{invoiceId}}/record-payment

    When the customer pays outside the platform, by check or by bank transfer, tell the invoice about it. Send the amount received and how it arrived. The platform applies it to the balance and moves the status: to Paid when the balance reaches zero, as here, or to PartiallyPaid when it doesn't. A partial amount is refused unless the invoice allows partial payment, and any amount above the balance is refused outright. A payment the customer makes through a payment link is applied for you by the same rule, so your reconciliation reads one status whichever way the money came.

    Reference for this operation

    Values this step gives you

      cURL

      curl -X POST "{{BASE_URL}}/api/invoicing/invoices/{{invoiceId}}/record-payment" \
        -H "api-key: {{API_KEY}}" \
        -H "Content-Type: application/json" \
        -d '{
          "amount": 1500.00,
          "paymentMethod": "Check",
          "notes": "Check received by mail."
        }'
      .NET

      var recording = await http.PostAsJsonAsync(
          $"/api/invoicing/invoices/{invoiceId}/record-payment",
          new
          {
              amount = 1500.00m,
              paymentMethod = "Check",
              notes = "Check received by mail."
          });
      
      recording.EnsureSuccessStatusCode();
      
      var paid = await recording.Content.ReadFromJsonAsync<JsonElement>();
      var paidStatus = paid.GetProperty("status").GetString(); // "Paid"

      What this step answers with

      Abridged to the properties this step depends on. A real response carries more.

      HTTP 200

      {
        "id": "{{invoiceId}}",
        "billerId": "{{merchantId}}",
        "billerType": "Merchant",
        "recipientId": "{{customerId}}",
        "recipientType": "Customer",
        "status": "Paid",
        "invoiceNumber": "INV-00001",
        "currency": "USD",
        "paymentTermsValue": "Net30",
        "issueDate": "2026-02-04T18:22:43.062Z",
        "dueDate": "2026-03-06T18:22:43.062Z",
        "subtotal": 1500.00,
        "taxTotal": 0.00,
        "grandTotal": 1500.00,
        "amountPaid": 1500.00,
        "balanceDue": 0.00,
        "paidAt": "2026-02-04T18:22:43.062Z",
        "isLocked": true,
        "lineItems": [
          {
            "description": "Website redesign",
            "quantity": 1,
            "unitPrice": 1200.00,
            "lineTotal": 1200.00
          },
          {
            "description": "Managed hosting, monthly",
            "quantity": 12,
            "unitPrice": 25.00,
            "lineTotal": 300.00
          }
        ]
      }

      6. Read the invoice back

      API call

      GET /api/invoicing/invoices/{{invoiceId}}

      Read the invoice you just settled. The status is Paid, the balance due is zero, the amount paid equals the grand total, and paidAt records when the balance cleared. Reconcile against this record rather than against the response you got from recording the payment, so a request that timed out on your side still has somewhere to recover the outcome from.

      Reference for this operation

      Values this step gives you

        cURL

        curl "{{BASE_URL}}/api/invoicing/invoices/{{invoiceId}}" \
          -H "api-key: {{API_KEY}}"
        .NET

        var invoice = await http.GetFromJsonAsync<JsonElement>(
            $"/api/invoicing/invoices/{invoiceId}");
        
        var settled = invoice.GetProperty("status").GetString() == "Paid"
                      && invoice.GetProperty("balanceDue").GetDecimal() == 0m;
        var paidAt = invoice.GetProperty("paidAt").GetString();

        What this step answers with

        Abridged to the properties this step depends on. A real response carries more.

        HTTP 200

        {
          "id": "{{invoiceId}}",
          "billerId": "{{merchantId}}",
          "billerType": "Merchant",
          "recipientId": "{{customerId}}",
          "recipientType": "Customer",
          "status": "Paid",
          "invoiceNumber": "INV-00001",
          "currency": "USD",
          "paymentTermsValue": "Net30",
          "issueDate": "2026-02-04T18:22:43.062Z",
          "dueDate": "2026-03-06T18:22:43.062Z",
          "subtotal": 1500.00,
          "taxTotal": 0.00,
          "grandTotal": 1500.00,
          "amountPaid": 1500.00,
          "balanceDue": 0.00,
          "paidAt": "2026-02-04T18:22:43.062Z",
          "isLocked": true,
          "lineItems": [
            {
              "description": "Website redesign",
              "quantity": 1,
              "unitPrice": 1200.00,
              "lineTotal": 1200.00
            },
            {
              "description": "Managed hosting, monthly",
              "quantity": 12,
              "unitPrice": 25.00,
              "lineTotal": 300.00
            }
          ]
        }

        Go further

        7. Send the invoice to the customer

        On your side

        In production you send the invoice rather than recording a payment by hand. The send call runs the whole delivery workflow: it issues the invoice if it's still a draft, creates a payment link and a view token for the recipient, marks the status Sent, and delivers the notification. That last part needs a merchant with a configured email destination, which a fresh sandbox may not have, and it's why this flow records a payment as its runnable path instead. Once you have configured delivery, call send from your own integration and let the payment link do the collecting.

        Reference for this operation

        Values this step gives you

          8. Download the invoice as a PDF

          On your side

          Any issued invoice can be rendered as a PDF from the snapshots and lines frozen at issue. Fetch it when your customer asks for a copy or when your own records need the document rather than the data. The response is the file itself, not JSON.

          Reference for this operation

          Values this step gives you

            9. Offer a payment plan

            On your side

            A larger invoice can be split into scheduled installments the platform collects against a stored payment method. Create the plan on an issued invoice; each installment is applied to the balance the same way the payment above was, so the invoice reaches Paid when the last one clears. Payment plans, credit notes and recurring invoices each have their own reference pages.

            Reference for this operation

            Values this step gives you

              Run the whole flow as one script

              Every step above in one script you can copy and run. Replace {{API_KEY}} with your own API key and {{BASE_URL}} with this instance's API address, and set any value the script asks you for at the top. A step that happens outside the API stays a comment.

              Code sample language

              brew install jq

              cURL

              #!/usr/bin/env bash
              # Invoice a customer and get paid
              #
              # Create a customer, write them an invoice, issue it, and record the payment when it arrives, so you
              # know what the platform does at each stage of an invoice's life.
              #
              # Every API call in this blueprint, in order. Each value a call returns is passed to the calls after
              # it. A step that happens outside the API is a comment, and any failed call stops the script.
              
              set -euo pipefail
              
              BASE_URL="{{BASE_URL}}"
              API_KEY="{{API_KEY}}"
              
              # Sends one request and prints the response body. A failed call prints the API's answer and stops
              # the script.
              call() {
                local method="$1" path="$2" body="${3:-}" out
                local args=(-sS --fail-with-body -X "$method" "$BASE_URL$path" -H "api-key: $API_KEY")
                if [ -n "$body" ]; then
                  args+=(-H "Content-Type: application/json" -d "$body")
                fi
                if ! out=$(curl "${args[@]}"); then
                  printf '%s\n' "$out" >&2
                  return 1
                fi
                printf '%s' "$out"
              }
              
              # Percent-encodes a value for use in a URL.
              urlencode() {
                jq -rn --arg value "$1" '$value | @uri'
              }
              
              # Phase 1: Set up the customer
              
              # Step 1: Read the merchant id off a sandbox sale
              step1=$(call POST "/api/transactions" '{
                "transactionType": "Sale",
                "cardData": {
                  "cardNumber": "4111111111111111",
                  "nameOnCard": "Jane Doe",
                  "expirationMonth": 12,
                  "expirationYear": 2030,
                  "cvv": 123
                },
                "invoiceData": {
                  "amounts": { "base": 10.00, "total": 10.00 }
                }
              }')
              merchantId=$(jq -er '.merchantId | if . == null then error("The response carried no value for merchantId.") else tostring end' <<< "$step1")
              
              # Step 2: Create the customer you are invoicing
              body=$(jq -n --arg merchantId "$merchantId" '{
                "merchantId": $merchantId,
                "name": "Jane Doe",
                "isActive": true,
                "contactDetail": {
                  "primaryContactName": "Jane Doe",
                  "emailAddress": "jane.doe@example.com",
                  "phone": "5555550123",
                  "addresses": [
                    {
                      "address1": "100 Main Street",
                      "city": "Minneapolis",
                      "state": "MN",
                      "zip": "55401",
                      "isDefault": true
                    }
                  ]
                }
              }')
              step2=$(call POST "/api/customers" "$body")
              customerId=$(jq -er '.id | if . == null then error("The response carried no value for customerId.") else tostring end' <<< "$step2")
              
              # Phase 2: Write the invoice
              
              # Step 3: Create the invoice as a draft
              body=$(jq -n --arg merchantId "$merchantId" --arg customerId "$customerId" '{
                "billerId": $merchantId,
                "billerType": "Merchant",
                "recipientId": $customerId,
                "recipientType": "Customer",
                "currency": "USD",
                "paymentTermsValue": "Net30",
                "recipientSnapshot": {
                  "name": "Jane Doe",
                  "email": "jane.doe@example.com"
                },
                "lineItems": [
                  {
                    "description": "Website redesign",
                    "quantity": 1,
                    "unitPrice": 1200.00
                  },
                  {
                    "description": "Managed hosting, monthly",
                    "quantity": 12,
                    "unitPrice": 25.00
                  }
                ]
              }')
              step3=$(call POST "/api/invoicing/invoices" "$body")
              invoiceId=$(jq -er '.id | if . == null then error("The response carried no value for invoiceId.") else tostring end' <<< "$step3")
              
              # Step 4: Issue the invoice
              call POST "/api/invoicing/invoices/$(urlencode "$invoiceId")/issue" > /dev/null
              
              # Phase 3: Get paid
              
              # Step 5: Record the payment
              call POST "/api/invoicing/invoices/$(urlencode "$invoiceId")/record-payment" '{
                "amount": 1500.00,
                "paymentMethod": "Check",
                "notes": "Check received by mail."
              }' > /dev/null
              
              # Step 6: Read the invoice back
              call GET "/api/invoicing/invoices/$(urlencode "$invoiceId")" > /dev/null
              
              # Phase 4: Go further
              
              # Step 7: Send the invoice to the customer
              # In production you send the invoice rather than recording a payment by hand. The send call runs the
              # whole delivery workflow: it issues the invoice if it's still a draft, creates a payment link and a
              # view token for the recipient, marks the status Sent, and delivers the notification. That last part
              # needs a merchant with a configured email destination, which a fresh sandbox may not have, and it's
              # why this flow records a payment as its runnable path instead. Once you have configured delivery,
              # call send from your own integration and let the payment link do the collecting.
              
              # Step 8: Download the invoice as a PDF
              # Any issued invoice can be rendered as a PDF from the snapshots and lines frozen at issue. Fetch it
              # when your customer asks for a copy or when your own records need the document rather than the
              # data. The response is the file itself, not JSON.
              
              # Step 9: Offer a payment plan
              # A larger invoice can be split into scheduled installments the platform collects against a stored
              # payment method. Create the plan on an issued invoice; each installment is applied to the balance
              # the same way the payment above was, so the invoice reaches Paid when the last one clears. Payment
              # plans, credit notes and recurring invoices each have their own reference pages.
              

              PowerShell

              # Invoice a customer and get paid
              #
              # Create a customer, write them an invoice, issue it, and record the payment when it arrives, so you
              # know what the platform does at each stage of an invoice's life.
              #
              # Every API call in this blueprint, in order. Each value a call returns is passed to the calls after
              # it. A step that happens outside the API is a comment, and any failed call stops the script.
              
              $ErrorActionPreference = 'Stop'
              
              $baseUrl = '{{BASE_URL}}'
              $apiKey = '{{API_KEY}}'
              
              # Sends one request and returns the parsed response body. A failed call stops the script.
              function Invoke-BlueprintCall([string] $Method, [string] $Path, [string] $Body) {
                  $arguments = @{
                      Method  = $Method
                      Uri     = $baseUrl + $Path
                      Headers = @{ 'api-key' = $apiKey }
                  }
                  if ($Body) {
                      $arguments.ContentType = 'application/json'
                      $arguments.Body = [System.Text.Encoding]::UTF8.GetBytes($Body)
                  }
                  Invoke-RestMethod @arguments
              }
              
              # Turns a value read off a response back into the text the API sent. A missing value stops the
              # script.
              function ConvertTo-CaptureValue($Value, [string] $Name) {
                  if ($null -eq $Value) { throw "The response carried no value for $Name." }
                  if ($Value -is [datetime] -and $Value.Kind -eq 'Unspecified') { return $Value.ToString('yyyy-MM-ddTHH:mm:ss.FFFFFFF', [cultureinfo]::InvariantCulture) }
                  if ($Value -is [datetime]) { return $Value.ToUniversalTime().ToString('o') }
                  if ($Value -is [bool]) { return $Value.ToString().ToLowerInvariant() }
                  [string]$Value
              }
              
              # Phase 1: Set up the customer
              
              # Step 1: Read the merchant id off a sandbox sale
              $body = @'
              {
                "transactionType": "Sale",
                "cardData": {
                  "cardNumber": "4111111111111111",
                  "nameOnCard": "Jane Doe",
                  "expirationMonth": 12,
                  "expirationYear": 2030,
                  "cvv": 123
                },
                "invoiceData": {
                  "amounts": { "base": 10.00, "total": 10.00 }
                }
              }
              '@
              $step1 = Invoke-BlueprintCall -Method 'POST' -Path '/api/transactions' -Body $body
              $merchantId = ConvertTo-CaptureValue $step1.merchantId 'merchantId'
              
              # Step 2: Create the customer you are invoicing
              $body = @"
              {
                "merchantId": $(ConvertTo-Json -InputObject ([string]($merchantId))),
                "name": "Jane Doe",
                "isActive": true,
                "contactDetail": {
                  "primaryContactName": "Jane Doe",
                  "emailAddress": "jane.doe@example.com",
                  "phone": "5555550123",
                  "addresses": [
                    {
                      "address1": "100 Main Street",
                      "city": "Minneapolis",
                      "state": "MN",
                      "zip": "55401",
                      "isDefault": true
                    }
                  ]
                }
              }
              "@
              $step2 = Invoke-BlueprintCall -Method 'POST' -Path '/api/customers' -Body $body
              $customerId = ConvertTo-CaptureValue $step2.id 'customerId'
              
              # Phase 2: Write the invoice
              
              # Step 3: Create the invoice as a draft
              $body = @"
              {
                "billerId": $(ConvertTo-Json -InputObject ([string]($merchantId))),
                "billerType": "Merchant",
                "recipientId": $(ConvertTo-Json -InputObject ([string]($customerId))),
                "recipientType": "Customer",
                "currency": "USD",
                "paymentTermsValue": "Net30",
                "recipientSnapshot": {
                  "name": "Jane Doe",
                  "email": "jane.doe@example.com"
                },
                "lineItems": [
                  {
                    "description": "Website redesign",
                    "quantity": 1,
                    "unitPrice": 1200.00
                  },
                  {
                    "description": "Managed hosting, monthly",
                    "quantity": 12,
                    "unitPrice": 25.00
                  }
                ]
              }
              "@
              $step3 = Invoke-BlueprintCall -Method 'POST' -Path '/api/invoicing/invoices' -Body $body
              $invoiceId = ConvertTo-CaptureValue $step3.id 'invoiceId'
              
              # Step 4: Issue the invoice
              $null = Invoke-BlueprintCall -Method 'POST' -Path "/api/invoicing/invoices/$([uri]::EscapeDataString($invoiceId))/issue"
              
              # Phase 3: Get paid
              
              # Step 5: Record the payment
              $body = @'
              {
                "amount": 1500.00,
                "paymentMethod": "Check",
                "notes": "Check received by mail."
              }
              '@
              $null = Invoke-BlueprintCall -Method 'POST' -Path "/api/invoicing/invoices/$([uri]::EscapeDataString($invoiceId))/record-payment" -Body $body
              
              # Step 6: Read the invoice back
              $null = Invoke-BlueprintCall -Method 'GET' -Path "/api/invoicing/invoices/$([uri]::EscapeDataString($invoiceId))"
              
              # Phase 4: Go further
              
              # Step 7: Send the invoice to the customer
              # In production you send the invoice rather than recording a payment by hand. The send call runs the
              # whole delivery workflow: it issues the invoice if it's still a draft, creates a payment link and a
              # view token for the recipient, marks the status Sent, and delivers the notification. That last part
              # needs a merchant with a configured email destination, which a fresh sandbox may not have, and it's
              # why this flow records a payment as its runnable path instead. Once you have configured delivery,
              # call send from your own integration and let the payment link do the collecting.
              
              # Step 8: Download the invoice as a PDF
              # Any issued invoice can be rendered as a PDF from the snapshots and lines frozen at issue. Fetch it
              # when your customer asks for a copy or when your own records need the document rather than the
              # data. The response is the file itself, not JSON.
              
              # Step 9: Offer a payment plan
              # A larger invoice can be split into scheduled installments the platform collects against a stored
              # payment method. Create the plan on an issued invoice; each installment is applied to the balance
              # the same way the payment above was, so the invoice reaches Paid when the last one clears. Payment
              # plans, credit notes and recurring invoices each have their own reference pages.
              

              TypeScript

              // Invoice a customer and get paid
              //
              // Create a customer, write them an invoice, issue it, and record the payment when it arrives, so
              // you know what the platform does at each stage of an invoice's life.
              //
              // Every API call in this blueprint, in order. Each value a call returns is passed to the calls
              // after it. A step that happens outside the API is a comment, and any failed call stops the script.
              
              export {};
              
              const baseUrl = '{{BASE_URL}}';
              const apiKey = '{{API_KEY}}';
              
              // Sends one request and returns the parsed response body. A failed call throws.
              async function call(method: string, path: string, body?: unknown): Promise<any> {
                const headers: Record<string, string> = { 'api-key': apiKey };
                if (body !== undefined) {
                  headers['Content-Type'] = 'application/json';
                }
              
                const response = await fetch(baseUrl + path, {
                  method,
                  headers,
                  body: body === undefined ? undefined : JSON.stringify(body),
                });
              
                const text = await response.text();
                if (!response.ok) {
                  throw new Error(`${method} ${path} answered ${response.status}: ${text}`);
                }
              
                return text ? JSON.parse(text) : null;
              }
              
              // Turns a value read off a response into the text the API sent. A missing value throws.
              function capture(value: unknown, name: string): string {
                if (value === undefined || value === null) {
                  throw new Error(`The response carried no value for ${name}.`);
                }
              
                return typeof value === 'string' ? value : JSON.stringify(value);
              }
              
              // Phase 1: Set up the customer
              
              // Step 1: Read the merchant id off a sandbox sale
              const step1 = await call('POST', '/api/transactions', {
                "transactionType": "Sale",
                "cardData": {
                  "cardNumber": "4111111111111111",
                  "nameOnCard": "Jane Doe",
                  "expirationMonth": 12,
                  "expirationYear": 2030,
                  "cvv": 123
                },
                "invoiceData": {
                  "amounts": { "base": 10.00, "total": 10.00 }
                }
              });
              const merchantId = capture(step1.merchantId, 'merchantId');
              
              // Step 2: Create the customer you are invoicing
              const step2 = await call('POST', '/api/customers', {
                "merchantId": merchantId,
                "name": "Jane Doe",
                "isActive": true,
                "contactDetail": {
                  "primaryContactName": "Jane Doe",
                  "emailAddress": "jane.doe@example.com",
                  "phone": "5555550123",
                  "addresses": [
                    {
                      "address1": "100 Main Street",
                      "city": "Minneapolis",
                      "state": "MN",
                      "zip": "55401",
                      "isDefault": true
                    }
                  ]
                }
              });
              const customerId = capture(step2.id, 'customerId');
              
              // Phase 2: Write the invoice
              
              // Step 3: Create the invoice as a draft
              const step3 = await call('POST', '/api/invoicing/invoices', {
                "billerId": merchantId,
                "billerType": "Merchant",
                "recipientId": customerId,
                "recipientType": "Customer",
                "currency": "USD",
                "paymentTermsValue": "Net30",
                "recipientSnapshot": {
                  "name": "Jane Doe",
                  "email": "jane.doe@example.com"
                },
                "lineItems": [
                  {
                    "description": "Website redesign",
                    "quantity": 1,
                    "unitPrice": 1200.00
                  },
                  {
                    "description": "Managed hosting, monthly",
                    "quantity": 12,
                    "unitPrice": 25.00
                  }
                ]
              });
              const invoiceId = capture(step3.id, 'invoiceId');
              
              // Step 4: Issue the invoice
              await call('POST', `/api/invoicing/invoices/${encodeURIComponent(invoiceId)}/issue`);
              
              // Phase 3: Get paid
              
              // Step 5: Record the payment
              await call('POST', `/api/invoicing/invoices/${encodeURIComponent(invoiceId)}/record-payment`, {
                "amount": 1500.00,
                "paymentMethod": "Check",
                "notes": "Check received by mail."
              });
              
              // Step 6: Read the invoice back
              await call('GET', `/api/invoicing/invoices/${encodeURIComponent(invoiceId)}`);
              
              // Phase 4: Go further
              
              // Step 7: Send the invoice to the customer
              // In production you send the invoice rather than recording a payment by hand. The send call runs
              // the whole delivery workflow: it issues the invoice if it's still a draft, creates a payment link
              // and a view token for the recipient, marks the status Sent, and delivers the notification. That
              // last part needs a merchant with a configured email destination, which a fresh sandbox may not
              // have, and it's why this flow records a payment as its runnable path instead. Once you have
              // configured delivery, call send from your own integration and let the payment link do the
              // collecting.
              
              // Step 8: Download the invoice as a PDF
              // Any issued invoice can be rendered as a PDF from the snapshots and lines frozen at issue. Fetch
              // it when your customer asks for a copy or when your own records need the document rather than the
              // data. The response is the file itself, not JSON.
              
              // Step 9: Offer a payment plan
              // A larger invoice can be split into scheduled installments the platform collects against a stored
              // payment method. Create the plan on an issued invoice; each installment is applied to the balance
              // the same way the payment above was, so the invoice reaches Paid when the last one clears. Payment
              // plans, credit notes and recurring invoices each have their own reference pages.
              

              C#

              // Invoice a customer and get paid
              //
              // Create a customer, write them an invoice, issue it, and record the payment when it arrives, so
              // you know what the platform does at each stage of an invoice's life.
              //
              // Every API call in this blueprint, in order. Each value a call returns is passed to the calls
              // after it. A step that happens outside the API is a comment, and any failed call stops the script.
              
              using System.Text;
              using System.Text.Json;
              
              var baseUrl = "{{BASE_URL}}";
              var apiKey = "{{API_KEY}}";
              
              using var http = new HttpClient();
              http.DefaultRequestHeaders.Add("api-key", apiKey);
              
              // Sends one request and returns the parsed response body. A failed call throws.
              async Task<JsonElement> CallAsync(string method, string path, string? body = null)
              {
                  using var request = new HttpRequestMessage(new HttpMethod(method), baseUrl + path);
                  if (body is not null)
                  {
                      request.Content = new StringContent(body, Encoding.UTF8, "application/json");
                  }
              
                  using var response = await http.SendAsync(request);
                  var json = await response.Content.ReadAsStringAsync();
                  if (!response.IsSuccessStatusCode)
                  {
                      throw new HttpRequestException($"{method} {path} answered {(int)response.StatusCode}: {json}");
                  }
              
                  return json.Length == 0 ? default : JsonSerializer.Deserialize<JsonElement>(json);
              }
              
              // Turns a value read off a response into the text the API sent. A missing value throws.
              static string Capture(JsonElement value, string name) => value.ValueKind switch
              {
                  JsonValueKind.String => value.GetString()!,
                  JsonValueKind.Number or JsonValueKind.True or JsonValueKind.False => value.GetRawText(),
                  _ => throw new InvalidOperationException($"The response carried no value for {name}.")
              };
              
              // Phase 1: Set up the customer
              
              // Step 1: Read the merchant id off a sandbox sale
              var step1 = await CallAsync("POST", "/api/transactions", """
                  {
                    "transactionType": "Sale",
                    "cardData": {
                      "cardNumber": "4111111111111111",
                      "nameOnCard": "Jane Doe",
                      "expirationMonth": 12,
                      "expirationYear": 2030,
                      "cvv": 123
                    },
                    "invoiceData": {
                      "amounts": { "base": 10.00, "total": 10.00 }
                    }
                  }
                  """);
              var merchantId = Capture(step1.GetProperty("merchantId"), "merchantId");
              
              // Step 2: Create the customer you are invoicing
              var step2 = await CallAsync("POST", "/api/customers", $$"""
                  {
                    "merchantId": {{JsonSerializer.Serialize(merchantId)}},
                    "name": "Jane Doe",
                    "isActive": true,
                    "contactDetail": {
                      "primaryContactName": "Jane Doe",
                      "emailAddress": "jane.doe@example.com",
                      "phone": "5555550123",
                      "addresses": [
                        {
                          "address1": "100 Main Street",
                          "city": "Minneapolis",
                          "state": "MN",
                          "zip": "55401",
                          "isDefault": true
                        }
                      ]
                    }
                  }
                  """);
              var customerId = Capture(step2.GetProperty("id"), "customerId");
              
              // Phase 2: Write the invoice
              
              // Step 3: Create the invoice as a draft
              var step3 = await CallAsync("POST", "/api/invoicing/invoices", $$"""
                  {
                    "billerId": {{JsonSerializer.Serialize(merchantId)}},
                    "billerType": "Merchant",
                    "recipientId": {{JsonSerializer.Serialize(customerId)}},
                    "recipientType": "Customer",
                    "currency": "USD",
                    "paymentTermsValue": "Net30",
                    "recipientSnapshot": {
                      "name": "Jane Doe",
                      "email": "jane.doe@example.com"
                    },
                    "lineItems": [
                      {
                        "description": "Website redesign",
                        "quantity": 1,
                        "unitPrice": 1200.00
                      },
                      {
                        "description": "Managed hosting, monthly",
                        "quantity": 12,
                        "unitPrice": 25.00
                      }
                    ]
                  }
                  """);
              var invoiceId = Capture(step3.GetProperty("id"), "invoiceId");
              
              // Step 4: Issue the invoice
              await CallAsync("POST", $"/api/invoicing/invoices/{Uri.EscapeDataString(invoiceId)}/issue");
              
              // Phase 3: Get paid
              
              // Step 5: Record the payment
              await CallAsync("POST", $"/api/invoicing/invoices/{Uri.EscapeDataString(invoiceId)}/record-payment", """
                  {
                    "amount": 1500.00,
                    "paymentMethod": "Check",
                    "notes": "Check received by mail."
                  }
                  """);
              
              // Step 6: Read the invoice back
              await CallAsync("GET", $"/api/invoicing/invoices/{Uri.EscapeDataString(invoiceId)}");
              
              // Phase 4: Go further
              
              // Step 7: Send the invoice to the customer
              // In production you send the invoice rather than recording a payment by hand. The send call runs
              // the whole delivery workflow: it issues the invoice if it's still a draft, creates a payment link
              // and a view token for the recipient, marks the status Sent, and delivers the notification. That
              // last part needs a merchant with a configured email destination, which a fresh sandbox may not
              // have, and it's why this flow records a payment as its runnable path instead. Once you have
              // configured delivery, call send from your own integration and let the payment link do the
              // collecting.
              
              // Step 8: Download the invoice as a PDF
              // Any issued invoice can be rendered as a PDF from the snapshots and lines frozen at issue. Fetch
              // it when your customer asks for a copy or when your own records need the document rather than the
              // data. The response is the file itself, not JSON.
              
              // Step 9: Offer a payment plan
              // A larger invoice can be split into scheduled installments the platform collects against a stored
              // payment method. Create the plan on an issued invoice; each installment is applied to the balance
              // the same way the payment above was, so the invoice reaches Paid when the last one clears. Payment
              // plans, credit notes and recurring invoices each have their own reference pages.
              

              pip install requests

              Python

              # Invoice a customer and get paid
              #
              # Create a customer, write them an invoice, issue it, and record the payment when it arrives, so you
              # know what the platform does at each stage of an invoice's life.
              #
              # Every API call in this blueprint, in order. Each value a call returns is passed to the calls after
              # it. A step that happens outside the API is a comment, and any failed call stops the script.
              
              from urllib.parse import quote
              
              import json
              import requests
              
              BASE_URL = "{{BASE_URL}}"
              API_KEY = "{{API_KEY}}"
              
              
              # Sends one request and returns the parsed response body. A failed call raises.
              def call(method, path, body=None):
                  response = requests.request(
                      method,
                      BASE_URL + path,
                      headers={"api-key": API_KEY},
                      json=body,
                  )
                  response.raise_for_status()
                  return response.json() if response.content else None
              
              
              # Turns a value read off a response into the text the API sent. A missing value raises.
              def capture(value, name):
                  if value is None:
                      raise ValueError(f"The response carried no value for {name}.")
                  return value if isinstance(value, str) else json.dumps(value)
              
              
              # Phase 1: Set up the customer
              
              # Step 1: Read the merchant id off a sandbox sale
              step1 = call("POST", "/api/transactions", {
                "transactionType": "Sale",
                "cardData": {
                  "cardNumber": "4111111111111111",
                  "nameOnCard": "Jane Doe",
                  "expirationMonth": 12,
                  "expirationYear": 2030,
                  "cvv": 123
                },
                "invoiceData": {
                  "amounts": { "base": 10.00, "total": 10.00 }
                }
              })
              merchant_id = capture(step1["merchantId"], "merchantId")
              
              # Step 2: Create the customer you are invoicing
              step2 = call("POST", "/api/customers", {
                "merchantId": merchant_id,
                "name": "Jane Doe",
                "isActive": True,
                "contactDetail": {
                  "primaryContactName": "Jane Doe",
                  "emailAddress": "jane.doe@example.com",
                  "phone": "5555550123",
                  "addresses": [
                    {
                      "address1": "100 Main Street",
                      "city": "Minneapolis",
                      "state": "MN",
                      "zip": "55401",
                      "isDefault": True
                    }
                  ]
                }
              })
              customer_id = capture(step2["id"], "customerId")
              
              # Phase 2: Write the invoice
              
              # Step 3: Create the invoice as a draft
              step3 = call("POST", "/api/invoicing/invoices", {
                "billerId": merchant_id,
                "billerType": "Merchant",
                "recipientId": customer_id,
                "recipientType": "Customer",
                "currency": "USD",
                "paymentTermsValue": "Net30",
                "recipientSnapshot": {
                  "name": "Jane Doe",
                  "email": "jane.doe@example.com"
                },
                "lineItems": [
                  {
                    "description": "Website redesign",
                    "quantity": 1,
                    "unitPrice": 1200.00
                  },
                  {
                    "description": "Managed hosting, monthly",
                    "quantity": 12,
                    "unitPrice": 25.00
                  }
                ]
              })
              invoice_id = capture(step3["id"], "invoiceId")
              
              # Step 4: Issue the invoice
              call("POST", f"/api/invoicing/invoices/{quote(invoice_id, safe='')}/issue")
              
              # Phase 3: Get paid
              
              # Step 5: Record the payment
              call("POST", f"/api/invoicing/invoices/{quote(invoice_id, safe='')}/record-payment", {
                "amount": 1500.00,
                "paymentMethod": "Check",
                "notes": "Check received by mail."
              })
              
              # Step 6: Read the invoice back
              call("GET", f"/api/invoicing/invoices/{quote(invoice_id, safe='')}")
              
              # Phase 4: Go further
              
              # Step 7: Send the invoice to the customer
              # In production you send the invoice rather than recording a payment by hand. The send call runs the
              # whole delivery workflow: it issues the invoice if it's still a draft, creates a payment link and a
              # view token for the recipient, marks the status Sent, and delivers the notification. That last part
              # needs a merchant with a configured email destination, which a fresh sandbox may not have, and it's
              # why this flow records a payment as its runnable path instead. Once you have configured delivery,
              # call send from your own integration and let the payment link do the collecting.
              
              # Step 8: Download the invoice as a PDF
              # Any issued invoice can be rendered as a PDF from the snapshots and lines frozen at issue. Fetch it
              # when your customer asks for a copy or when your own records need the document rather than the
              # data. The response is the file itself, not JSON.
              
              # Step 9: Offer a payment plan
              # A larger invoice can be split into scheduled installments the platform collects against a stored
              # payment method. Create the plan on an issued invoice; each installment is applied to the balance
              # the same way the payment above was, so the invoice reaches Paid when the last one clears. Payment
              # plans, credit notes and recurring invoices each have their own reference pages.
              

              Reconnecting to the server

              Could not reconnect

              This session has ended

              Attempt 1

              Your work on this page is still here. Retrying keeps it; reloading starts the page again.

              The server no longer holds this page's state, so it has to be loaded again.