Test mode
Build and verify a full Koil integration with test-mode keys and magic connections, before any provider app is approved.
Test mode is Koil's sandbox. A test-mode API key uses the same /v1 endpoints, schemas, event topics, idempotency rules, pagination, and error envelopes as a live key, against fully isolated infrastructure and simulated providers. Nothing a test-mode key does can reach a real provider or live data.
Keys
Every API key belongs to exactly one mode, and the mode is visible in the key itself: koil_live_… or koil_test_…. Send the full value as the bearer token:
Authorization: Bearer koil_test_...The prefix makes a key's environment obvious in an env file and lets leak scanners match it, but it is not what decides the mode: Koil checks the prefix against the key's own mode and rejects a mismatch, and an unprefixed value is rejected outright. Both modes belong to the same Organization and users; switching to test mode means using a test key, not a separate account. Create keys in the Koil admin console.
Magic connections
Test mode has no OAuth flow. Instead, every Organization can use a fixed catalog of magic connections — the equivalent of test card numbers — each of which stands for a provider grant in a known state:
healthy— an active grant carrying every scope any capability needs.expired— a grant that can no longer be refreshed; operations fail as they would after a user revokes access.missing_scopes— an active grant carrying only what profile discovery needs, so the profile can be listed and connected and every other operation is refused withscope_insufficient.
Use one exactly where you would use a real connectionId: list its eligible profiles, then create a Connected Profile from one of them. The Quickstart walks through it.
curl "https://api.koil.co/v1/connections/test_conn_youtube_healthy/eligible-profiles" \ -H "Authorization: Bearer $KOIL_API_KEY"Not yet connectable in test mode: Instagram, Facebook
WhatsApp, TikTok, YouTube, Google Business Profile, LinkedIn magic connections can be discovered and connected end to end. For the others, build against a live key with your own app for now:
- Instagram: Test mode's simulated Graph API lists no Pages, so discovery finds no Instagram account, and Facebook Login's connect step needs a Page token test mode does not mint.
- Facebook: Test mode's simulated Graph API lists no Pages, so discovery finds none, and connecting a Page needs a Page token test mode does not mint.
The catalog below is generated from the same declarations test mode serves, so every id listed resolves and nothing else does.
| Connection id | Provider | Status | Scopes |
|---|---|---|---|
test_conn_instagram_healthy | instagram | active | instagram_basic, instagram_content_publish, instagram_manage_comments, instagram_manage_messages, pages_read_engagement, pages_show_list |
test_conn_instagram_expired | instagram | invalid | instagram_basic, instagram_content_publish, instagram_manage_comments, instagram_manage_messages, pages_read_engagement, pages_show_list |
test_conn_instagram_missing_scopes | instagram | active | instagram_basic, pages_show_list |
test_conn_facebook_healthy | facebook | active | pages_manage_engagement, pages_manage_metadata, pages_manage_posts, pages_messaging, pages_read_engagement, pages_read_user_content, pages_show_list, publish_video |
test_conn_facebook_expired | facebook | invalid | pages_manage_engagement, pages_manage_metadata, pages_manage_posts, pages_messaging, pages_read_engagement, pages_read_user_content, pages_show_list, publish_video |
test_conn_facebook_missing_scopes | facebook | active | pages_show_list |
test_conn_whatsapp_healthy | whatsapp | active | business_management, whatsapp_business_management, whatsapp_business_messaging |
test_conn_whatsapp_expired | whatsapp | invalid | business_management, whatsapp_business_management, whatsapp_business_messaging |
test_conn_whatsapp_missing_scopes | whatsapp | active | business_management, whatsapp_business_management |
test_conn_tiktok_healthy | tiktok | active | biz.brand.insights, comment.list, comment.list.manage, message.list.read, message.list.send, user.account.type, user.info.basic, user.info.username, video.list, video.publish, video.upload |
test_conn_tiktok_expired | tiktok | invalid | biz.brand.insights, comment.list, comment.list.manage, message.list.read, message.list.send, user.account.type, user.info.basic, user.info.username, video.list, video.publish, video.upload |
test_conn_tiktok_missing_scopes | tiktok | active | user.account.type, user.info.basic, user.info.username |
test_conn_youtube_healthy | youtube | active | https://www.googleapis.com/auth/youtube.force-ssl |
test_conn_youtube_expired | youtube | invalid | https://www.googleapis.com/auth/youtube.force-ssl |
test_conn_youtube_missing_scopes | youtube | active | none |
test_conn_google_business_profile_healthy | google_business_profile | active | https://www.googleapis.com/auth/business.manage |
test_conn_google_business_profile_expired | google_business_profile | invalid | https://www.googleapis.com/auth/business.manage |
test_conn_google_business_profile_missing_scopes | google_business_profile | active | none |
test_conn_linkedin_healthy | linkedin | active | r_organization_social, r_organization_social_feed, rw_organization_admin, w_organization_social, w_organization_social_feed |
test_conn_linkedin_expired | linkedin | invalid | r_organization_social, r_organization_social_feed, rw_organization_admin, w_organization_social, w_organization_social_feed |
test_conn_linkedin_missing_scopes | linkedin | active | rw_organization_admin |
Connect Sessions and POST /v1/connections/import are not available in test mode; they need a real provider app. Build and test everything downstream of the Connection with magic connections, then run the connect flow against your own app in live mode.
What is isolated
Test mode keeps its own database, event delivery, and background workers, so there is no shared state between modes. Every Koil id a test-mode key produces carries a test_ prefix (test_cp_…, test_pub_…, test_med_…), and every delivered event carries metadata.mode — live or test — so a receiver shared between modes can tell them apart.
Provider content reads return deterministic fixture data through the same schemas and pagination rules as live reads.
Limits
Test usage is never billed. Test resources are bounded: each Organization may hold a small number of test Connected Profiles, test workflows run for at most an hour, and test state is disposable and may be reset. So a test-mode publish may be scheduled at most 45 minutes ahead; a later scheduling.at is refused with validation_error.