Skip to main content
Settlements close out invoices by recording proof of payment onchain. When you submit a settlement, Retempo doesn’t just log a record — it executes a real transaction against the Arc protocol, waits for the receipt, and only marks the invoice PAID once the SettlementRecorded event is observed. Every USDC settlement you see as CONFIRMED maps to a verifiable onchain transaction.
Retempo never fabricates transaction hashes or confirms settlements without a real Arc receipt. A settlement that reaches CONFIRMED status always corresponds to a real, observable onchain event.

What happens when you settle

When you POST a new settlement, Retempo executes the following steps automatically:
1

Create the settlement record

Retempo creates a settlement record with status PENDING, linking it to the invoice, payer, and merchant you specified.
2

Submit to Arc

The backend calls RetempoSettlement.recordSettlement() on the Arc smart contract, submitting the settlement onchain.
3

Wait for the transaction receipt

Retempo waits for the Arc transaction to be mined and retrieves the onchain receipt. If the transaction reverts or times out, the settlement moves to FAILED.
4

Observe the SettlementRecorded event

Once the receipt confirms success, Retempo checks that the SettlementRecorded event was emitted by the Arc contract. If the event is observed, the settlement moves to CONFIRMED.
5

Mark the invoice PAID

With a CONFIRMED settlement, Retempo automatically updates the linked invoice status to PAID. No further action is required on your end.

Creating a settlement

To create a settlement, send a POST request to /api/v1/settlements. You must supply an invoiceId and a referenceHash. The referenceHash must be a 32-byte hex value — the 0x prefix followed by exactly 64 hexadecimal characters. You also need to supply payerAddress (the subscriber’s wallet) and merchantAddress (the service owner’s wallet). Retempo validates that the payerId matches the invoice’s userId and that the merchantId matches the service’s ownerId before submitting to Arc.
curl --request POST \
  --url https://api.retempo.xyz/api/v1/settlements \
  --header 'Content-Type: application/json' \
  --data '{
    "invoiceId": "inv_01hx9r5js9tv0w6eb7zpg8x",
    "referenceHash": "0xabc123def456abc123def456abc123def456abc123def456abc123def456abcd",
    "payerAddress": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b",
    "merchantAddress": "0xdeadbeefcafe1234567890abcdef1234567890ab",
    "amount": "49.000000",
    "currency": "USDC",
    "recordedAt": "2025-01-14T13:05:00.000Z"
  }'
The response includes both the settlement record and a chain object that contains the raw Arc transaction details:
{
  "settlement": {
    "id": "stl_01hx9s6kt0uw1x7fc8aqh9y",
    "invoiceId": "inv_01hx9r5js9tv0w6eb7zpg8x",
    "serviceId": "svc_01hx9kz3v8mq2t4yw6npd7e",
    "payerId": "usr_01hx9n2fp8qt6s3bz4wmd5k",
    "merchantId": "usr_01hx9kz0a3bq1r7fm5ctd2w",
    "status": "CONFIRMED",
    "amount": "49.000000",
    "currency": "USDC",
    "referenceHash": "0xabc123def456abc123def456abc123def456abc123def456abc123def456abcd",
    "transactionHash": "0x9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e",
    "recordedAt": "2025-01-14T13:05:00.000Z",
    "createdAt": "2025-01-14T13:04:42.000Z",
    "invoice": {
      "id": "inv_01hx9r5js9tv0w6eb7zpg8x",
      "status": "PAID",
      "amount": "49.000000",
      "currency": "USDC"
    },
    "service": {
      "id": "svc_01hx9kz3v8mq2t4yw6npd7e",
      "name": "DataStream Pro"
    },
    "payer": {
      "id": "usr_01hx9n2fp8qt6s3bz4wmd5k",
      "email": "agent@example.io"
    },
    "merchant": {
      "id": "usr_01hx9kz0a3bq1r7fm5ctd2w",
      "email": "billing@datastream.io"
    }
  },
  "chain": {
    "transactionHash": "0x9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e",
    "receiptStatus": "success",
    "eventObserved": true,
    "executor": "0xretempo_executor_address",
    "circleTransactionId": null,
    "circleTransactionState": null
  }
}

Settlement statuses

A settlement transitions through the following statuses as it moves from creation to finality:
StatusMeaning
PENDINGThe settlement record has been created. The transaction has not yet been submitted to Arc.
SUBMITTEDThe transaction has been sent to Arc and Retempo is waiting for a receipt.
CONFIRMEDArc returned a successful receipt and the SettlementRecorded event was observed. The linked invoice has been marked PAID.
FAILEDThe transaction failed onchain, timed out, or the SettlementRecorded event was not observed. The invoice remains unpaid. You may create a new settlement to retry.

Fetching a settlement

To retrieve the current state of a settlement along with its linked invoice, service, payer, and merchant, send a GET request with the settlement ID:
curl --request GET \
  --url https://api.retempo.xyz/api/v1/settlements/stl_01hx9s6kt0uw1x7fc8aqh9y \
  --header 'Content-Type: application/json'
{
  "settlement": {
    "id": "stl_01hx9s6kt0uw1x7fc8aqh9y",
    "invoiceId": "inv_01hx9r5js9tv0w6eb7zpg8x",
    "serviceId": "svc_01hx9kz3v8mq2t4yw6npd7e",
    "payerId": "usr_01hx9n2fp8qt6s3bz4wmd5k",
    "merchantId": "usr_01hx9kz0a3bq1r7fm5ctd2w",
    "status": "CONFIRMED",
    "amount": "49.000000",
    "currency": "USDC",
    "referenceHash": "0xabc123def456abc123def456abc123def456abc123def456abc123def456abcd",
    "transactionHash": "0x9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e",
    "recordedAt": "2025-01-14T13:05:00.000Z",
    "createdAt": "2025-01-14T13:04:42.000Z",
    "invoice": {
      "id": "inv_01hx9r5js9tv0w6eb7zpg8x",
      "status": "PAID",
      "amount": "49.000000",
      "currency": "USDC"
    },
    "service": {
      "id": "svc_01hx9kz3v8mq2t4yw6npd7e",
      "name": "DataStream Pro"
    },
    "payer": {
      "id": "usr_01hx9n2fp8qt6s3bz4wmd5k",
      "email": "agent@example.io"
    },
    "merchant": {
      "id": "usr_01hx9kz0a3bq1r7fm5ctd2w",
      "email": "billing@datastream.io"
    }
  }
}
If you fetch a settlement with status SUBMITTED, Retempo automatically re-checks Arc for the latest receipt before returning the response. The status you receive reflects the most up-to-date onchain state — no need to poll separately.

Idempotency

If you submit a POST /api/v1/settlements request with an invoiceId and referenceHash that already correspond to a CONFIRMED settlement, Retempo returns 200 with the existing settlement record instead of creating a duplicate. You do not need to track whether a settlement has already been confirmed — Retempo handles this for you. This means it is safe to retry a settlement request if you experience a network timeout or are unsure whether your first request landed. If the settlement is already confirmed, you’ll get the existing record back at no cost.