Replikate.co developer sandbox
Build and test your integration with Replikate.co before you touch production. Same paths, request validation, signatures, response shapes and error codes. Nothing here bills, sends email, pays commissions or reaches production data.
Getting started
- Sign up at partners.replikate.co and create a sandbox key. It looks like
rk_sandbox_…, is shown once and lasts up to 365 days (90 by default). Sandbox access needs no approval. - Point your server at
https://api.sandbox.replikate.coand send the key asAuthorization: Bearer rk_sandbox_…. In production the same paths live on the origins in the table below; keep the origin and credential in configuration so switching is a configuration change. - Generate your own Ed25519 key pair and register the public key once with
PUT /v1/sandbox/settings. Signed routes verify against it, exactly as production verifies a project's registered key. Your private key never leaves you. - Call
GET /v1/sandbox/meto read your project slug (sbx-…), then run the quick starts.POST /v1/sandbox/resetreturns your data to the seed.
Every response carries X-Replikate-Mode: sandbox, X-Replikate-Data: synthetic and X-Replikate-Financial-Effects: none. State is held in memory per partner account: a reset clears your data, a sandbox restart clears everything including your registered signing key, and other accounts never see it. Revoking a key in the portal is recorded there, but because the sandbox serves only synthetic data a revoked key keeps working here until it expires.
What the sandbox serves
| Area | Routes | Credential | Production origin |
|---|---|---|---|
| Project ingestion | POST /v1/projects/{project}/events | Ed25519 project signature | https://affiliate.commonquant.ai |
| Referrals | GET /r/{project}/{code}/{version}, POST /v1/projects/{project}/referrals/bind | none / project signature | https://affiliate.commonquant.ai |
| Discounts (your checkout) | POST /v1/discount-integrations/{project}/commands | signature, scope discounts/{project} | https://app.replikate.co |
| Newsletter | POST /v1/newsletters/publications/{publication}/subscriptions, …/tokens/check|confirm|unsubscribe | sandbox key (production: newsletter service key) | https://app.replikate.co |
| Partner reads | GET /v1/projects/{project}/partners/me, …/campaigns, …/statements, …/statements/{currency} | sandbox key (production: partner OIDC token) | https://affiliate.commonquant.ai |
| Sandbox only | GET /v1/sandbox/me, PUT /v1/sandbox/settings, POST /v1/sandbox/reset | sandbox key | sandbox only |
Errors use production's envelope: {"error":{"code","message","requestId"}}. Newsletter routes keep the newsletter service's {"error":"code"} form. JSON bodies are limited to 256 KiB (newsletter: 1 MiB).
Signing project requests
Sign the UTF-8 message v1\n<unix-seconds>\n<project>\n<exact body> with your Ed25519 private key. Send X-Replikate-Timestamp: <unix-seconds> and X-Replikate-Signature: <base64url signature, no padding>. Timestamps must be within 300 seconds. Discount commands sign discounts/<project> in place of the project. Sign the exact bytes you send; do not re-serialise the body afterwards.
# OpenSSL 3. Create your signing key once and register its public half.
openssl genpkey -algorithm ed25519 -out signing.pem
openssl pkey -in signing.pem -pubout -out signing.pub.pem
API=https://api.sandbox.replikate.co SANDBOX_KEY=rk_sandbox_...
jq -n --rawfile k signing.pub.pem '{signingPublicKey:$k}' |
curl -sS -X PUT $API/v1/sandbox/settings -H "Authorization: Bearer $SANDBOX_KEY" -H 'Content-Type: application/json' --data-binary @-
PROJECT=$(curl -sS $API/v1/sandbox/me -H "Authorization: Bearer $SANDBOX_KEY" | jq -r .project)
sign() { # $1 = scope (project or discounts/project), $2 = body file
ts=$(date +%s)
printf 'v1\n%s\n%s\n' "$ts" "$1" | cat - "$2" > /tmp/msg
sig=$(openssl pkeyutl -sign -inkey signing.pem -rawin -in /tmp/msg | openssl base64 -A | tr '+/' '-_' | tr -d '=')
echo "-H X-Replikate-Timestamp:$ts -H X-Replikate-Signature:$sig"
}
Quick starts
1. Send a signed payment event
cat > event.json <<'JSON'
{"eventId":"3f0c3c5e-7d5f-4a8e-9a43-0d1c8c1b2a10","type":"payment.collected","data":{"provider":"airwallex","providerAccount":"acct-sandbox","paymentId":"pay_1","customerId":"cust_1","currency":"USD","collectedMinor":"3200","taxMinor":"0","eligibleMinor":"3200","settledAt":"2026-01-02T03:04:05.000Z"}}
JSON
curl -sS $API/v1/projects/$PROJECT/events -H 'Content-Type: application/json' $(sign $PROJECT event.json) --data-binary @event.json
# 202 {"state":"pending",...}; send the same body again: 200 {"state":"applied",...}
2. Referral click and bind
curl -sS -o /dev/null -w '%{redirect_url}\n' $API/r/$PROJECT/sandbox/1
# → your referralDestination (or this page)#partner_claim=TOKEN
cat > bind.json <<JSON
{"type":"referral.bind","token":"TOKEN","customerId":"cust_1","identity":{"issuer":"https://accounts.example.com","subject":"user-1"}}
JSON
curl -sS $API/v1/projects/$PROJECT/referrals/bind -H 'Content-Type: application/json' $(sign $PROJECT bind.json) --data-binary @bind.json
3. Apply a discount code at checkout
cat > reserve.json <<'JSON'
{"action":"reserve","data":{"operationId":"6a1f0d3e-2b4c-4d5e-8f60-718293a4b5c6","customerId":"cust_1","code":"SANDBOX20","productId":"sandbox-plus","priceId":"plus-monthly","period":"monthly","currency":"USD","amountMinor":1600}}
JSON
curl -sS $API/v1/discount-integrations/$PROJECT/commands -H 'Content-Type: application/json' $(sign discounts/$PROJECT reserve.json) --data-binary @reserve.json
# {"discountMinor":320,"payableMinor":1280,"state":"reserved",...}
# Then: dispatch {reservationId} → record_checkout {reservationId,checkoutId} → redeem {reservationId,checkoutId,redemptionId},
# or release {reservationId[,proof]} if the checkout is abandoned.
Amounts are integer minor units. A discount never changes your price: send what your checkout charges and charge the returned payableMinor.
4. Newsletter double opt-in
curl -sS -D - $API/v1/newsletters/publications/sandbox/subscriptions \
-H "Authorization: Bearer $SANDBOX_KEY" -H 'Content-Type: application/json' \
-d '{"email":"[email protected]","source":"web"}'
# The sandbox sends no email; the confirmation token is in X-Sandbox-Confirmation-Token.
curl -sS $API/v1/newsletters/publications/sandbox/tokens/confirm \
-H "Authorization: Bearer $SANDBOX_KEY" -H 'Content-Type: application/json' -d '{"token":"TOKEN"}'
5. Partner earnings
curl -sS $API/v1/projects/$PROJECT/statements -H "Authorization: Bearer $SANDBOX_KEY"
curl -sS $API/v1/projects/$PROJECT/campaigns -H "Authorization: Bearer $SANDBOX_KEY"
Seed data
| Item | Value |
|---|---|
| Campaign | code sandbox, version 1, 20% commission, 30-day attribution window, markets equities |
| Discount codes | SANDBOX20 20% first invoice · SANDBOX5OFF USD 5.00 off every renewal (sandbox-plus, monthly) · SANDBOXDRAFT draft until you bind it · SANDBOXSPENT exhausted |
| Catalogue | products sandbox-plus, sandbox-pro; periods monthly, yearly; currency USD |
| Statements | USD: pending 12500, available 48000, paid 100000 · SGD: available 2400 |
| Partner identity | issuer https://sandbox.replikate.co, subject sandbox-partner (binding this identity is rejected as self_referral) |
Not simulated: ledger effects of events (statements stay at the seed), payouts, administrator routes, email delivery, and provider calls. The full contract is in openapi.json.