Skip to content
Akedly

CLI recipes

Common setup jobs, with commands you can preview before saving.


Run a full verification cycle

Send and verify a free V1.2 test code from an empty terminal. Quickstart uses a fake Test Pair number and code returned by the server, so no real message goes out.

  1. Log in with Full access.

    bash
    akedly login
    

    Choose Full access on the approval page. Quickstart refuses a Read-only login.

  2. Check your setup.

    bash
    akedly doctor
    

    It checks your login, the server, your pipelines, your balance and WhatsApp, and sends nothing.

  3. Preview the steps.

    bash
    akedly quickstart --dry-run
    

    Lists the steps quickstart would take and makes no requests.

  4. Run it.

    bash
    akedly quickstart --yes
    

    Without --yes, quickstart stops with CONFIRMATION_REQUIRED (exit 65) and changes nothing.

Next: the quickstart and doctor reference.


Connect WhatsApp

Connecting your own WhatsApp Business Account goes through Meta's sign-up in the dashboard. The CLI gives you the link and waits for the result.

  1. Get the link and wait.

    bash
    akedly whatsapp connect --wait
    

    The CLI prints the dashboard link for your region and does not open a browser. It writes a handoff event to stderr in JSON mode (progress events).

    The link is on the dashboard of the deployment you are logged in to:

    • Egypt: https://app.akedly.io/admin/whatsapp-connect
    • KSA (--ksa): https://ksa.app.akedly.io/admin/whatsapp-connect
  2. Finish the sign-up in the dashboard.

    Meanwhile the CLI checks akedly whatsapp status every 10 seconds for up to 10 minutes. --timeout <seconds> changes the wait.

  3. Check that you can send.

    bash
    akedly whatsapp status
    akedly whatsapp diagnose
    

    A finished wait confirms only that the account is connected. It does not confirm registered numbers, business verification or that sending is ready.

With more than one number, choose the one used for OTPs:

bash
akedly whatsapp set-primary <phoneNumberId> --yes

Use the phoneNumberId from whatsapp status. It needs --yes because it changes the number your OTPs are sent from. If the account was already connected and nothing new happens in the dashboard, the wait times out. The CLI cannot see a Meta sign-up that was abandoned or failed.

Next: the WhatsApp reference and Your WhatsApp Business Account.


Replace an API key without downtime

Issue a new key, move your app to it, then revoke the old one with a grace period.

  1. Create the new key.

    bash
    akedly api-keys create --label <name> --secret-file <new path> --yes
    

    The Secret is returned only once. --secret-file writes it to a new private file for your app's secret store and keeps it out of the output. Add --save to also store it for the CLI's own Sending Commands.

    This key can use every pipeline, so the command needs --yes. A key limited with --scope selected --pipeline-ids <ids> needs no --yes, unless you add --save or --replaces-api-key-id. --save needs --yes because it changes the default key the CLI sends with.

  2. Deploy the new Secret.

    Put the new Secret in your app's secret store and confirm your traffic works with it.

  3. Revoke the old key.

    bash
    akedly api-keys list
    akedly api-keys revoke <id> --grace-minutes <0-1440> --yes
    

    --grace-minutes is required: the old key keeps working for that many minutes, up to 24 hours. 0 stops it now.

  • api-keys create --replaces-api-key-id <id> --yes replaces a key in one step, but the old Secret stops immediately. Use it only when downtime does not matter.
  • api-keys create recovers once by itself. After a network error or a server error it sends the request again with the same idempotency key, and if the response has no Secret it calls recover-secret once. If that still fails, follow the error hint, or run akedly api-keys recover-secret with exactly one of --idempotency-key or --api-key-id.
  • akedly api-keys use <prefix> makes a saved key the default for this region; --secret-file <path> imports a key you already have.

Next: the API keys reference.


Configure a V1.2 pipeline

Create a pipeline with your real callback URLs, then use the returned id. The webhook Secret path must be new; keep the resulting file private.

bash
akedly pipelines create --name "Website OTP" --api-version v1.2 --redirect-url https://example.com/verified --webhook-url https://example.com/webhooks/akedly --secret-file ./website-webhook-secret
akedly pipelines update <id> --verification-methods whatsapp,sms --method-order custom --otp-language en --status active --yes
akedly pipelines get <id>

