JouloDocs

Import customers in the CSV row shape

Creates one claimable draft per row, from a rows array or a CSV string. It runs the same validation, dedupe and caps as POST /partner/customers. Rows that fail are named in rejected: the request itself succeeds.

POST
/partner/drafts/import
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
rows?array<PartnerDraftRow>

The rows to import. When present, csv is ignored. Without rows and csv the import adds nothing.

csv?string

CSV text with a header row, sent as a JSON string. Comma or semicolon separated, quotes allowed. Headers map case-insensitively: type/soort, naam/name, email/emailadres/mail, ean/eancode, kvk/kvknummer, btw/btwnummer/vat, bedrijfsnaam/bedrijf/company_name/company, contactpersoon/contact_name/contact, referral_code/referral/vriendencode, external_ref/customer_ref/klantnummer/referentie/extref, postcode/postal_code/zip/zipcode, huisnummer/house_number, toevoeging/huisnummertoevoeging/house_number_addition/house_number_suffix, plaats/woonplaats/stad/city. CSV cannot pre-couple a charger.

source?string

Label for the upload. Any value other than api counts as csv. Only api runs the EAN lookup during the request.

Default"csv"
Value in"csv" | "api"
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/drafts/import" \
  -H "Content-Type: application/json" \
  -d '{
    "consent": true,
    "send_invite": false,
    "source": "api",
    "rows": [
      {
        "naam": "Jan de Vries",
        "email": "[email protected]",
        "external_ref": "KLANT-8842"
      }
    ]
  }'
{
  "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": "consent_required",
  "message": "Bevestig dat je deze klanten mag aanleveren en bij Joulo mag voor-aanmelden."
}
{
  "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"
}