Quickstart
1. Create a test key
Log in to the partner portal, open API keys and create a TEST key. Copy it — it is shown only once.
export KL_KEY=kl_test_…
2. Check the key
curl https://api-test-pp.keikkis.fi/v1/me -H "Authorization: Bearer $KL_KEY"
3. See your work types
curl https://api-test-pp.keikkis.fi/v1/work_types -H "Authorization: Bearer $KL_KEY"
Each code comes with the VAT valid today. Use a code as work_type.
4. Invite a worker
curl -X POST https://api-test-pp.keikkis.fi/v1/connections \
-H "Authorization: Bearer $KL_KEY" -H "Content-Type: application/json" \
-d '{"external_user_id": "u_1842", "email": "aino@example.com"}'
A new connection is always pending. In production Keikkalasku emails the invitation; you can
also show connect_url in your own UI.
5. Preview a gig
curl -X POST "https://api-test-pp.keikkis.fi/v1/gigs?dry_run=true" \
-H "Authorization: Bearer $KL_KEY" -H "Content-Type: application/json" \
-d '{
"external_id": "hv-2026-11-07-001",
"date": "2026-11-07",
"title": "Keikka Tavastialla",
"work_type": "performing_arts",
"workers": [
{"external_user_id": "u_1842", "email": "aino@example.com", "amount": "200.00"}
]
}'
dry_run runs every validation and limit and returns the VAT and totals, without saving
anything. It answers identically in both environments.
6. Report it
The same request without dry_run creates the gig (201). Sending it again returns the same
gig (200); sending the same external_id with different content is 409 idempotency_conflict.
7. Poll the status
curl "https://api-test-pp.keikkis.fi/v1/gigs?updated_since=2026-11-07T00:00:00Z" \
-H "Authorization: Bearer $KL_KEY"
Keep the latest updated_at you have seen and use it as the next updated_since.
Going live
When Keikkalasku has opened production use, create a PRODUCTION key and change the base URL
to https://api-pp.keikkis.fi. Nothing else changes.