Estimated Time: Under 15 minutes
Prerequisites
- Your API key (format:
zupy_pk_*) — provided by the Zupy team during onboarding - The company ID for the restaurant you’re integrating with
- Your integration slug (e.g.,
repediu) for webhook URLs
Step 1: Verify Your API Key
Test your credentials with a simple customer search:Phone format: The
phone parameter accepts digits only (e.g., 5511987654321). The API normalizes all phone numbers to E.164 format (+5511987654321) internally, so any input format will match the same customer.200 response (even if no customers match):
401 error in RFC 7807 format:
Step 2: Send a Test Webhook
Send order data to Zupy. Replace{partner} with your integration slug (e.g., repediu).
The webhook accepts any JSON payload — Zupy stores it raw and processes it asynchronously using a partner-specific adapter. During onboarding, the Zupy team will map your payload format. For new integrations, use this standard catch-all format:
{data, meta} envelope):
200 with "status": "received". Orders are processed in a background queue (typically within seconds).
Idempotency: Sending the same payload twice returns
"status": "duplicate" — no error, no double-processing. Zupy computes a SHA-256 hash of the request body to detect duplicates.Step 3: Look Up the Customer
After the webhook processes (typically within seconds), search for the customer:{data, meta} envelope):
Step 4: Check Points Balance
{data, meta} envelope):
You’re Integrated!
You’ve successfully verified your API key, sent order data via webhook, looked up a customer, and checked their points balance.Field Glossary — balances and identifiers
To save you the time we spent figuring this out the first time, here are the partner-visible naming conventions in one table:Balance fields
| Field | Where it appears | What it means |
|---|---|---|
points_balance | GET /customers/{id}/, GET /customers/{id}/points/, OTP verify response | The customer’s current points balance. The stable, always-queryable field. |
new_balance | POST /rewards/{id}/redeem/ response, POST /coupons/{id}/validate/ response | The customer’s balance immediately after the operation. Same number as points_balance if you GET-after-POST — included so you don’t have to. |
current_points | (rare — Wallet / scanner contexts only) | Synonym for points_balance. Will be deprecated. Do not write new code against this. |
zupy_balance | GET /companies/ response | The company’s Z$ balance (marketing-campaign budget pool). Not a customer balance. |
new_z_balance | POST /rewards/{id}/redeem/ response, POST /coupons/{id}/validate/ response | The customer’s Z$ balance after the operation. Stringified Decimal with 6 places (e.g. "2418.400000"). |
z_tokens_used | POST /rewards/{id}/redeem/ response, POST /coupons/{id}/validate/ response | Z$ tokens consumed by this specific operation. "0.000000" (zero-as-string) for points-only redemptions. |
Coupon identifiers
| Field | Format | When to use |
|---|---|---|
id | KSUID (e.g. 16a33f27fbbc1801d63d56d2027) | When you obtained it from a prior API call (redeem response or /coupons/issued/ list). Always works. |
coupon_code | CZ-XXXXXXXX or CP-XXXXXXXX (legacy) | When you have a printed code from the customer’s receipt. The validate endpoint accepts this directly (case-insensitive). |
Error Handling
All errors use the RFC 7807 Problem Details format:| Status | Type | When It Occurs |
|---|---|---|
| 401 | authentication-required | Missing or invalid X-API-Key header |
| 403 | permission-denied | Read-only key attempting a write operation |
| 429 | rate-limit-exceeded | Too many requests — check Retry-After header |
Retry logic for rate limits
Retry logic for rate limits
When you receive a
429 response, wait for the Retry-After header duration before retrying:Next Steps
Authentication
Learn about access levels, rate limits, OTP, and security best practices
Webhook Setup
Configure webhooks for automatic order processing and customer enrollment
API Reference
Browse all endpoints with request/response schemas
Partner Onboarding
Complete the onboarding checklist for production deployment