Contracts
Create & send digital contracts · E-signatures · Linked payments & subscriptions
Summary
Contracts enable merchants to create digital agreements that customers must sign before a payment can proceed. A contract can be linked to a Payment Link (one-time payment), a Subscription (recurring payment), or an Installment plan. The customer receives the contract via email, signs it electronically (with optional document upload), and is then directed to complete payment.
Contracts support HTML-based templates with {{ signature }} and {{ input::placeholder }} placeholders, allowing merchants to build reusable contract templates. The system automatically generates a contract number in CT-YYYYMMDD#### format.
Contract Lifecycle
- Create — Merchant creates a contract with HTML content, customer, amount, and payment type. A Payment Link or Subscription is automatically created and linked.
- Notify — Customer receives an email with a link to view and sign the contract. The email includes a “Pay Now” button directing them to the signing page.
- View — Customer opens the contract and sees the agreement with signature fields and input fields. If a document upload is required, a file upload area is displayed.
- Sign — Customer fills in all signature and input fields, optionally uploads a supporting document, and submits. The contract status changes to
SIGNED. - Pay — After signing, the customer is directed to the linked Payment Link or Subscription page to complete payment. The payment page will not allow access until the contract is signed.
Contract Statuses
UNSIGNED
Initial state. Contract has been created and sent to the customer but has not yet been signed.
SIGNED
Customer has signed the contract. The linked payment page is now accessible.
If a Payment Link has an UNSIGNED contract, the payment page will throw a PaymentLinkContractUnsignedException and prevent the customer from paying.
Processing Flow
Authentication
Merchant API (Private)
All merchant-facing endpoints require a valid Bearer token and are scoped to a business:
Authorization: Bearer {access_token}
Content-Type: application/json
Base URL pattern: /api/{business_id}/contracts
Customer API (Public)
Public endpoints for viewing and signing contracts do not require authentication:
GET /api/contracts/{contract_id}/show
POST /api/contracts/{contract_id}/sign
Create Contract
POST /api/{business}/contracts
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
contract | string | Yes | HTML content of the contract. Supports {{ signature }} and {{ input::Label }} placeholders. |
customerId | string (UUID) | Yes | Customer who will receive and sign the contract |
amount | number | Yes | Payment amount linked to the contract |
includeDocument | boolean | Yes | Whether to require the customer to upload a document when signing |
paymentType | string | Yes | 1 = Payment Link, 2 = Subscription, 3 = Installment |
sequence | number | If type 2 or 3 | Payment frequency (see Payment Types) |
startDate | date | If type 2 or 3 | First charge date for recurring payments |
numberOfBills | number | If type 3 | Total number of installments |
description | string | No | Contract description |
paymentMethod | string | No | Default: rapidcents_direct_manual_card_entry |
customInvoiceNumber | string | No | Custom invoice number for the linked Payment Link |
POST /api/{business}/contracts
Content-Type: application/json
Authorization: Bearer {token}
{
"contract": "<h1>Service Agreement</h1><p>I, {{ input::Full Name }}, agree to...</p><p>Signature: {{ signature }}</p>",
"customerId": "customer-uuid",
"amount": 500.00,
"includeDocument": true,
"paymentType": "1",
"description": "Monthly service agreement"
}
{
"ok": true,
"contract": {
"id": "contract-uuid",
"contract_number": "CT-202602190001",
"status": "UNSIGNED",
"payment_link_id": "payment-link-uuid",
"has_file": true,
"created_at": "2026-02-19T12:00:00.000000Z"
},
"message": "Contract created successfully"
}
List Contracts
GET /api/{business}/contracts
Returns a paginated list of contracts. Includes permission flags for the current user.
{
"ok": true,
"contracts": { /* paginated collection */ },
"business": { /* business object */ },
"isRoleAdmin": true,
"canUpdateContract": true,
"canDeleteContract": true,
"filters": { "fromDate": null, "toDate": null }
}
Edit Contract (Form Data)
GET /api/{business}/contracts/{contract}/edit
Returns the contract data in a format suitable for populating an edit form.
Update Contract
PUT /api/{business}/contracts/{contract}
Updates an existing contract. Only editable if the contract has not been signed and its linked payment has not been completed.
Delete Contract
DELETE /api/{business}/contracts/{contract}
Deletes a contract and its linked Payment Link or Subscription. Only deletable if the linked payment has not been completed.
{
"ok": true,
"message": "Contract deleted successfully"
}
Contract Details
GET /api/{business}/contracts/{contract}/details
Returns full details of a contract, including its signed content and linked payment information.
Export Contracts
GET /api/{business}/contracts/export
Returns all contracts matching the filter criteria in a JSON format suitable for CSV or spreadsheet export.
Contract Templates
List Templates
GET /api/{business}/contracts/templates
Returns all saved contract templates for the business.
Save Template
POST /api/{business}/contracts/storeTemplate
Saves the current contract content as a reusable template. The placeholder [Your business name] is automatically replaced with the business legal name when used.
View Contract (Public)
GET /api/contracts/{contract}/show
Loads the contract for the customer to view and sign. Returns the contract HTML, business branding (logo), customer email, and 3D Secure configuration.
If the contract has been deleted, or if its linked Payment Link has already been paid, the endpoint will return an error.
{
"ok": true,
"contract": {
"id": "contract-uuid",
"content": "<h1>Service Agreement</h1>...",
"status": "UNSIGNED",
"has_file": true
},
"business": { "legal_name": "Acme Corp" },
"logo": "https://s3.amazonaws.com/...",
"dddSecure": true,
"customerEmail": "[email protected]"
}
Sign Contract (Public)
POST /api/contracts/{contract}/sign
Submits the customer's signatures, input values, and optional document. Uses multipart/form-data when a file is included.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
signature-1, signature-2, ... | string | Yes | One field per {{ signature }} placeholder in the contract (base64 image) |
input-1, input-2, ... | string | Yes | One field per {{ input::Label }} placeholder |
file | file | If required | Supporting document. Max 100 MB. Accepted: PDF, JPEG, PNG, GIF, BMP, WebP, TIFF, SVG, ICO |
Placeholders are matched in order of appearance. The first {{ signature }} maps to signature-1, the second to signature-2, and so on. Similarly for {{ input::... }} fields.
{
"ok": true,
"signed_content": "<h1>Service Agreement</h1><p>I, John Doe, agree to...</p>...",
"message": "Contract signed successfully"
}
Payment Types
| Type | Value | Description | Additional Fields |
|---|---|---|---|
| Payment Link | 1 | One-time payment via Payment Link | None |
| Subscription | 2 | Recurring payment with a frequency | sequence, startDate |
| Installment | 3 | Fixed number of recurring payments | sequence, startDate, numberOfBills |
Frequency Options (Sequence)
| Value | Frequency |
|---|---|
1 | Weekly |
2 | Bi-Weekly |
3 | Monthly |
4 | Quarterly |
5 | Twice a Year |
6 | Annual |
Template Placeholders
| Placeholder | Purpose | Customer Action |
|---|---|---|
{{ signature }} | E-signature field | Customer draws or uploads a signature |
{{ input::Full Name }} | Text input with label “Full Name” | Customer types a value |
{{ input::Date }} | Text input with label “Date” | Customer types a value |
[Your business name] | Auto-replaced with business legal name | Automatic — no customer action |
<h1>Service Agreement</h1>
<p>This agreement is entered into between
<strong>[Your business name]</strong> and
<strong>{{ input::Full Name }}</strong>.</p>
<p>The customer agrees to the terms outlined herein
on <strong>{{ input::Date }}</strong>.</p>
<p>Customer Signature:</p>
<p>{{ signature }}</p>
File Upload
When includeDocument is set to true during contract creation, the customer is required to upload a supporting document at signing time.
| Property | Value |
|---|---|
| Max file size | 100 MB |
| Accepted formats | PDF, JPEG, PNG, JPG, GIF, BMP, WebP, TIFF, TIF, SVG, ICO |
| Storage | Amazon S3 (s3-contract disk) |
| File path | {business_id}/contracts/{contract_id}/{filename} |
| Access | Pre-signed URL (30-minute expiry) |
All Endpoints
Merchant Endpoints (Authenticated)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/{business}/contracts | List contracts |
| POST | /api/{business}/contracts | Create contract |
| GET | /api/{business}/contracts/{id}/edit | Edit form data |
| PUT | /api/{business}/contracts/{id} | Update contract |
| DELETE | /api/{business}/contracts/{id} | Delete contract |
| GET | /api/{business}/contracts/{id}/details | Full details |
| GET | /api/{business}/contracts/export | Export contracts |
| GET | /api/{business}/contracts/templates | List templates |
| POST | /api/{business}/contracts/storeTemplate | Save template |
Public Endpoints (No Authentication)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/contracts/{contract}/show | View contract for signing |
| POST | /api/contracts/{contract}/sign | Sign contract |
Error Handling
| HTTP Code | Scenario | Description |
|---|---|---|
422 | Validation error | Missing required fields or invalid data |
403 | Contract unsigned | Attempting to pay via a linked Payment Link before signing the contract |
404 | Not found | Contract does not exist or has been deleted |
409 | Already paid | Linked Payment Link has already been paid |
500 | Server error | Unexpected processing error |
Notifications
| Event | Notification | Recipient | Content |
|---|---|---|---|
| Contract created (type 1) | PaymentLinkCreated | Customer | Email with subject “Your Payment Link is Ready”, amount, and a “Pay Now” link |
| Contract created (type 2 or 3) | ReoccurringPaymentCreated | Customer | Email with subject “Your Recurring payment is Ready”, amount, and a “Pay Now” link |
The “Pay Now” link in the notification directs the customer to the contract signing page first. After signing, they are redirected to the payment page.