Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/appicons/io.pilot.didit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
255 changes: 255 additions & 0 deletions src/data/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2343,6 +2343,261 @@ export const apps: App[] = [
"publishedAt": "2026-07-07",
"updatedAt": "2026-07-07"
}
,
{
"id": "io.pilot.didit",
"name": "Didit",
"tagline": "One API for identity and fraud \u2014 KYC, liveness, face match, AML, and more, with a no-broker key you mint in one call.",
"description": "**Didit is one API for identity and fraud** \u2014 KYC/ID verification, liveness, face match, AML screening, proof of address, database validation, and email/phone OTP, wrapped as a single Pilot app. It fronts Didit's full platform: **hosted verification sessions**, reusable **workflows**, **users**, **billing**, **blocklists**, **questionnaires**, and **webhooks** \u2014 40 methods in all.\n\n## Your own key, minted in one call \u2014 no email, no code\n\nThe hard part of using an identity provider is usually onboarding: signing up, confirming an email code, and wiring the key. This app removes all of it. **`didit.signup` takes no arguments** and returns a working key:\n\n- It signs a keyless request (your Pilot identity) to Pilot's Didit broker. The broker provisions a mailbox on Pilot infrastructure, registers a Didit account, reads Didit's one-time email code **server-side**, verifies it, and hands back your account's `api_key`.\n- The adapter caches `{email, api_key}` to `$APP/secrets.json`. From then on **every other method sends your key as `x-api-key` automatically** \u2014 you never see an inbox, a code, or the key unless you ask (`didit.account`).\n- **Idempotent:** the broker mints at most one Didit account per Pilot identity, so a repeat call \u2014 or a fresh install on another machine \u2014 returns the *same* account. The account is entirely **yours**: verifications bill to **your** Didit balance (top up with `didit.billing_topup`), and Pilot adds no markup. Each account includes Didit's **500 free full-KYC checks/month**; account creation, management, sessions CRUD, users, billing, blocklists, questionnaires and webhooks are all **free** \u2014 you pay only per verification you run.\n\n## The fast path\n\n1. `didit.signup {}` \u2192 your key is cached (one call, ~5s, no email).\n2. `didit.create_workflow` `{workflow_label:\"KYC\", features:[{feature:\"OCR\"},{feature:\"LIVENESS\"},{feature:\"FACE_MATCH\"}]}` \u2192 get `uuid`.\n3. `didit.create_session` `{workflow_id, vendor_data:\"user-123\"}` \u2192 send the user to the returned `url`.\n4. `didit.get_decision` `{session_id}` (or a webhook) \u2192 read the Approved/Declined result and extracted data.\n\n`didit.account` returns your provisioned email + key any time.\n\n## What each area does\n\n- **Sessions** \u2014 hosted flows where the user completes verification at a Didit URL, so you never handle document images: `create_session`, `get_decision`, `list_sessions`, `update_session_status` (approve/decline/resubmit), `delete_session`, `batch_delete_sessions`, `share_session` / `import_session` (B2B KYC reuse), `list_reviews`, `create_review`.\n- **Workflows** \u2014 templates built from an ordered `features` array (`OCR`, `LIVENESS`, `FACE_MATCH`, `AML`, `PROOF_OF_ADDRESS`, `PHONE_VERIFICATION`, `EMAIL_VERIFICATION`, `DATABASE_VALIDATION`, `IP_ANALYSIS`, `AGE_ESTIMATION`, `NFC`, `QUESTIONNAIRE`, `KYB_*`), each with an optional per-feature `config`: `create_workflow`, `list_workflows`, `get_workflow`, `update_workflow`, `delete_workflow`.\n- **Standalone checks (JSON, no session)** \u2014 `aml` (sanctions/PEP/adverse-media, $0.20), `database_validation` (gov sources, from $0.05).\n- **Contact** \u2014 `email_send`/`email_check` ($0.03) and `phone_send`/`phone_check` (from $0.03) OTP verification.\n- **Billing** \u2014 `billing_balance`, `billing_topup` (Stripe checkout URL).\n- **Governance** \u2014 `blocklist_*` (auto-flag repeat faces/docs/phones/emails), `questionnaire_*` (custom forms), `users_*` (people grouped by your `vendor_data`), `get_webhook`/`update_webhook` (set + rotate the HMAC secret programmatically).\n\n## Pricing\n\nPay-per-check on **your** Didit balance \u2014 no Pilot markup. See the full rate card in `didit.help`. Highlights: full KYC bundle **$0.33/check** (first **500/month free**), ID verification $0.15, passive liveness $0.10, face match $0.05, **face search free**, AML $0.20, PoA $0.20, email/phone from $0.03. Image-upload APIs (direct ID scan, liveness, face match, face search, age estimation, PoA) run through the **hosted session** flow rather than as direct methods.\n\n## Notes\n\n- The adapter dials exactly two hosts: Pilot's broker (`broker.pilotprotocol.network`) for the one-call `didit.signup`, and Didit (`verification.didit.me`) for every operational call with your cached key. It holds no shared secret; the broker signs you in, then steps out of the data path.\n- Plain request/response REST \u2014 no websockets, no async jobs. Rate limits: ~600 session-creates/min, 300/min per other method; the account OTP register is 5/IP/hour.\n- Errors surface verbatim: `401` (run `didit.signup` first), `403` (top up credits), `429` (back off).\n",
"categories": [
"security"
],
"primaryCategory": "security",
"keywords": [
"kyc",
"identity",
"verification",
"aml",
"liveness",
"face-match",
"biometrics",
"proof-of-address",
"sanctions",
"pep",
"onboarding",
"fraud",
"kyb",
"otp",
"didit"
],
"version": "1.0.0",
"vendor": "Didit",
"vendorUrl": "https://didit.me",
"license": "Proprietary",
"sourceUrl": "https://github.com/didit-protocol/skills",
"homepage": "https://didit.me",
"methods": [
{
"name": "didit.signup",
"summary": "Get your own Didit API key in ONE call \u2014 no email, no code, no human step. This signs a keyless request to Pilot's Didit broker, which provisions a mailbox on Pilot infrastructure, registers a Didit account, reads the emailed one-time code server-side, verifies it, and returns your account's api_key. The adapter caches {email, api_key} to $APP/secrets.json, and from then on EVERY other didit.* method authenticates automatically (x-api-key) \u2014 you never handle the key or an inbox. Idempotent: the broker mints at most one account per Pilot identity, so a repeat call (or a fresh install) returns the SAME account. Run this ONCE before any other method. FREE \u2014 account creation costs nothing; you pay only per verification you run, and each account includes Didit's 500 free full-KYC checks/month. The account (email + key) is retrievable any time via didit.account. Takes no arguments."
},
{
"name": "didit.account",
"summary": "Retrieve your cached Didit account \u2014 the email the broker provisioned for you and your api_key \u2014 plus a signed_up flag. Local, instant, FREE (reads $APP/secrets.json; no backend call). Use it to confirm you're signed up or to read your key. If signed_up is false, call didit.signup first."
},
{
"name": "didit.billing_balance",
"summary": "Check your remaining Didit credit balance (and auto-refill settings). FREE. Returns {balance, auto_refill_enabled, auto_refill_amount, auto_refill_threshold}. Verifications draw down this balance; check it before a batch of checks."
},
{
"name": "didit.billing_topup",
"summary": "Add credit to your Didit balance. FREE call \u2014 returns a Stripe checkout URL (checkout_session_url) to present to the user; the charge happens on Stripe, not through Pilot."
},
{
"name": "didit.create_workflow",
"summary": "Create a verification workflow \u2014 the reusable template that defines which checks a hosted session runs, in order. FREE to create; you're billed per feature only when a session actually runs it. Returns {uuid} \u2014 pass it as workflow_id to didit.create_session. The v3 API takes a `features` ARRAY (in the order users complete them); each item is {feature, config?} where feature is one of OCR, NFC, LIVENESS, FACE_MATCH, PROOF_OF_ADDRESS, QUESTIONNAIRE, DOCUMENT_AI, PHONE_VERIFICATION, EMAIL_VERIFICATION, DATABASE_VALIDATION, AML, IP_ANALYSIS, AGE_ESTIMATION, KYB_REGISTRY, KYB_DOCUMENTS, KYB_KEY_PEOPLE. Example: [{\"feature\":\"OCR\"},{\"feature\":\"LIVENESS\",\"config\":{\"face_liveness_method\":\"PASSIVE\"}},{\"feature\":\"FACE_MATCH\"}]. The API uses a strict field whitelist \u2014 any undeclared key (e.g. workflow_type) is a 400. Max 50 workflows per account."
},
{
"name": "didit.list_workflows",
"summary": "List your verification workflows with their features and total_price. FREE."
},
{
"name": "didit.get_workflow",
"summary": "Get one workflow by id. FREE."
},
{
"name": "didit.update_workflow",
"summary": "Update a workflow (partial \u2014 send only the fields to change; same field set as create_workflow, e.g. a replacement `features` array, workflow_label, status, is_default). FREE."
},
{
"name": "didit.delete_workflow",
"summary": "Delete a workflow. FREE. Existing sessions are unaffected. Returns 204."
},
{
"name": "didit.create_session",
"summary": "Start a hosted verification session for a user and get a URL to send them to. This is Didit's recommended path for ID/liveness/face-match/AML/PoA/etc. \u2014 the user completes everything at the hosted URL, so you never handle document images yourself. COST is the sum of the features the workflow enables (e.g. a full KYC bundle \u2248 $0.33/check; 500 full-KYC checks/month are free), charged to your Didit balance when the session runs. Returns {session_id, session_token, url, status}. Poll didit.get_decision or set a webhook for the result. Nested objects (contact_details, expected_details) are passed as JSON objects."
},
{
"name": "didit.get_decision",
"summary": "Get the full decision and extracted data for a session \u2014 status plus id_verifications, liveness_checks, face_matches, aml_screenings, phone/email verifications, poa_verifications, database_validations, ip_analyses, and reviews. FREE (reading results). Image URLs in the response expire after 60 minutes. Statuses: Not Started | In Progress | In Review | Approved | Declined | Abandoned | Expired | Resubmitted."
},
{
"name": "didit.list_sessions",
"summary": "List/filter your sessions (paginated). FREE."
},
{
"name": "didit.update_session_status",
"summary": "Manually override a session's status (approve/decline/resubmit) \u2014 the programmatic-review action. FREE. For Resubmitted, pass nodes_to_resubmit; the session must be Declined, In Review, or Abandoned."
},
{
"name": "didit.delete_session",
"summary": "Permanently delete a session and all its data. FREE. Returns 204."
},
{
"name": "didit.batch_delete_sessions",
"summary": "Delete many sessions at once by number (or all). FREE."
},
{
"name": "didit.share_session",
"summary": "Generate a share_token so a partner can import a finished session (B2B KYC reuse). FREE. Works only for finished sessions."
},
{
"name": "didit.import_session",
"summary": "Import a session shared by a partner via its share_token. FREE."
},
{
"name": "didit.list_reviews",
"summary": "List the manual-review activity for a session (status changes, notes). FREE."
},
{
"name": "didit.create_review",
"summary": "Add a manual review decision to a session (Approved/Declined/In Review). FREE."
},
{
"name": "didit.aml",
"summary": "Screen a person or company against sanctions, PEP, and adverse-media watchlists (standalone, no session). COST $0.20/check on your Didit balance. Returns matches with scores and categories."
},
{
"name": "didit.database_validation",
"summary": "Cross-check identity fields against government / authoritative databases (standalone). COST from $0.05/check (1x1, single source) to $0.30 (2x2, two-source cross-validation); varies by country/source. Covers 1,000+ sources across 18+ countries."
},
{
"name": "didit.email_send",
"summary": "Send a one-time verification code to an email address. Part of email verification ($0.03 per completed verification, charged to your Didit balance)."
},
{
"name": "didit.email_check",
"summary": "Verify the email OTP the user received. Completes an email verification ($0.03)."
},
{
"name": "didit.phone_send",
"summary": "Send a one-time code by SMS / WhatsApp / Telegram. Part of phone verification (from $0.03 per completed verification, varies by channel)."
},
{
"name": "didit.phone_check",
"summary": "Verify the phone OTP the user received. Completes a phone verification (from $0.03)."
},
{
"name": "didit.blocklist_add",
"summary": "Add a session's face/document/phone/email to your blocklist so future matches auto-flag (FACE_IN_BLOCKLIST, etc.). FREE."
},
{
"name": "didit.blocklist_remove",
"summary": "Remove items from your blocklist. FREE."
},
{
"name": "didit.blocklist_list",
"summary": "List your blocklisted items. FREE."
},
{
"name": "didit.create_questionnaire",
"summary": "Create a custom form (7 element types) to attach to a questionnaire_verification workflow. FREE."
},
{
"name": "didit.list_questionnaires",
"summary": "List your questionnaires. FREE."
},
{
"name": "didit.get_questionnaire",
"summary": "Get one questionnaire. FREE."
},
{
"name": "didit.update_questionnaire",
"summary": "Update a questionnaire (partial). FREE."
},
{
"name": "didit.delete_questionnaire",
"summary": "Delete a questionnaire. FREE. Returns 204."
},
{
"name": "didit.list_users",
"summary": "List verified individuals (grouped by vendor_data) with status and session counts. FREE."
},
{
"name": "didit.get_user",
"summary": "Get one user by your vendor_data. FREE."
},
{
"name": "didit.update_user",
"summary": "Update a user's display name / manual status / metadata. FREE."
},
{
"name": "didit.batch_delete_users",
"summary": "Delete many users by vendor_data (or all). FREE."
},
{
"name": "didit.get_webhook",
"summary": "Get your webhook configuration (url, version, HMAC secret_shared_key, capture_method). FREE."
},
{
"name": "didit.update_webhook",
"summary": "Set/rotate your webhook config programmatically \u2014 no console needed. FREE."
},
{
"name": "didit.help",
"summary": "Discovery: every method with params, latency, and the per-endpoint pricing rate card."
}
],
"changelog": [
{
"version": "1.0.0",
"notes": [
"Initial release \u2014 the full Didit identity platform over one byo HTTPS app: 39 methods + didit.help.",
"One-call broker signup: didit.signup {} mints and caches a per-user Didit API key with no email and no code (Pilot's broker runs the signup and reads the OTP server-side); didit.account retrieves it; ops stay direct to Didit.",
"KYC/ID, liveness, face match, AML, proof-of-address, database validation, email/phone OTP, hosted sessions, workflows, billing, blocklist, questionnaires, users, webhooks \u2014 per-endpoint pricing in didit.help."
]
}
],
"grants": [
"fs.read:$APP/config.json",
"fs.read:$APP/secrets.json",
"fs.write:$APP/secrets.json",
"key.sign:self",
"net.dial:verification.didit.me",
"net.dial:broker.pilotprotocol.network",
"audit.log:*"
],
"bundles": [
{
"platform": "darwin-arm64",
"bytes": 4954879
},
{
"platform": "darwin-amd64",
"bytes": 5287106
},
{
"platform": "linux-arm64",
"bytes": 4696257
},
{
"platform": "linux-amd64",
"bytes": 5130067
}
],
"installedBytes": 9324763,
"depends": [],
"protection": "shareable",
"featured": false,
"real": true,
"inCatalogue": true,
"icon": {
"mode": "image",
"img": "/appicons/io.pilot.didit.png",
"fit": "contain",
"pos": "center",
"color": "#ffffff",
"ink": false,
"file": null,
"hue": 220
},
"minPilotVersion": "1.10.0",
"runtimes": [
"go"
],
"publishedAt": "2026-07-07",
"updatedAt": "2026-07-08"
}
];

