Skip to main content
Get up and running with the Zupy Partner API in 4 steps.
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
Don’t have credentials yet? Contact webmaster@zupy.com.br to start the onboarding process.

Step 1: Verify Your API Key

Test your credentials with a simple customer search:
curl -X GET "https://api.zupy.com/api/v2/customers/?phone=5511987654321" \
  -H "X-API-Key: zupy_pk_your_api_key_here"
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.
If your key is valid, you receive a 200 response (even if no customers match):
{
  "data": [],
  "meta": {
    "cursor": null,
    "has_next": false,
    "count": 0
  }
}
If your key is invalid, you receive a 401 error in RFC 7807 format:
{
  "type": "https://api.zupy.com/errors/authentication-required",
  "title": "Authentication Required",
  "status": 401,
  "detail": "Invalid API key"
}

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:
curl -X POST "https://api.zupy.com/api/v2/webhooks/integrations/{partner}/" \
  -H "X-API-Key: zupy_pk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "customer_name": "Maria Santos",
      "customer_phone": "+5511987654321",
      "customer_email": null,
      "customer_cpf": null,
      "order_total": "89.90",
      "order_id": "123456789",
      "order_date": "2026-03-22T14:30:00.000Z",
      "store_cnpj": "12.345.678/0001-90",
      "store_name": "Pizzaria Exemplo"
    }
  ]'
Already have your own payload format? Send it as-is — Zupy accepts any JSON. During onboarding, the Zupy team will create a mapper for your specific field names, just like we did for Repediu, Saipos, and other partners.
Success response ({data, meta} envelope):
{
  "data": {
    "status": "received",
    "id": "2bxRKmpWJY8lHHqsGfsQQtwCDef"
  },
  "meta": {}
}
The webhook is processed asynchronously. You receive an immediate 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:
curl -X GET "https://api.zupy.com/api/v2/customers/?phone=5511987654321" \
  -H "X-API-Key: zupy_pk_your_api_key_here"
Response ({data, meta} envelope):
{
  "data": [
    {
      "id": "2awTHloSJX7kGGprFerOOsvABcd",
      "full_name": "Maria Santos",
      "email": null,
      "phone": "+5511987654321",
      "cpf": null,
      "birth_date": null,
      "points_balance": 89,
      "points_earned": 89,
      "points_spent": 0,
      "tier": "default",
      "card_number": "ZP-ABC123",
      "join_date": "2026-03-22",
      "last_activity_date": "2026-03-22T14:30:00Z",
      "rfm_segment": "new",
      "program_id": "2awTHmNw8X7kGGpr...",
      "program_name": "Clube Pizzaria Exemplo",
      "company_id": "2awTHkVw8X7kGGpr..."
    }
  ],
  "meta": {
    "cursor": null,
    "has_next": false,
    "count": 1
  }
}

Step 4: Check Points Balance

curl -X GET "https://api.zupy.com/api/v2/customers/2awTHloSJX7kGGprFerOOsvABcd/points/" \
  -H "X-API-Key: zupy_pk_your_api_key_here"
Response ({data, meta} envelope):
{
  "data": {
    "customer_id": "2awTHloSJX7kGGprFerOOsvABcd",
    "points_balance": 89,
    "points_earned": 89,
    "points_spent": 0,
    "points_name": "Pontos",
    "last_activity_date": "2026-03-22T14:30:00Z",
    "tier": "default"
  },
  "meta": {}
}

You’re Integrated!

You’ve successfully verified your API key, sent order data via webhook, looked up a customer, and checked their points balance.

Error Handling

All errors use the RFC 7807 Problem Details format:
{
  "type": "https://api.zupy.com/errors/{error-type}",
  "title": "Human-Readable Title",
  "status": 400,
  "detail": "Specific explanation of what went wrong"
}
Common errors you may encounter:
StatusTypeWhen It Occurs
401authentication-requiredMissing or invalid X-API-Key header
403permission-deniedRead-only key attempting a write operation
429rate-limit-exceededToo many requests — check Retry-After header
When you receive a 429 response, wait for the Retry-After header duration before retrying:
import time
import requests

def api_request(method, url, **kwargs):
    """Make an API request with automatic retry on rate limit."""
    max_retries = 3
    for attempt in range(max_retries):
        response = requests.request(method, url, **kwargs)

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 30))
            print(f"Rate limited. Retrying in {retry_after}s...")
            time.sleep(retry_after)
            continue

        return response

    raise Exception("Max retries exceeded")

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