JouloDocs

Upload customers

Creates one claimable draft per customer. Name and email are enough. Joulo emails the claim link unless send_invite is false, in which case the links come back in the response.

POST
/partner/customers
AuthorizationBearer <token>

Partner API key, sent as Authorization: Bearer <key>. Production keys start with jpk_live_ and work only on https://api.joulo.nl. Sandbox keys start with jpk_test_ and work only on https://api-staging.joulo.nl. Sandbox keys minted before September 2026 also start with jpk_live_. A key used on the wrong host returns 401 with a detail. A key is bound to one partner and reaches only the Partner API routes. Any other route returns 404 when it does not exist. A route that needs a scope the key lacks, such as GET /sessions, returns 403 with error: Insufficient scope and a required_scope. Every other route returns 403 with error: partner_api_key_scope. Mint and revoke keys in the partner portal. A partner has one active key at a time.

In: header

consentboolean

Must be true: you confirm you may supply these customers and pre-register them with Joulo.

Value intrue
customersarray<PartnerCustomerInput>

The customers to upload. At most 1,000 rows become drafts per request. The rest are rejected with over_request_limit.

send_invite?boolean

When true, Joulo emails each customer the claim link. When false, the claim links come back in the response.

Defaulttrue

Response Body

curl -X POST "https://api.joulo.nl/functions/v1/api/partner/customers" \
  -H "Content-Type: application/json" \
  -d '{
    "consent": true,
    "send_invite": true,
    "customers": [
      {
        "name": "Jan de Vries",
        "email": "[email protected]",
        "external_ref": "KLANT-8842",
        "postal_code": "6971 LB",
        "house_number": "12B"
      },
      {
        "type": "zakelijk",
        "company_name": "Bedrijf B.V.",
        "name": "Piet Pietersen",
        "email": "[email protected]",
        "kvk": "12345678"
      }
    ]
  }'
{
  "ok": true,
  "added": 0,
  "batch_id": "4da22c97-b7d5-4e31-8c3a-03870ebc7b20",
  "created": [
    {
      "draft_id": "d998e5e8-954a-4a68-bb9e-7305e87278c0",
      "email": "string",
      "external_ref": "string",
      "claim_url": "http://example.com",
      "ean_status": "resolved",
      "ean_candidates": 0
    }
  ],
  "address_ignored": [
    {
      "email": "string",
      "reason": "invalid_postal_code"
    }
  ],
  "claim_urls": [
    {
      "email": "string",
      "claim_url": "http://example.com"
    }
  ],
  "referral_codes": [
    {
      "email": "string",
      "code": "string",
      "matched": true
    }
  ],
  "rejected": [
    {
      "email": "string",
      "reason": "invalid"
    }
  ],
  "skipped": {
    "invalid": 0,
    "reserved_domain": 0,
    "missing_kvk": 0,
    "already_drafted": 0,
    "existing_user": 0,
    "suppressed": 0,
    "conflict": 0,
    "over_request_limit": 0,
    "over_cap": 0,
    "charger_brand_unsupported": 0,
    "charger_not_linked": 0,
    "charger_claimed": 0
  },
  "cap": {
    "rolling_days": 0,
    "rolling_cap": 0,
    "remaining_before": 0
  }
}
{
  "error": "customers must be a non-empty array of { name, email }"
}
{
  "error": "Missing or invalid API token"
}
{
  "error": "No partner is linked to this API key"
}
{
  "error": "Too many requests",
  "retry_after_seconds": 3
}
{
  "error": "Failed to create drafts"
}
{
  "error": "Authentication is temporarily unavailable, try again shortly"
}