The Pivotal API doesn’t expose bulk endpoints (e.g. there is no POST /customers/bulk that takes an array). The reason: bulk endpoints either lie about partial-failure handling, or push the complexity into a job queue you can’t see into.
For now, fan out from your side. The patterns below handle 95% of bulk imports — backfills, migrations, periodic refreshes.
Two numbers matter:
N requests, where N is your record count.A safe default for a 60/min key: concurrency of 4, with each task waiting briefly between requests. That keeps you well under the bucket while staying fast enough to finish 5,000 records in ~85 minutes.
For 600/min: concurrency of 10 finishes 5,000 records in under 10 minutes.
Three things to call out:
Idempotency-Key lets you re-run after a crash without duplicating records.external_ids. Crude but enough for a one-shot script. For long-running services, use Redis or a Postgres row.slug_taken is accepted as a non-error — it means the customer was created in a previous run.Idempotency-KeyIf you send the same body to POST /customers twice without a key, you get 409 slug_taken on the second attempt. With a key, you get 200 OK with the original response — which lets the script keep moving and treat it as “already done”.
X-RateLimit-RemainingThe script above retries on 429. You can do better — slow down before you hit zero:
This drops your peak throughput slightly but eliminates 429 round trips entirely.
Bulk-importing customers is the main case. If you also need to attach contacts and onboardings, fan them out the same way after the customer pass finishes:
Three passes is more wall time but easier to reason about than interleaving. The total request count is the same.
After the script finishes, eyeball:
slug_taken, look at the error and decide.Promise.all over 5,000 records means 5,000 in-flight requests. You’ll trip the rate limit and the OS file descriptor limit before you trip anything else.