Changing OTP language can provision its template on your connected WhatsApp account. The commands configure the pipeline; they do not prove message delivery. For a free fake-number verification cycle on this pipeline, run akedly quickstart --pipeline-id <id> --yes. Its dev-mode and webhook effects are described above.

Use pipeline settings for destination countries, protections and delivery policy. Add --dry-run to preview an update before saving.

Set up a V2 widget

Use your own callback endpoints. V2 requires both; create and activate the pipeline before attaching the widget.

bash
akedly pipelines create --name "Website V2" --api-version v2 --redirect-url https://example.com/verified --webhook-url https://example.com/webhooks/akedly --secret-file ./v2-webhook-secret
akedly pipelines update <pipeline-id> --verification-methods whatsapp,sms --method-order custom --status active --yes
akedly widgets create --name "Website widget" --pipeline-id <pipeline-id> --company-name Example --widget-language en --secret-file ./website-widget-secret
akedly widgets get <widget-id>

Keep both Secret files. Widget Secrets cannot be revealed or recovered later. After a partial create, preserve the saved file and widgetId, then run the exact pipelines update command returned in details.recovery; do not create another widget to retry its pipeline settings.

Continue with the V2 start flow to integrate the widget in your app. Widget settings explains appearance, rate limits and pipeline-owned controls. A successful setup command is not a completed verification.

Use a library OTP template

Your own WhatsApp Business Account must be active. Find a library entry, then create the template using its exact name:

bash
akedly whatsapp status
akedly whatsapp otp-templates library
akedly whatsapp otp-templates create --library-name <library-name> --languages en,ar
akedly whatsapp otp-templates list

Creation checks the requested languages' approval for up to 30 seconds. A pending approval still returns success because the template was saved; stderr gives the status and attach command. Wait until the language you need is approved, then attach it:

bash
akedly pipelines update <pipeline-id> --otp-language en --otp-template <template-id> --yes

The pipeline needs an active WhatsApp method, your connected account and approval for its resulting OTP language. To restore the built-in template, use --otp-template default --yes.

TEMPLATE_PROVISIONING_FAILED means the template was saved. List it, then recover NOT_FOUND languages with akedly whatsapp otp-templates update <template-id> --add-languages en,ar; creating again can duplicate the operation. These commands remain available; the CLI's withdrawn authenticator enrollment is a separate feature.

Connect your own Turnstile keys

For a V1.2 Web integration, save the Cloudflare secret key in a private local file. Use only the public site key in the command and browser link.

bash
akedly pipelines update <id> --turnstile on --turnstile-platform web --turnstile-site-key <public-site-key> --turnstile-secret-key-file <private-file> --yes

For new credentials, this first command is refused with TURNSTILE_SETUP_TOKEN_MISSING; its hint gives a link to the Turnstile setup-token helper with the public site key filled in. Add docs.akedly.io to that Cloudflare widget's Hostnames, open the link, then copy its token.

bash
akedly pipelines update <id> --turnstile on --turnstile-platform web --turnstile-site-key <public-site-key> --turnstile-secret-key-file <private-file> --turnstile-test-token <fresh-token> --yes
akedly pipelines get <id>

The token works once and expires in five minutes. Generate another after a refused or uncertain save. Every key flag requires --turnstile on; the secret-file flag accepts - for piped stdin. --dry-run masks credentials, including secret query parameters and secret fields inside JSON text, but does not prove the key pair works.

Fit rate limits to your traffic

For a V1.2 pipeline, preview and apply recommendations from the selected period:

bash
akedly pipelines update <pipeline-id> --recommended-limits --period last-month --dry-run
akedly pipelines update <pipeline-id> --recommended-limits --period last-month --yes
akedly pipelines get <pipeline-id>

This changes pipeline-wide limits with a 10% growth buffer, keeping phone/IP limits and breaker sensitivity. V1/V2 pipelines route the request to every attached widget, including inactive ones. To target one widget:

bash
akedly widgets update <widget-id> --recommended-limits --period last-quarter --dry-run
akedly widgets update <widget-id> --recommended-limits --period last-quarter --yes
akedly widgets get <widget-id>

Widget recommendations use account-wide widget traffic, replace all 18 limits and enable/configure the circuit breaker. They do not change appearance, PoW or the breaker's trip state.

NOT_ENOUGH_TRAFFIC saves nothing: keep the current limits, choose a longer period, or supply your own pipeline or widget JSON file with --rate-limits-file. Recommendations cannot be combined with explicit limit files; widget recommendations also refuse breaker flags.