{"components":{"responses":{},"schemas":{"Connection":{"description":"The worker's consent for the partner to create invoicing requests on their behalf. A new connection is always `pending` — the API never reveals whether an email has a Keikkalasku account.","example":{"accepted_at":null,"connect_url":"https://oma.keikkalasku.fi/kumppanit/yhdista/test_8d41c2e07a55","email":"aino@example.com","expires_at":"2026-12-01T12:00:00Z","external_user_id":"u_1842","id":"con_test_8d41c2e07a55","invited_at":"2026-11-01T12:00:00Z","status":"pending"},"properties":{"accepted_at":{"format":"date-time","nullable":true,"type":"string"},"connect_url":{"description":"The consent link. Keikkalasku emails it; you can also show it in your own UI.","type":"string"},"email":{"example":"aino@example.com","type":"string"},"expires_at":{"format":"date-time","type":"string"},"external_user_id":{"example":"u_1842","nullable":true,"type":"string"},"id":{"description":"Our id (`con_…`).","example":"con_123","type":"string"},"invited_at":{"format":"date-time","type":"string"},"status":{"description":"`pending` until the worker accepts; `expired` after 30 days without an answer (invite again by posting the connection again).","enum":["pending","active","declined","expired","revoked"],"type":"string"}},"required":["id","status","connect_url"],"type":"object"},"ConnectionList":{"example":{"data":[{"accepted_at":null,"connect_url":"https://oma.keikkalasku.fi/kumppanit/yhdista/test_000000000001","email":"pending@example.com","expires_at":"2026-12-01T12:00:00Z","external_user_id":"u_test_pending","id":"con_test_000000000001","invited_at":"2026-11-01T12:00:00Z","status":"pending"},{"accepted_at":"2026-11-02T09:30:00Z","connect_url":"https://oma.keikkalasku.fi/kumppanit/yhdista/test_000000000002","email":"active@example.com","expires_at":"2026-12-01T12:00:00Z","external_user_id":"u_test_active","id":"con_test_000000000002","invited_at":"2026-11-01T12:00:00Z","status":"active"},{"accepted_at":null,"connect_url":"https://oma.keikkalasku.fi/kumppanit/yhdista/test_000000000003","email":"declined@example.com","expires_at":"2026-12-01T12:00:00Z","external_user_id":"u_test_declined","id":"con_test_000000000003","invited_at":"2026-11-01T12:00:00Z","status":"declined"},{"accepted_at":null,"connect_url":"https://oma.keikkalasku.fi/kumppanit/yhdista/test_000000000004","email":"expired@example.com","expires_at":"2026-12-01T12:00:00Z","external_user_id":"u_test_expired","id":"con_test_000000000004","invited_at":"2026-11-01T12:00:00Z","status":"expired"},{"accepted_at":"2026-11-02T09:30:00Z","connect_url":"https://oma.keikkalasku.fi/kumppanit/yhdista/test_000000000005","email":"revoked@example.com","expires_at":"2026-12-01T12:00:00Z","external_user_id":"u_test_revoked","id":"con_test_000000000005","invited_at":"2026-11-01T12:00:00Z","status":"revoked"}],"has_more":false},"properties":{"data":{"items":{"$ref":"#/components/schemas/Connection"},"type":"array"},"has_more":{"type":"boolean"}},"type":"object"},"ConnectionRequest":{"properties":{"email":{"description":"The worker's email. The invitation is sent here, and the worker can accept it only with a Keikkalasku account under the same email.","example":"aino@example.com","format":"email","type":"string"},"external_user_id":{"description":"Your own permanent id for the worker.","example":"u_1842","maxLength":100,"pattern":"^[A-Za-z0-9._:\\-]{1,100}$","type":"string"},"firstname":{"description":"Shown in the invitation.","example":"Aino","maxLength":100,"type":"string"},"lastname":{"example":"Esiintyjä","maxLength":100,"type":"string"}},"required":["external_user_id","email"],"type":"object"},"DryRun":{"description":"What `POST /v1/gigs` would create, without saving anything. No ids or statuses, so the answer is identical in both environments.","properties":{"date":{"format":"date","type":"string"},"dry_run":{"example":true,"type":"boolean"},"external_id":{"type":"string"},"location":{"nullable":true,"type":"string"},"title":{"type":"string"},"totals":{"$ref":"#/components/schemas/Totals"},"warnings":{"items":{"$ref":"#/components/schemas/Warning"},"type":"array"},"work_type":{"nullable":true,"type":"string"},"workers":{"items":{"additionalProperties":true,"type":"object"},"type":"array"}},"type":"object"},"Gig":{"example":{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-2026-11-07-001","id":"gig_test_3f2a9c1d0b7e","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"350.00","invoice_total":"439.25","vat_amount":"89.25"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":null,"invoice_total":"251.00","status":"received","status_changed_at":"2026-11-07T12:00:00Z","status_reason":null,"vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"},{"amount":"150.00","connection_id":"con_test_1b96f3a2c4d8","email":"eero@example.com","external_user_id":"u_2210","invoice":null,"invoice_total":"188.25","status":"received","status_changed_at":"2026-11-07T12:00:00Z","status_reason":null,"vat_amount":"38.25","vat_percent":"25.5","work_type":"performing_arts"}]},"properties":{"cancelled_at":{"format":"date-time","nullable":true,"type":"string"},"created_at":{"format":"date-time","type":"string"},"date":{"format":"date","type":"string"},"external_id":{"type":"string"},"id":{"description":"Our id (`gig_…`). Either id or your external_id can be used to fetch the gig.","example":"gig_123","type":"string"},"location":{"nullable":true,"type":"string"},"title":{"type":"string"},"totals":{"$ref":"#/components/schemas/Totals"},"updated_at":{"description":"The latest change to the gig or any worker's status — use it with `updated_since`.","format":"date-time","type":"string"},"warnings":{"items":{"$ref":"#/components/schemas/Warning"},"type":"array"},"work_type":{"nullable":true,"type":"string"},"workers":{"items":{"$ref":"#/components/schemas/Worker"},"type":"array"}},"required":["id","external_id","date","workers","totals"],"type":"object"},"GigList":{"example":{"data":[{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-awaiting_worker","id":"gig_test_000000000001","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":null,"invoice_total":"251.00","status":"awaiting_worker","status_changed_at":"2026-11-07T12:00:00Z","status_reason":null,"vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-received","id":"gig_test_000000000002","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":null,"invoice_total":"251.00","status":"received","status_changed_at":"2026-11-07T12:00:00Z","status_reason":null,"vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-invoiced","id":"gig_test_000000000003","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":{"due_date":"2026-11-21","iban":"FI2112345600000785","number":"TEST-100002","reference_number":"TEST 100002","total":"251.00"},"invoice_total":"251.00","status":"invoiced","status_changed_at":"2026-11-07T12:00:00Z","status_reason":null,"vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-paid","id":"gig_test_000000000004","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":{"due_date":"2026-11-21","iban":"FI2112345600000785","number":"TEST-100003","reference_number":"TEST 100003","total":"251.00"},"invoice_total":"251.00","status":"paid","status_changed_at":"2026-11-07T12:00:00Z","status_reason":null,"vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-completed","id":"gig_test_000000000005","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":{"due_date":"2026-11-21","iban":"FI2112345600000785","number":"TEST-100004","reference_number":"TEST 100004","total":"251.00"},"invoice_total":"251.00","status":"completed","status_changed_at":"2026-11-07T12:00:00Z","status_reason":null,"vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-declined","id":"gig_test_000000000006","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":null,"invoice_total":"251.00","status":"declined","status_changed_at":"2026-11-07T12:00:00Z","status_reason":"worker_declined","vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-expired","id":"gig_test_000000000007","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":null,"invoice_total":"251.00","status":"expired","status_changed_at":"2026-11-07T12:00:00Z","status_reason":"invitation_expired","vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":"2026-11-07T12:00:00Z","created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-cancelled","id":"gig_test_000000000008","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":null,"invoice_total":"251.00","status":"cancelled","status_changed_at":"2026-11-07T12:00:00Z","status_reason":"gig_cancelled","vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]},{"cancelled_at":null,"created_at":"2026-11-07T12:00:00Z","date":"2026-11-07","external_id":"hv-test-rejected","id":"gig_test_000000000009","location":"Helsinki","title":"Keikka Tavastialla","totals":{"amount":"200.00","invoice_total":"251.00","vat_amount":"51.00"},"updated_at":"2026-11-07T12:00:00Z","warnings":[],"work_type":"performing_arts","workers":[{"amount":"200.00","connection_id":"con_test_8d41c2e07a55","email":"aino@example.com","external_user_id":"u_1842","invoice":null,"invoice_total":"251.00","status":"rejected","status_changed_at":"2026-11-07T12:00:00Z","status_reason":"account_closed","vat_amount":"51.00","vat_percent":"25.5","work_type":"performing_arts"}]}],"has_more":false},"properties":{"data":{"items":{"$ref":"#/components/schemas/Gig"},"type":"array"},"has_more":{"type":"boolean"}},"type":"object"},"GigRequest":{"example":{"date":"2026-11-07","external_id":"hv-2026-11-07-001","location":"Helsinki","title":"Keikka Tavastialla","work_type":"performing_arts","workers":[{"amount":"200.00","email":"aino@example.com","external_user_id":"u_1842"},{"amount":"150.00","email":"eero@example.com","external_user_id":"u_2210"}]},"properties":{"date":{"description":"The day the gig was performed. Decides the VAT rate. Not in the future, not over 12 months ago.","example":"2026-11-07","format":"date","type":"string"},"external_id":{"description":"Your unique id for the gig. Also the idempotency key: the same external_id with the same content returns the existing gig (200); with different content, 409.","example":"hv-2026-11-07-001","pattern":"^[A-Za-z0-9._:\\-]{1,100}$","type":"string"},"location":{"example":"Helsinki","maxLength":100,"type":"string"},"title":{"description":"Shown on the invoice row with the date.","example":"Keikka Tavastialla","maxLength":100,"type":"string"},"work_type":{"description":"A code from GET /v1/work_types for every worker of the gig. Optional when the partner has a default.","example":"performing_arts","type":"string"},"workers":{"description":"One entry per worker; each becomes one invoicing request.","items":{"properties":{"amount":{"description":"The worker's share, VAT-excluded. VAT is added on top at the work type's rate.","example":"200.00","pattern":"^\\d+\\.\\d{2}$","type":"string"},"email":{"description":"With an email, a worker without a connection is invited automatically.","example":"aino@example.com","format":"email","type":"string"},"external_user_id":{"description":"The worker's id from POST /v1/connections. Give this, email, or both.","example":"u_1842","type":"string"},"work_type":{"description":"Overrides the gig's work type for this worker.","example":"performing_arts","type":"string"}},"required":["amount"],"type":"object"},"minItems":1,"type":"array"}},"required":["external_id","date","title","workers"],"type":"object"},"Invoice":{"description":"The invoice to the partner, once it has been sent — enough to automate payment.","properties":{"due_date":{"format":"date","nullable":true,"type":"string"},"iban":{"nullable":true,"type":"string"},"number":{"nullable":true,"type":"string"},"reference_number":{"description":"Pay with this reference.","nullable":true,"type":"string"},"total":{"description":"The invoice total including VAT.","example":"251.00","pattern":"^\\d+\\.\\d{2}$","type":"string"}},"type":"object"},"Me":{"description":"The partner and the key making the request.","properties":{"environment":{"description":"The key's environment.","enum":["test","live"],"type":"string"},"key":{"properties":{"created_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"prefix":{"description":"The key's public prefix, e.g. `kl_test_ab12cd34_…`.","type":"string"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"limits":{"properties":{"daily_amount_cap":{"description":"The most the partner can post per day (Helsinki time), VAT-excluded. Not enforced by the test API.","example":"20000.00","pattern":"^\\d+\\.\\d{2}$","type":"string"},"max_item_amount":{"description":"The largest amount per worker per gig.","example":"5000.00","pattern":"^\\d+\\.\\d{2}$","type":"string"},"max_workers_per_gig":{"example":50,"type":"integer"},"rate_limit_per_minute":{"example":120,"type":"integer"}},"type":"object"},"partner":{"properties":{"name":{"type":"string"},"slug":{"type":"string"}},"type":"object"},"production_enabled":{"description":"Whether Keikkalasku has opened production use for the partner.","type":"boolean"}},"type":"object"},"Problem":{"description":"An RFC 9457 problem document. Every error has these fields.","example":{"code":"invalid_amount","docs_url":"https://kumppani-pp.keikkis.fi/docs/errors#invalid_amount","field":"workers[0].amount","hint":"amount must be a string with two decimals, e.g. \"200.00\", greater than zero. It is VAT-excluded.","request_id":"F1a2B3c4D5e6","status":422,"title":"The amount is not valid.","type":"https://kumppani-pp.keikkis.fi/docs/errors#invalid_amount"},"properties":{"code":{"description":"A stable machine-readable code.","enum":["api_disabled","missing_api_key","invalid_api_key","key_revoked","wrong_environment","partner_suspended","production_not_enabled","ip_not_allowed","insufficient_scope","rate_limited","unknown_host","not_found","invalid_json","invalid_parameter","missing_field","invalid_field","invalid_email","invalid_date","date_in_future","date_too_old","invalid_amount","amount_over_limit","too_many_workers","no_workers","duplicate_worker","worker_identifier_missing","unknown_worker","daily_cap_exceeded","work_type_required","work_type_not_allowed","work_type_not_available_on_date","work_type_retired","idempotency_conflict","already_invoiced"],"example":"invalid_amount","type":"string"},"detail":{"description":"Details of this occurrence, when there are any.","type":"string"},"docs_url":{"description":"Where the error is documented.","type":"string"},"errors":{"description":"With several validation errors, all of them (the first is also the top-level error).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"field":{"description":"The request field the error concerns, e.g. `workers[0].amount`.","example":"workers[0].amount","type":"string"},"hint":{"description":"One line on how to fix the request.","example":"amount must be a string with two decimals, e.g. \"200.00\", greater than zero. It is VAT-excluded.","type":"string"},"request_id":{"description":"The X-Request-Id of the request; quote it to support.","nullable":true,"type":"string"},"status":{"description":"The HTTP status.","example":422,"type":"integer"},"title":{"description":"A short summary of the error type.","type":"string"},"type":{"description":"A URL identifying the error type (same as docs_url).","type":"string"}},"required":["type","title","status","code","hint","docs_url"],"type":"object"},"Totals":{"properties":{"amount":{"description":"Sum of the workers' VAT-excluded amounts.","example":"350.00","pattern":"^\\d+\\.\\d{2}$","type":"string"},"invoice_total":{"description":"Sum of the invoice totals.","example":"439.25","pattern":"^\\d+\\.\\d{2}$","type":"string"},"vat_amount":{"description":"Sum of the VAT.","example":"89.25","pattern":"^\\d+\\.\\d{2}$","type":"string"}},"type":"object"},"Warning":{"description":"A non-blocking notice, e.g. `work_type_deprecated` with its replacement and sunset date.","properties":{"code":{"example":"work_type_deprecated","type":"string"},"replacement":{"nullable":true,"type":"string"},"sunset":{"format":"date","nullable":true,"type":"string"},"work_type":{"type":"string"}},"type":"object"},"WorkType":{"description":"A work type code the partner may use. The code is permanent; the VAT behind it follows the law.","properties":{"available":{"description":"Whether the code has a valid VAT treatment today.","type":"boolean"},"code":{"description":"The permanent code to send as `work_type`.","example":"performing_arts","type":"string"},"default":{"description":"Whether this is the partner's default work type, used when a gig names none.","type":"boolean"},"deprecation":{"description":"Set when the code is being retired. It keeps working until `sunset`, after which requests using it get `422 work_type_retired`.","nullable":true,"properties":{"replacement":{"nullable":true,"type":"string"},"sunset":{"format":"date","nullable":true,"type":"string"}},"type":"object"},"description":{"description":"What kind of work the code covers.","nullable":true,"type":"string"},"name":{"description":"Finnish name.","example":"Esiintyminen","type":"string"},"name_en":{"example":"Performing","type":"string"},"name_fi":{"example":"Esiintyminen","type":"string"},"upcoming":{"description":"The next VAT change already known, if any. Gigs performed on or after `from` get the new rate.","nullable":true,"properties":{"from":{"example":"2027-01-01","format":"date","type":"string"},"vat_percent":{"example":"26","type":"string"}},"type":"object"},"vat_percent":{"description":"The VAT % valid today, as a decimal string.","example":"25.5","nullable":true,"type":"string"}},"required":["code","name","vat_percent","available"],"type":"object"},"WorkTypeList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/WorkType"},"type":"array"},"default_work_type":{"description":"The partner's default code, or null.","nullable":true,"type":"string"}},"type":"object"},"Worker":{"properties":{"amount":{"description":"VAT-excluded share.","example":"200.00","pattern":"^\\d+\\.\\d{2}$","type":"string"},"connection_id":{"nullable":true,"type":"string"},"email":{"nullable":true,"type":"string"},"external_user_id":{"nullable":true,"type":"string"},"invoice":{"allOf":[{"$ref":"#/components/schemas/Invoice"}],"nullable":true},"invoice_total":{"description":"What the partner will be invoiced for this worker.","example":"251.00","pattern":"^\\d+\\.\\d{2}$","type":"string"},"status":{"description":"The worker's status — our public contract, separate from internal statuses:\n`awaiting_worker` (no consent yet; invitation sent), `received` (invoicing request created),\n`invoiced` (invoice sent to the partner; `invoice` is filled in), `paid` (the partner has paid),\n`completed` (the worker's salary has been paid out), `declined` / `expired` / `cancelled` /\n`rejected` (with `status_reason`). Net salaries, taxes and deductions are never shown.\n","enum":["awaiting_worker","received","invoiced","paid","completed","declined","expired","cancelled","rejected"],"type":"string"},"status_changed_at":{"format":"date-time","type":"string"},"status_reason":{"description":"Why, for declined, expired, cancelled and rejected; e.g. `account_closed`, `worker_declined`, `invitation_expired`, `gig_cancelled`, `invoice_credited`, `cancellation_refused`.","nullable":true,"type":"string"},"vat_amount":{"description":"VAT on the amount.","example":"51.00","pattern":"^\\d+\\.\\d{2}$","type":"string"},"vat_percent":{"description":"The VAT % applied, decided by the work type and the gig date.","example":"25.5","type":"string"},"work_type":{"example":"performing_arts","type":"string"}},"required":["amount","status","vat_percent","invoice_total"],"type":"object"}},"securitySchemes":{"bearer":{"description":"`Authorization: Bearer kl_test_…`. Keys are created in the partner portal; each key has scopes (`connections:read`, `connections:write`, `gigs:read`, `gigs:write`).","scheme":"bearer","type":"http"}}},"info":{"description":"Create invoicing requests for gig workers through Keikkalasku.\n\nA partner (a gig platform) invites each worker once (`POST /v1/connections`). After the\nworker has accepted the connection in Keikkalasku, every gig the partner posts\n(`POST /v1/gigs`) becomes one invoicing request per worker, invoiced **to the partner\nitself**: the receiver is fixed by Keikkalasku and never sent in a request. Keikkalasku\ninvoices the partner, withholds its normal service fee and pays the worker. The partner\nfollows each worker's status by polling `GET /v1/gigs`.\n\nTwo environments with separate keys:\n\n* **Test** `https://api.test.keikkalasku.fi` with `kl_test_` keys. Every request is\n  validated exactly as in production, and answered from fixed test data. Nothing is\n  stored. Magic values produce every status and error — see the docs.\n* **Production** `https://api.keikkalasku.fi` with `kl_live_` keys.\n\nAmounts are strings with two decimals, VAT-excluded, always EUR. Errors are\nRFC 9457 problem documents with a stable `code`, the `field` concerned, a `hint`\non how to fix it, and a `docs_url`.\n","title":"Keikkalasku Partner API","version":"1.0.0"},"openapi":"3.0.3","paths":{"/v1/connections":{"get":{"callbacks":{},"deprecated":false,"description":"Oldest first. Page with `starting_after` (the last id you got).\n\nScope: `connections:read`.","operationId":"listConnections","parameters":[{"description":"Only connections in this status.","in":"query","name":"status","schema":{"enum":["pending","active","declined","expired","revoked"],"type":"string"}},{"description":"Page size, 1–100 (default 100).","in":"query","name":"limit","schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"A connection id (`con_…`) from the previous page.","in":"query","name":"starting_after","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionList"}}},"description":"A page of connections."},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `invalid_parameter`"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"List connections","tags":[]},"post":{"callbacks":{},"deprecated":false,"description":"Creates (201) or returns (200) the connection for `external_user_id`. Keikkalasku emails the invitation; it is valid for 30 days. Posting an expired, declined or revoked connection again sends a new invitation.\n\nScope: `connections:write`.","operationId":"createConnection","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Connection"}}},"description":"The existing connection."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Connection"}}},"description":"A new connection, always `pending`."},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `missing_field`, `invalid_field`, `invalid_email`"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"Invite a worker","tags":[]}},"/v1/connections/{id}":{"get":{"callbacks":{},"deprecated":false,"description":"By our id (`con_…`) or your `external_user_id`.\n\nScope: `connections:read`.","operationId":"getConnection","parameters":[{"description":"`con_…` or your external_user_id.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Connection"}}},"description":"The connection."},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `not_found`"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"Get a connection","tags":[]}},"/v1/gigs":{"get":{"callbacks":{},"deprecated":false,"description":"Gigs changed since `updated_since` — the gig or any worker's status — oldest change first. Poll with the latest `updated_at` you have seen.\n\nScope: `gigs:read`.","operationId":"listGigs","parameters":[{"description":"ISO 8601 timestamp.","in":"query","name":"updated_since","schema":{"format":"date-time","type":"string"}},{"description":"Page size, 1–100 (default 100).","in":"query","name":"limit","schema":{"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GigList"}}},"description":"A page of gigs."},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `invalid_parameter`"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"List changed gigs","tags":[]},"post":{"callbacks":{},"deprecated":false,"description":"Creates the gig; every worker becomes one invoicing request to the partner once their\nconnection is active. The work type is taken from the worker, else the gig, else the\npartner's default. With `?dry_run=true` every validation and limit runs and the answer\nshows exactly what would be created, without saving anything.\n\n\nScope: `gigs:write`.","operationId":"createGig","parameters":[{"description":"Validate and preview without saving.","in":"query","name":"dry_run","schema":{"type":"boolean"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GigRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Gig"}}},"description":"The existing gig (same external_id and content), or the dry-run result (DryRun schema)."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Gig"}}},"description":"The created gig."},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `idempotency_conflict`"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `missing_field`, `invalid_field`, `invalid_email`, `invalid_date`, `date_in_future`, `date_too_old`, `invalid_amount`, `amount_over_limit`, `too_many_workers`, `no_workers`, `duplicate_worker`, `worker_identifier_missing`, `unknown_worker`, `daily_cap_exceeded`, `work_type_required`, `work_type_not_allowed`, `work_type_not_available_on_date`, `work_type_retired`"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"Report a gig","tags":[]}},"/v1/gigs/{id}":{"delete":{"callbacks":{},"deprecated":false,"description":"Possible while no worker has been invoiced. Workers still waiting are cancelled at once; invoicing requests not yet sent are withdrawn within a minute.\n\nScope: `gigs:write`.","operationId":"cancelGig","parameters":[{"description":"`gig_…` or your external_id.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Cancelled."},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `not_found`"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `already_invoiced`"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"Cancel a gig","tags":[]},"get":{"callbacks":{},"deprecated":false,"description":"By our id (`gig_…`) or your `external_id`.\n\nScope: `gigs:read`.","operationId":"getGig","parameters":[{"description":"`gig_…` or your external_id.","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Gig"}}},"description":"The gig with every worker's status."},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `not_found`"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"Get a gig","tags":[]}},"/v1/me":{"get":{"callbacks":{},"deprecated":false,"description":"Use this to test a key.","operationId":"getMe","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}},"description":"The key and its partner."},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"The key and partner","tags":[]}},"/v1/work_types":{"get":{"callbacks":{},"deprecated":false,"description":"The codes allowed for this partner, each with the VAT valid today, any announced change and any deprecation. You never send a VAT rate: the code and the gig date decide it.\n\nScope: `gigs:read`.","operationId":"listWorkTypes","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkTypeList"}}},"description":"The allowed work types."},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Error. Possible codes: `api_disabled`, `missing_api_key`, `invalid_api_key`, `key_revoked`, `wrong_environment`, `partner_suspended`, `production_not_enabled`, `ip_not_allowed`, `insufficient_scope`, `rate_limited`"}},"summary":"Work types you may use","tags":[]}}},"security":[{"bearer":[]}],"servers":[{"description":"Test API (kl_test_ keys)","url":"https://api.test.keikkalasku.fi","variables":{}},{"description":"Production (kl_live_ keys)","url":"https://api.keikkalasku.fi","variables":{}}],"tags":[]}