Payments
A payment record tracks an amount an individual owes to an agency: a fine, fee, restitution, bond, or any other balance due. Creating a payment record does not charge anyone and does not move money. eCourtDate uses the record to schedule automated reminder messages through the payment's flow, and each reminder can include a link the recipient uses to view and pay the balance through the agency's portal.
All endpoints use the base URL for your assigned region (see Environments & Regions) and require a Bearer token (see Authentication):
Authorization: Bearer {access_token}
Content-Type: application/json
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /v1/payments | List payments |
GET | /v1/payments/total | Count payments matching filters |
GET | /v1/payments/uniques | List distinct values for a field |
GET | /v1/payments/{uuid} | Get a single payment |
POST | /v1/payments | Create a payment |
PATCH | /v1/payments/{uuid} | Update a payment |
DELETE | /v1/payments/{uuid} | Delete a payment (soft delete) |
PUT | /v1/payments/{uuid}/archive | Archive a payment |
PUT | /v1/payments/{uuid}/restore | Restore an archived or deleted payment |
POST | /v1/payments/{uuid}/process | Reprocess a payment (reschedule reminders) |
The Payment Object
| Field | Type | Description |
|---|---|---|
uuid | string | Unique identifier, generated when the payment is created. |
client | string | UUID of the client who owes the payment. Reminders are sent to this client's contacts. |
payment_reference | string | Your identifier for the payment, such as an invoice, receipt, or ticket number. Auto-generated as a random 12-character value when omitted on create. |
amount | number | Amount due. Must be greater than zero. |
status | string | Current status. Statuses are agency-defined text values, such as draft, outstanding, or paid. |
type | string | Payment type, such as fine or fee. Types are agency-defined text values. |
issued_at | string | Issue date in YYYY-MM-DD format. |
due_at | string | Due date in YYYY-MM-DD format. |
description | string | Short description of what the payment is for. |
notes | string | Additional notes about the payment. Available to messages via the [PaymentNotes] merge tag. |
case_number | string | Case number tied to the payment. |
citation | string | Citation identifier tied to the payment. |
flow | string | UUID of the flow that schedules this payment's reminder messages. |
portal | string | UUID of the portal that hosts the payment's page. |
location | string | UUID of the location tied to the payment. |
location_notes | string | Notes about the payment's location. |
contact | string | Contact tied to the payment. |
upload | string | UUID of the file import associated with the payment, when the payment is linked to a file import. |
url | string | Unique slug for the payment's link. The [PaymentLink] merge tag resolves to this link in messages. Generated automatically. |
created_by | string | Email or UUID of the user or API client that created the payment. |
created_at | string | Creation timestamp, UTC, YYYY-MM-DD HH:MM:SS. |
updated_at | string | Last update timestamp, UTC. |
archived_at | string | Set when the payment is archived, otherwise null. |
deleted_at | string | Set when the payment is deleted, otherwise null. |
Responses also include computed amount fields:
| Field | Type | Description |
|---|---|---|
raw_amount | string | The stored amount with currency symbols and commas removed. |
amount | number | The amount as a number. |
formatted_amount | string | The amount prefixed with the currency symbol, for example $250.75. |
Retrieving a single payment (GET /v1/payments/{uuid}) also returns the names of related records: flow_name, location_name, and portal_name. These are null when the related record is not set, archived, or deleted. List responses omit these name fields.
Create a Payment
POST /v1/payments
Request:
curl -X POST "$BASE_URL/v1/payments" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"client_reference": "CLIENT-12345",
"payment_reference": "INV-2024-0042",
"amount": 250.75,
"type": "fine",
"status": "outstanding",
"issued_at": "2024-03-01",
"due_at": "2024-03-31",
"case_number": "CASE-2024-001",
"description": "Traffic fine"
}'
Response (201):
{
"uuid": "{payment_uuid}",
"client": "{client_uuid}",
"payment_reference": "INV-2024-0042",
"amount": 250.75,
"raw_amount": "250.75",
"formatted_amount": "$250.75",
"type": "fine",
"status": "outstanding",
"issued_at": "2024-03-01",
"due_at": "2024-03-31",
"case_number": "CASE-2024-001",
"description": "Traffic fine",
"flow": "{flow_uuid}",
"portal": "{portal_uuid}",
"location": "{location_uuid}",
"url": "aB3dE5fG7hJ9",
"created_by": "integration@agency.gov",
"created_at": "2024-03-01 14:22:05"
}
Request Fields and Defaults
Only amount is required. Every other field is optional and falls back to a default:
| Field | Default when omitted |
|---|---|
amount | Required. Currency symbols ($, ¢) and commas are stripped, then the value must be numeric and greater than zero, otherwise the API returns 400 with Invalid Payment amount. 250.75, "250.75", "$250.75", and "$1,250.00" are all accepted and stored as 1250.00. |
client / client_reference | No client is attached. Payments without a client do not generate reminder messages. See Attaching a Client. |
payment_reference | A random 12-character value is generated. |
issued_at | Today's date in the agency's timezone. |
due_at | issued_at plus the agency's Payment Due Date setting (30 days when the setting is not configured). |
status | The agency's default payment status setting, or draft when no default is configured. |
type | The agency's default payment type setting, or null. |
flow | The agency's default payment flow. See Attaching a Flow. |
portal | The agency's default portal. |
location | The agency's default location. |
url | A unique random slug is generated. This becomes the payment's link. |
Attaching a Client
Identify the client with either field:
client: the client's UUID.client_reference: your identifier for the client, as stored on the client record.
The API matches only active clients (not archived, not deleted). If no match is found, the payment is created without a client, the response omits the client field, and no reminder messages are scheduled. Verify the client field in the response when reminders matter.
Attaching a Flow
A flow defines the reminder message schedule for the payment (for example: a message when the payment is issued, 7 days before the due date, and on the due date). Identify the flow with flow (UUID), flow_reference, or the flow's exact name. If no value is provided or no match is found, the agency's default payment flow is used; when no payment flow is flagged as the default, the first payment-type flow found is used. If the agency has no payment-type flow at all, no reminders are scheduled.
What Happens After Create
- The payment is saved and returned with a
201status. - If a client is attached and the payment's status and type are not flagged with Disable Messages, a
payment_createdauto message trigger fires. Agencies can configure an auto message for this trigger to confirm the new balance to the client. - The payment is queued for processing, which schedules reminder messages from the flow. See How Payment Reminders Work.
Pass "skip_sync": true in the request body to skip step 3, the flow reminder processing. The record is still saved, and the payment_created auto message in step 2 still fires if configured, so skip_sync suppresses only the scheduled flow reminders, not a confirmation auto message.
List Payments
GET /v1/payments
curl -X GET "$BASE_URL/v1/payments?status=outstanding&due_from=2024-03-01&due_to=2024-03-31&limit=50" \
-H "Authorization: Bearer $TOKEN"
Response (200): a JSON array of payment objects.
Query Parameters
Filtering:
| Parameter | Description |
|---|---|
search | Partial match on payment_reference. |
payment_reference | Exact match on payment_reference. reference is an accepted alias. |
client | Filter by client UUID. |
status | Filter by exact status. |
type | Filter by exact type. |
case_number | Filter by exact case number. |
citation | Filter by exact citation. |
description | Filter by exact description. |
flow | Filter by flow UUID. |
portal | Filter by portal UUID. |
location | Filter by location UUID. |
contact | Filter by contact. |
upload | Filter by the file import (upload) UUID that created the payments. |
url | Filter by the payment's link slug. |
due_from | Payments with due_at on or after this date (YYYY-MM-DD). |
due_to | Payments with due_at on or before this date. |
issued_from | Payments with issued_at on or after this date. |
issued_to | Payments with issued_at on or before this date. |
archived | Set to 1 to return only archived payments. By default, archived payments are excluded. |
trashed | Set to 1 to return only deleted payments. By default, deleted payments are excluded. deleted is an accepted alias. |
Pagination and shaping:
| Parameter | Default | Description |
|---|---|---|
limit | 10 | Records per page. Maximum 100. |
skip | 0 | Records to skip. |
sort | created_at | Field to sort by. Any payment field is accepted. |
sortDirection | desc | asc or desc. |
fields | all fields | Comma-separated list of fields to return, for example fields=uuid,amount,status,due_at. |
Combine date filters for common reports. Payments coming due this month: ?due_from=2024-03-01&due_to=2024-03-31. Payments issued last week that are still in a given status: ?issued_from=2024-02-19&issued_to=2024-02-25&status=outstanding.
Count Payments
GET /v1/payments/total
Returns the number of payments matching the same filters as List Payments, as a bare number. Useful for pagination math and dashboards without transferring records.
curl -X GET "$BASE_URL/v1/payments/total?status=outstanding" \
-H "Authorization: Bearer $TOKEN"
Response (200):
42
List Distinct Values
GET /v1/payments/uniques
Returns the distinct values in use for one field, as a JSON array of strings. Supported fields: type (default) and description. Any other field returns 400 with Invalid unique attribute. Use this to build filter dropdowns from values agencies actually use. This endpoint honors the limit parameter, so it returns at most 10 values by default; pass limit=100 for a fuller list.
curl -X GET "$BASE_URL/v1/payments/uniques?field=type" \
-H "Authorization: Bearer $TOKEN"
Response (200):
["fine", "fee", "restitution"]
Get a Payment
GET /v1/payments/{uuid}
Returns the payment object, including the computed amount fields and the related record names (flow_name, location_name, portal_name). Returns 404 with a message of Payment {uuid} not found when no payment matches.
curl -X GET "$BASE_URL/v1/payments/{payment_uuid}" \
-H "Authorization: Bearer $TOKEN"
Response (200):
{
"uuid": "{payment_uuid}",
"client": "{client_uuid}",
"payment_reference": "INV-2024-0042",
"amount": 250.75,
"raw_amount": "250.75",
"formatted_amount": "$250.75",
"type": "fine",
"status": "outstanding",
"issued_at": "2024-03-01",
"due_at": "2024-03-31",
"case_number": "CASE-2024-001",
"citation": null,
"description": "Traffic fine",
"notes": null,
"flow": "{flow_uuid}",
"flow_name": "Payment Reminders",
"portal": "{portal_uuid}",
"portal_name": "Agency Portal",
"location": "{location_uuid}",
"location_name": "Main Courthouse",
"location_notes": null,
"contact": null,
"upload": null,
"url": "aB3dE5fG7hJ9",
"created_by": "integration@agency.gov",
"created_at": "2024-03-01 14:22:05",
"updated_at": "2024-03-01 14:22:05",
"archived_at": null,
"deleted_at": null
}
Single-payment responses are cached. After an update through the API the cache is refreshed automatically; changes made outside the API can take a short time to appear.
Update a Payment
PATCH /v1/payments/{uuid}
Send only the fields you want to change. Fields not included are left as they are. updated_at is set automatically.
curl -X PATCH "$BASE_URL/v1/payments/{payment_uuid}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "paid"
}'
Response (200): the updated fields.
After a successful update the payment is reprocessed: unsent scheduled reminders are removed and rescheduled from the flow using the payment's current data. Messages already sent are not affected. If the new status or type is one the agency has flagged to disable messages (for example a paid status), no new reminders are scheduled. See How Payment Reminders Work.
Unlike create, PATCH writes the fields you send without applying defaults, so send complete values (for example, a full YYYY-MM-DD date for due_at).
Updating the Amount
To change a payment's amount, send a PATCH with the new amount, and optionally a new status in the same request:
curl -X PATCH "$BASE_URL/v1/payments/{payment_uuid}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 175.00,
"status": "partial"
}'
The amount is normalized the same way on update as on create: currency symbols ($, ¢) and commas are stripped, and the value must be numeric and greater than zero, so 175.00, "175.00", and "$1,175.00" are all accepted. After the update, reminders are rescheduled from the payment's current data, so future messages using [PaymentAmount] reflect the new value; already-sent messages keep the amount they were sent with. To stop reminders once a balance is settled, update the status to one the agency flags to disable messages, or archive the payment, rather than setting the amount to zero.
Delete a Payment
DELETE /v1/payments/{uuid}
Soft-deletes the payment by setting deleted_at. Any scheduled, unsent reminder messages for the payment are cancelled. The record remains retrievable with the trashed=1 list filter and can be brought back with Restore.
Response (204): no body.
Archive a Payment
PUT /v1/payments/{uuid}/archive
Sets archived_at, removes the payment from default list results, and cancels any scheduled, unsent reminder messages. Archiving suits payments that are resolved or no longer active but should stay out of the trash. Archived payments are retrievable with the archived=1 list filter.
Response (200):
{"message": "Payment {payment_uuid} archived"}
Restore a Payment
PUT /v1/payments/{uuid}/restore
Clears both archived_at and deleted_at, marks the payment as unprocessed, and queues it for processing, which reschedules reminder messages from the flow.
Response (200):
{"message": "Payment {payment_uuid} restored"}
Reprocess a Payment
POST /v1/payments/{uuid}/process
Queues the payment for processing: scheduled unsent reminders are removed and rebuilt from the payment's flow and current data. Use this after changing a client's contacts, editing the flow, or fixing payment data, to bring the reminder schedule back in line. /v1/payments/{uuid}/sync is an accepted alias for the same operation.
Response (202):
{"message": "Syncing Payment"}
Returns 400 when the {uuid} path value is not a valid UUID.
How Payment Reminders Work
When a payment is created, updated, restored, or reprocessed, eCourtDate rebuilds its reminder schedule:
- Scheduled, unsent flow reminder messages attached to the payment are removed. Messages already sent are kept, and unsent auto messages (such as a
payment_createdconfirmation) are also kept. - The payment's flow defines which messages to send and when, relative to dates such as the issue and due date.
- One message is scheduled per flow step for each of the client's notifiable contacts (phone and email).
No reminders are scheduled when any of the following is true:
- The payment has no client attached, or the client has no notifiable contacts.
- The payment has no flow, or its flow has no messages.
- The payment amount is zero or missing.
- The payment is archived or deleted.
- The payment's status or type matches an agency status with Disable Messages enabled. Agencies typically flag statuses like
paidthis way so reminders stop once a balance is settled. - The client's status, type, or group matches an agency client status with Disable Messages enabled.
If reminders are not going out, check these conditions in order: confirm the response from GET /v1/payments/{uuid} shows a client and a flow, then confirm the client has opted-in contacts (GET /v1/contacts?client={client_uuid}), then review the payment's status against the agency's status settings.
Merge Tags in Payment Messages
Reminder messages and one-off messages attached to a payment can include these merge tags:
| Tag | Inserts |
|---|---|
[PaymentAmount] | The payment amount. |
[PaymentDueDate] | The due date. |
[PaymentIssueDate] | The issue date. |
[PaymentReference] | The payment reference. |
[PaymentLink] | The payment's unique link. |
[PaymentStatus] | The status. |
[PaymentType] | The type. |
[PaymentDescription] | The description. |
[PaymentNotes] | The notes. |
[PaymentCitation] | The citation. |
[TotalPayments] | The client's total payment balance. Needs only a client, not an attached payment. |
See Merge Tags for resolution rules and the full tag catalog.
Sending a One-Off Payment Message
To send a single message about a payment outside the flow schedule, attach the payment when sending:
curl -X POST "$BASE_URL/v1/messages/oneoffs" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "+15551234567",
"subject": "Balance Due",
"content": "You owe [PaymentAmount] by [PaymentDueDate]. Pay online: [PaymentLink]",
"payment": "{payment_uuid}"
}'
To list every message tied to a payment: GET /v1/messages?payment={payment_uuid}.
Webhooks
Payment webhook events are delivered when payment transactions are processed. Subscribe to keep an external system in sync without polling. See Webhook Event Types and Webhook Configuration.
FAQs
Does creating a payment charge the client or process a transaction?
No. A payment record tracks an amount owed. The recipient pays through the agency's portal using the payment link, and payment webhook events report transaction activity. The API record is the source for reminders and reporting, not a charge instruction.
How do I update a payment's amount?
Send a PATCH /v1/payments/{uuid} with the new amount, and optionally a new status in the same request, for example {"amount": 175.00, "status": "partial"}. The amount is normalized the same way as on create, so currency symbols and commas are accepted. The update reprocesses the payment, so future reminder messages reflect the new amount; messages already sent are unchanged. This is the recommended way to record a revised balance or a partial payment.
What formats does amount accept?
Numbers and numeric strings, with or without currency symbols ($, ¢) and commas: 250.75, "250.75", "$250.75", and "$1,250.00" are all valid. On both create and update, the symbols and commas are stripped and the remaining value must be numeric and greater than zero, or the API returns 400 with Invalid Payment amount.
Which payment statuses are valid?
Statuses are agency-defined text values, not a fixed list. A new payment defaults to the agency's default payment status, or draft when none is configured. To see the statuses an agency uses in practice, list existing payments or check the agency's status settings. Statuses flagged with Disable Messages stop reminder scheduling for payments in that status.
Can I use my own invoice or receipt numbers?
Yes. Set payment_reference when creating the payment and filter by it later with GET /v1/payments?payment_reference=INV-2024-0042. When omitted, the API generates a random 12-character reference.
How do I mark a payment as paid and stop its reminders?
PATCH /v1/payments/{uuid} with the agency's paid status, for example {"status": "paid"}. Updating reprocesses the payment: unsent reminders are removed, and no new ones are scheduled when the status is flagged with Disable Messages. Archiving or deleting the payment also cancels unsent reminders.
Why are no reminder messages going out for a payment?
The most common causes: the payment has no client attached (check the client field on the payment), the client has no opted-in contacts, the payment has no flow with messages, the amount is zero, or the payment's status or type is flagged to disable messages. The full list of conditions is in How Payment Reminders Work.
What is the difference between deleting and archiving a payment?
Both cancel unsent reminders and remove the payment from default list results. Archiving (PUT /v1/payments/{uuid}/archive) is for payments that are resolved or inactive; they remain available with the archived=1 filter. Deleting (DELETE /v1/payments/{uuid}) is a soft delete for records that should not have been created; they remain available with the trashed=1 filter. Either state can be undone with PUT /v1/payments/{uuid}/restore, which also reschedules reminders.
Does updating a payment re-send messages that were already sent?
No. Reprocessing only removes and reschedules messages that have not been sent yet. Delivered messages are never recalled or duplicated by an update.
Can a client have more than one open payment?
Yes. Each payment is an independent record with its own reminders, link, and due date. The [TotalPayments] merge tag inserts the client's combined balance into a message, and GET /v1/payments?client={client_uuid} lists all of a client's payments.
What timezone are payment dates in?
issued_at and due_at are calendar dates (YYYY-MM-DD) interpreted in the agency's timezone; the default issued_at is today's date in that timezone. Timestamps such as created_at and updated_at are UTC in YYYY-MM-DD HH:MM:SS format.
How do I import many payments at once?
The API creates one payment per POST /v1/payments request. For bulk loads, batch your requests within rate limits, or import payments from files over SFTP. When a payment is linked to a file import, its upload field holds the import's UUID, so you can filter by a batch with GET /v1/payments?upload={upload_uuid}.
Related Documentation
- API Reference: all resources on one page
- Merge Tags: payment tags in message templates
- Webhook Event Types: payment event delivery
- Rate Limits: request budgets for batch operations
- Error Handling: status codes and error responses