Developers
Limits, metering and billing
Call limits keep one credential from crowding out the rest; quotas cap how much a writer can propose. Both are separate from billing.
Limits and quotas
Call limits count per credential over a short rolling window and per UTC day; the short window is kept in memory per server instance, so treat it as approximate. Proposal quotas are separate: they count proposals, not calls.
| Limit | Value | Unit | Defined in |
|---|---|---|---|
source_key_calls | 30 | calls per 60 s per source key (approximate: the limiter is in memory per instance) | supabase/functions/_shared/arp/auth.ts:31 |
owner_key_calls | 30 | calls per 60 s per owner key (the default and the most a new key may set; approximate, in memory per instance) | supabase/migrations/20261215110000_arp_p1_keys_and_ledger.sql:726 |
owner_key_daily_calls | 1,000 | calls per 24 h per owner key (the default and the most a new key may set) | supabase/migrations/20261215110000_arp_p1_keys_and_ledger.sql:726 |
source_key_daily_calls | 1,000 | calls per rolling 24 h per source key (rate_limited beyond it; the window starts at the first call) | supabase/migrations/20261215110000_arp_p1_keys_and_ledger.sql:795 |
grant_proposal_quota | 200 | proposals per UTC calendar date per grant (a quota, not a call limit; the owner may set 1 to 5000) | supabase/migrations/20261215110000_arp_p1_keys_and_ledger.sql:41 |
credential_proposal_quota | 2,000 | proposals per UTC calendar date per owner key or OAuth connection without a grant (a quota, not a call limit) | supabase/migrations/20261216100000_arp_p2_proposals.sql:251 |
proposal_batch_max | 100 | envelopes per propose_ark_records call | supabase/functions/_shared/arp/proposals.ts:PROPOSAL_BATCH_MAX |
proposal_text_max | 200,000 | characters of content.text on the raw and voice lanes | supabase/functions/_shared/arp/proposals.ts:PROPOSAL_TEXT_MAX |
proposal_text_max_typed | 11,782 | characters of content.text on the typed lane (fence markers inside the text count double) | supabase/functions/_shared/arp/proposals.ts:PROPOSAL_TEXT_MAX_TYPED |
proposal_structured_max | 32,768 | bytes of content.structured as JCS, UTF-8 | supabase/functions/_shared/arp/proposals.ts:PROPOSAL_STRUCTURED_MAX_BYTES |
proposal_list_max | 50 | entries in domains, topics or lineage.derived_from | supabase/functions/_shared/arp/proposals.ts:PROPOSAL_LIST_MAX |
proposal_list_entry_max | 200 | characters per entry in those lists | supabase/functions/_shared/arp/proposals.ts:PROPOSAL_LIST_ENTRY_MAX |
status_ids_max | 100 | proposal ids per get_ark_proposal_status call | supabase/functions/_shared/arp/status.ts:STATUS_IDS_MAX |
status_page_max | 100 | proposals per status listing page | supabase/functions/_shared/arp/status.ts:STATUS_LIMIT_MAX |
records_page_max | 100 | records per list_ark_records page | supabase/functions/_shared/arp/gateway.ts:ARP_MCP_TOOLS list_ark_records limit.maximum |
scope_record_cap | 10,000 | records one scope may resolve to (arp_scope_too_large beyond it) | supabase/migrations/20261217100000_arp_p3_scope.sql:681 |
ask_question_max | 4,000 | characters per ask_ark question | supabase/functions/_shared/ark-actions.ts:askArk |
mcp_body_max | 64 | KiB per MCP request body | supabase/functions/ark-mcp/index.ts:68 |
mcp_batch_max | 20 | JSON-RPC messages per MCP batch | supabase/functions/ark-mcp/index.ts:375 |
proposal_expiry | 90 | d after creation a proposal not yet decided expires (expires_at); the expiry job, arp_expire_proposals_v1, is not scheduled yet, so nothing expires today | supabase/migrations/20261216100000_arp_p2_proposals.sql:58 |
rejected_retention | 30 | d after the decision a rejected proposal is removed (by the same unscheduled job) | supabase/migrations/20261216100000_arp_p2_proposals.sql:976 |
expired_retention | 30 | d after expires_at an expired proposal is removed (by the same unscheduled job) | supabase/migrations/20261216100000_arp_p2_proposals.sql:977 |
The call ledgerEarly access
Every answered call on both gateways is recorded as one row in the call ledger, with the credential and the action.
What is billed
- ask_ark is billed to the account behind the credential. An owner key or an OAuth connection bills the ARK owner's wallet in actions, at the owner's rate. A licence credential bills the licensee under the licence quota and overage, crediting the creator. A bounded derivative licence is covered by its allowance: cost_cents 0 and billing_status covered_subscription.
- A proposal is free at intake. When the owner accepts it, it counts as one ingested insight on the owner's plan and its AI is charged in actions at the owner's rate.
- Reading records, the profile, topic search, the schema and the status check are free.
- A source never pays to write. Plans and action prices are on the pricing page.