Sandbox Environment
Test the FairePlace API without affecting production data or incurring charges.
Sandbox vs Production
Feature Sandbox Production Base URL https://sandbox.faireplace.com/apihttps://api.faireplace.com/apiAPI keys Separate sandbox keys (fp_sandbox_*) Production keys (fp_*) Data Isolated test data, reset weekly Real data Signatures OTP bypass with code 000000 Real SMS OTP Payments Stripe test mode (no real charges) Real Stripe charges PDFs Watermarked "SANDBOX - AUCUNE VALEUR JURIDIQUE" Production PDFs Notifications Logged but not sent Real email/SMS Rate limits Same as production plan Per plan
Getting started with sandbox
1. Get a sandbox API key
Sandbox API keys are managed separately from production:
Log in to FairePlace
Go to Paramètres > Développeur > Clés API
Toggle the Sandbox switch
Click + Créer une clé API
Your sandbox key will have the prefix fp_sandbox_
2. Point your client to sandbox
export FAIREPLACE_API_KEY = "fp_sandbox_a1b2c3d4e5f6..."
export FAIREPLACE_BASE_URL = "https://sandbox.faireplace.com/api"
curl $FAIREPLACE_BASE_URL /health \
-H "Authorization: Bearer $FAIREPLACE_API_KEY "
3. Create test data
All standard API endpoints work identically in sandbox:
# Create a test owner
curl -X POST $FAIREPLACE_BASE_URL /owners \
-H "Authorization: Bearer $FAIREPLACE_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"title": "Mr.",
"first_name": "Test",
"last_name": "Owner",
"owner_category": "individual",
"email": "[email protected] ",
"mobile_phone": "+33600000000"
}'
Test scenarios
Scenario 1: Happy path — signed lease in 5 minutes
export B = "https://sandbox.faireplace.com/api"
export H = "Authorization: Bearer $FAIREPLACE_API_KEY "
# 1. Create owner
OWNER = $( curl -s -X POST $B /owners \
-H " $H " -H "Content-Type: application/json" \
-d '{"first_name":"Test","last_name":"Owner","owner_category":"individual","email":"[email protected] ","mobile_phone":"+33600000001"}' | jq -r '.id' )
# 2. Create place + estate
PLACE = $( curl -s -X POST $B /places \
-H " $H " -H "Content-Type: application/json" \
-d "{ \" name \" : \" Test Building \" , \" owner_id \" : \" $OWNER \" , \" postal_code \" : \" 75012 \" , \" city \" : \" Paris \" }" | jq -r '.id' )
ESTATE = $( curl -s -X POST $B /places/ $PLACE /estates \
-H " $H " -H "Content-Type: application/json" \
-d '{"area":45.0,"number_of_room":2}' | jq -r '.id' )
# 3. Create lease
LEASE = $( curl -s -X POST $B /leases \
-H " $H " -H "Content-Type: application/json" \
-d "{ \" estate_id \" : \" $ESTATE \" , \" rent_amount \" :950, \" deposit_amount \" :950, \" start_date \" : \" 2026-04-01 \" , \" end_date \" : \" 2029-03-31 \" }" | jq -r '.id' )
# 4. Add tenant
TENANT = $( curl -s -X POST $B /lessees \
-H " $H " -H "Content-Type: application/json" \
-d '{"category":"individual","first_name":"Test","last_name":"Tenant","email":"[email protected] ","mobile_phone":"+33600000002"}' | jq -r '.id' )
curl -s -X POST $B /leases/ $LEASE /lessees \
-H " $H " -H "Content-Type: application/json" \
-d "{ \" lessee_id \" : \" $TENANT \" , \" role \" : \" PrimaryTenant \" , \" start_date \" : \" 2026-04-01 \" }"
# 5. Generate PDF
PDF = $( curl -s -X POST $B /leases/ $LEASE /pdf \
-H " $H " -H "Content-Type: application/json" \
-d '{"template_type":"StandardLease"}' | jq -r '.pdf_id' )
# 6. Sign (OTP bypass with 000000)
curl -s -X POST $B /leases/ $LEASE /signature/initiate \
-H " $H " -H "Content-Type: application/json" \
-d "{ \" pdf_id \" : \" $PDF \" , \" signers \" :[{ \" signer_type \" : \" PROPRIETAIRE \" , \" first_name \" : \" Test \" , \" last_name \" : \" Owner \" , \" person_id \" : \" $OWNER \" , \" email \" : \" [email protected] \" , \" phone \" : \" +33600000001 \" }]}"
echo "Lease $LEASE created and signature initiated!"
Scenario 2: Compliance rejection
Test what happens when rent exceeds the legal cap:
# This will fail with 422 COMPLIANCE_ERROR — rent too high for Paris 75012
curl -s -X POST $B /leases \
-H " $H " -H "Content-Type: application/json" \
-d "{ \" estate_id \" : \" $ESTATE \" , \" rent_amount \" :5000, \" deposit_amount \" :5000, \" start_date \" : \" 2026-04-01 \" , \" end_date \" : \" 2029-03-31 \" }"
Expected response:
{
"error" : {
"code" : 422 ,
"type" : "COMPLIANCE_ERROR" ,
"message" : "Rent exceeds legal maximum for this area" ,
"details" : {
"rule" : "RentCap" ,
"current_value" : 111.11 ,
"maximum_allowed" : 30.60 ,
"unit" : "EUR/m2"
}
}
}
Scenario 3: Dependency conflict
Test what happens when you try to delete a place that still has estates:
# This will fail with 409 CONFLICT
curl -s -X DELETE $B /places/ $PLACE \
-H " $H "
Expected response:
{
"error" : {
"code" : 409 ,
"type" : "CONFLICT" ,
"message" : "Cannot delete place with associated estates"
}
}
Scenario 4: Check rent regulation
# Check if 75012 is in a zone tendue
curl -s -X POST $B /legislative-zones/rent-regulation/check \
-H " $H " -H "Content-Type: application/json" \
-d '{"postal_code":"75012"}'
# Check rent control compliance
curl -s -X POST $B /legislative-zones/rent-control/check \
-H " $H " -H "Content-Type: application/json" \
-d '{"address":"24 rue du Faubourg Saint-Antoine","postal_code":"75012","room_count":2,"surface_area":45.0,"construction_period":"1946_1970","is_furnished":false,"proposed_rent":950}'
Signature testing
In sandbox, the OTP verification step is bypassed with a fixed code:
# Initiate signature (same as production)
curl -X POST $FAIREPLACE_BASE_URL /leases/{lease_id}/signature/initiate \
-H "Authorization: Bearer $FAIREPLACE_API_KEY " \
-H "Content-Type: application/json" \
-d '{ "pdf_id": "<pdf_uuid>", "signers": [...] }'
# Validate OTP with bypass code
curl -X POST $FAIREPLACE_BASE_URL /leases/{lease_id}/signature/validate-otp \
-H "Authorization: Bearer $FAIREPLACE_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"signature_request_id": "<sig_request_uuid>",
"otp_code": "000000"
}'
Note: Sandbox-signed PDFs include a visible watermark: "SANDBOX - AUCUNE VALEUR JURIDIQUE" . These documents have no legal value.
Payment testing
Sandbox uses Stripe test mode. Use Stripe test card numbers :
Card number Scenario 4242 4242 4242 4242Successful payment 4000 0000 0000 0002Card declined 4000 0000 0000 9995Insufficient funds
# Purchase test credits
curl -X POST $FAIREPLACE_BASE_URL /credits/checkout \
-H "Authorization: Bearer $FAIREPLACE_API_KEY " \
-H "Content-Type: application/json" \
-d '{ "package_id": "<package_uuid>" }'
No real charges are made in sandbox mode.
Sandbox limitations
Data resets: Sandbox data is reset every Sunday at 02:00 UTC
No real notifications: Emails and SMS are logged but not delivered
No real signatures: Signed PDFs have no legal value (eIDAS proof is simulated)
Credit limits: Sandbox accounts start with 100 free test credits
Switching to production
When you're ready to go live:
Replace your sandbox API key with a production key
Update the base URL from sandbox.faireplace.com to api.faireplace.com
Purchase real signature credits
Test the signature flow with a real phone number to verify OTP delivery
# Production
export FAIREPLACE_API_KEY = "fp_a1b2c3d4e5f6..."
export FAIREPLACE_BASE_URL = "https://api.faireplace.com/api"
Related
Last modified on March 17, 2026