UAE Rent Now Pay Later: Partner API flow
This guide walks through a UAE Rent Now Pay Later (RNPL) application on the Rently Partner API (public v2): which endpoint to call at each step, what to send and what comes back.
The full request and response schemas are in the Partner API reference.
- For a working reference integration that runs this whole flow against your own credentials, see the playground repository: https://github.com/RentlyApp/partner-playground
Before you start
Every request needs an access token from POST /v2/Token, sent as Authorization: <tokenType> <accessToken>. Getting the token is covered in Get Started.
The flow at a glance
Each box is a status returned by GET /v2/ae/rnpl/{productFlowId}, coloured by who acts next: the partner, Rently or the tenant. Arrows show what moves the application on; the partner's arrows are the endpoints to call.
Blue: the partner acts. Purple: Rently acts. Yellow: the tenant acts, on the Rently website. Green: done. Red: stopped. Dashed: optional.
GET /v2/ae/rnpl/{productFlowId} can be called in any status to see where the application is.
| Status | Who acts | What to do |
|---|---|---|
| Before the application exists | Partner | Optionally price it with POST /v2/ae/rnpl/quote (step 1), then create it with POST /v2/ae/rnpl (step 2). |
idle | Partner | Upload the documents with POST /v2/blob/upload (step 3), attach them with PUT /v2/ae/rnpl/{productFlowId} (step 4) and submit with POST /v2/ae/rnpl/{productFlowId}/advance (step 5). |
pending | Rently | Submitted. Rently's team reviews it and approves it, rejects it or asks for more documents. Nothing to call. |
document-required | Partner | Rently's team asked for more documents; the reason is in review.documentRequiredReason. Upload the documents with POST /v2/blob/upload (step 3) and attach them with PUT /v2/ae/rnpl/{productFlowId} (step 4). The application goes back to pending. |
approved | Rently | Approved. Rently prepares the agreement and moves the application to signing. Nothing to call. |
signing | Tenant | The tenant continues the journey on Rently by clicking continueUrl (step 7). |
completed | Done | The tenant finished the journey on Rently. |
rejected | Stopped | Rejected by Rently's team; the reason is in review.rejectReason. Final. |
Also available at any point:
| Endpoint | Purpose |
|---|---|
GET /v2/ae/rnpl/applications/{userId} | List a tenant's applications. |
GET /v2/ae/rnpl/{productFlowId}/schedules | Preview the application's payment schedule. Nothing is saved. |
GET /v2/blob/download | Download a file uploaded earlier. |
1. Quote the application (optional)
POST /v2/ae/rnpl/quote prices an application before it exists. It takes the same payload as the create endpoint (step 2), minus intendedPaymentMethod, and validates it the same way, so it is also a safe way to check the payload. Nothing is saved.
{
"totalPayment": 8420.5,
"currency": "AED",
"items": [
{ "label": "Monthly principal", "amount": 8000, "rate": null },
{ "label": "Subscription Fee", "amount": 420.5, "rate": 5.25 }
]
}
totalPayment is the monthly installment the tenant would pay: the monthly principal plus the subscription fee. items lists each line of the quote, such as the rent financed, the deposit, the monthly principal and the subscription fee. The values above are illustrative.
2. Create the application
POST /v2/ae/rnpl starts an application on behalf of your tenant.
{
"userId": null,
"currency": "AED",
"partnerReferenceId": "HT-2026-000123",
"lease": {
"leaseType": "found-place",
"annualRent": 96000,
"numberOfCheques": 4,
"leaseDurationInMonths": 12,
"moveInDate": "2026-11-01",
"deposit": { "amount": 5000 }
},
"property": {
"location": "dubai",
"address": "Apartment 1204, Marina Gate 2, Dubai Marina"
},
"tenant": {
"fullName": "Aisha Rahman",
"email": "tenant@example.com",
"phoneNumber": "+971501234567",
"identityNumber": "784-1990-1234567-1",
"monthlyIncome": 15000,
"hasCoapplicant": false
},
"landlord": {
"fullName": "Omar Haddad",
"email": "landlord@example.com",
"phoneNumber": "+971507654321",
"bankAccount": { "bankCode": "HBZUAEAD", "iban": "AE070331234567890123456" }
},
"intendedPaymentMethod": "Card"
}
{
"productFlowId": "<application id>",
"userId": "<tenant's user id>"
}
Store both ids on your side:
productFlowIdidentifies the application in every later call.userIdidentifies the tenant. LeaveuserIdout (ornull) for a new tenant and Rently generates one. Send it on the tenant's later applications so they are grouped under the same user, and use it to list them withGET /v2/ae/rnpl/applications/{userId}.
Field rules
| Field | Rule |
|---|---|
currency | Optional. Defaults to AED, the only accepted value. All amounts are in AED. |
partnerReferenceId | Optional. Your own reference, e.g. your application or lease id. Rently stores it with the application. |
lease.leaseType | found-place, renewing, mid-lease-switch or not-yet-secured. |
lease.numberOfCheques | 1, 2, 3, 4 or 6. |
lease.leaseDurationInMonths | Between 6 and 12. |
lease.moveInDate | YYYY-MM-DD. All dates use this format. |
lease.deposit | Optional. Ignored for mid-lease-switch. |
lease.midLease | { chequesRemaining, rentRemaining }. Required when leaseType is mid-lease-switch. |
property.location | dubai, abu-dhabi, sharjah, ajman or ras-al-khaimah. |
tenant.identityNumber | The tenant's Emirates ID number. |
tenant.monthlyIncome | Between 7,000 and 999,999. |
tenant.hasCoapplicant | Whether the tenant splits the rent with someone. |
landlord.bankAccount.bankCode | SWIFT (BIC) code of a UAE bank, 8 or 11 characters. |
landlord.bankAccount.iban | UAE IBAN without spaces: AE followed by 21 digits. |
intendedPaymentMethod | Card or DirectDebit. |
3. Upload the documents
Each document is uploaded first with POST /v2/blob/upload, then attached to the application in step 4.
Send the request as multipart/form-data with two fields:
blobType:11(product flow files).files: one or more files. Up to 10 files per request, and the whole request must be 10 MB or smaller.
{
"blobNames": ["productflowfiles/3f2c9a1e-emirates-id-front.pdf"]
}
blobNames lists the stored path of each file, in the order they were sent. Files are always renamed, so keep these paths: they are what you attach in step 4 and what you download with GET /v2/blob/download?blobType=11&blobName=<path>.
4. Attach the documents
PUT /v2/ae/rnpl/{productFlowId} sets the application's documents. For each file, send the path returned by the upload as url (the path, not a full URL) together with the file's metadata.
{
"attachments": {
"emiratesId": [
{
"url": "productflowfiles/3f2c9a1e-emirates-id-front.pdf",
"fileName": "emirates-id-front.pdf",
"contentType": "application/pdf",
"size": 254812
}
],
"fullCreditReport": [ { "url": "...", "fileName": "...", "contentType": "...", "size": 0 } ],
"ejari": [ { "url": "...", "fileName": "...", "contentType": "...", "size": 0 } ],
"salaryCertificate": [],
"bankStatements": [],
"otherDocuments": []
}
}
| Attachment | Required | Files |
|---|---|---|
emiratesId | Yes | 1 to 2 (front and back) |
fullCreditReport | Yes | Exactly 1 (AECB full credit report) |
ejari | Yes | Exactly 1 (registered Ejari tenancy contract) |
salaryCertificate | No | Up to 2 (issued less than 30 days ago) |
bankStatements | No | Up to 6 (last three bank statements) |
otherDocuments | No | Up to 5 |
Accepted files are application/pdf, image/png and image/jpeg, 10 MB each at most.
The update replaces the application's documents. Files left out of the request are removed, and files already attached (same url under the same document) stay as they are. To add a file, send the files the application already has (from attachments in GET /v2/ae/rnpl/{productFlowId}) together with the new one.
You can call this endpoint as often as needed while the application accepts documents (see The flow at a glance).
5. Advance the application
POST /v2/ae/rnpl/{productFlowId}/advance moves the application to its next status, e.g. submits it for review once its documents are in. It has no request body: whatever the next status needs must already be on the application, sent through the create and update endpoints.
When something is missing, the application stays where it is and errors says what.
6. Follow the application
GET /v2/ae/rnpl/{productFlowId} returns the application in the shape it was created with, plus:
| Field | Meaning |
|---|---|
id | The application id. |
status | Where the application is. See The flow at a glance. |
review.documentRequiredReason | What the tenant still needs to provide. Set when Rently moves the application to document-required. |
review.rejectReason | Why the application was rejected. Set when Rently moves it to rejected. |
continueUrl | Link where the tenant continues their application on Rently. |
attachments | The documents attached in step 4. null until they are provided. |
Read the application again to see when its status changes, or register a webhook to be notified with an ApplicationStatusChangeEvent.
7. Send the tenant to Rently
When the status is signing, give the tenant continueUrl, e.g. as a link or button. The tenant continues the journey on Rently by clicking it and signs the agreement there. Once they finish, the application moves to completed.
List a tenant's applications
GET /v2/ae/rnpl/applications/{userId} returns the ids of the applications a tenant made through you. Read each one with GET /v2/ae/rnpl/{productFlowId}. An unknown userId returns an empty list.
{
"userId": "<tenant's user id>",
"productFlowIds": ["<application id>", "<application id>"]
}
Preview the payment schedule
GET /v2/ae/rnpl/{productFlowId}/schedules returns every payment the application would schedule, in the order they fall due. Nothing is saved, and the schedule is built from what the application carries now; when something it needs is missing, schedules is empty and errors says what.
{
"productFlowId": "<application id>",
"schedules": [
{
"party": "tenant",
"type": "money-in",
"description": "Monthly installment",
"amount": 8420.5,
"discountAmount": 0,
"finalAmount": 8420.5,
"currency": "AED",
"paymentDate": "2026-11-01"
}
]
}
| Field | Values |
|---|---|
party | Who the payment is with: tenant, landlord or b2b-entity. |
type | money-in (collected from the tenant), money-out (paid out to the landlord) or on-behalf (paid on a party's behalf). |
finalAmount | What is actually collected or paid: amount less discountAmount. |
Errors
A call can fail in two ways, so check both:
- A non-2xx status.
401means the token is missing, expired or invalid. Request validation failures return400with the fields at fault:
{
"title": "One or more validation errors occurred.",
"errors": { "lease.numberOfCheques": ["..."] }
}
- A
200witherrors. Every response body can carry anerrorsarray. When it is not empty, the call did not succeed:
{
"errors": [{ "code": "PSAE015", "message": "The application cannot be found." }]
}
| Code | Endpoint | Meaning |
|---|---|---|
PSAE012 | POST /v2/blob/upload | The file upload failed. Try again. |
PSAE013 | GET /v2/blob/download | The requested file cannot be found. |
PSAE014 | POST /v2/ae/rnpl | The application could not be created. Try again. |
PSAE015 | Application endpoints | The application cannot be found. |
PSAE016 | Application endpoints | The application could not be retrieved. Try again. |
PSAE017 | PUT /v2/ae/rnpl/{productFlowId} | The application could not be updated. Try again. |
PSAE018 | POST /v2/ae/rnpl/{productFlowId}/advance | The application could not be advanced. Try again. |
PSAE019 | POST /v2/ae/rnpl/quote | The quote could not be calculated. Try again. |
PSAE020 | GET /v2/ae/rnpl/{productFlowId}/schedules | The payment schedule could not be retrieved. Try again. |
SEC003 | Application endpoints | The application belongs to another partner. |