export const featuredOrder: string[] = ["io.pilot.postgres","io.pilot.duckdb","io.pilot.docker"];
Expand Down
2 changes: 1 addition & 1 deletion src/pages/app-store.astro
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const canonicalUrl = 'https://pilotprotocol.network/app-store';
const featured = featuredApps();
const hero = featured[0];
const sideFeatured = featured.slice(1, 4);
const freshPinned = ['io.pilot.agentphone', 'io.pilot.orthogonal', 'io.pilot.bowmark', 'io.pilot.miren', 'io.pilot.smol', 'io.pilot.wallet', 'io.pilot.slipstream'];
const freshPinned = ['io.pilot.didit', 'io.pilot.agentphone', 'io.pilot.orthogonal', 'io.pilot.bowmark', 'io.pilot.miren', 'io.pilot.smol', 'io.pilot.wallet', 'io.pilot.slipstream'];
const freshExclude = new Set(['io.pilot.postgres', 'io.pilot.docker']);
const fresh = [
...freshPinned.map((id) => apps.find((a) => a.id === id)).filter(Boolean),
Expand Down
15 changes: 7 additions & 8 deletions src/pages/plain/app-store.astro
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
---
// Auto-generated by scripts/regen-plain.mjs. Edit the marketing source and re-run.
// plain-source: src/pages/app-store.astro
// plain-source-sha256: 8a9d28e8652fe841199f155c1275837551d175fa50db613f725f9fedecb7c93c
// plain-source-sha256: 3ee1de7d24a2e16e41b490f914ad2a359b7031d57cb2721fa82ec79674b5d493
import PlainLayout from '../../layouts/PlainLayout.astro';
---
<PlainLayout title="App Store — Pilot Protocol" description="Agent-native apps on the Pilot Protocol network. Install with one command; publish your own from your browser or by PR." canonical="https://pilotprotocol.network/plain/app-store/">

<h1>App Store</h1>

<p>The Pilot Protocol App Store provides agent apps. Apps install as sha256-pinned, signature-verified native services. They are auto-spawned by the daemon and callable over typed IPC.</p>
<p>A collection of agent apps for the Pilot Protocol. Apps install as sha256-pinned, signature-verified native services, are auto-spawned by the daemon, and are callable over typed IPC.</p>

<h2>App Discovery</h2>
<p>The App Store contains curated lists, including featured apps and new or updated apps. Apps are also organized by category. A search function is available to find apps by name, capability, or vendor.</p>
<h2>Browsing Apps</h2>
<p>The App Store highlights featured, new, and recently updated apps. Apps are organized into categories and can be found with search.</p>

<h2>Publishing an App</h2>
<p>Apps are published by signing a manifest.json file, attaching a bundle, and opening a pull request.</p>
<p>Once merged, the app is installable on the overlay network with the pilotctl command.</p>
<p>To publish an app, sign a manifest.json, attach a bundle, and open one pull request. Once merged, the app becomes installable on the overlay network via its ID.</p>
<pre><code>pilotctl appstore install &lt;id&gt;</code></pre>

<h2>Related</h2>
<ul>
<li><a href="/plain/publish">Publish an App</a></li>
<li><a href="/docs/app-store">App Store Documentation</a></li>
<li><a href="/plain/publish">Publish your app</a></li>
<li><a href="/docs/app-store">Read the docs</a></li>
</ul>

</PlainLayout>
Loading