# Agent identities Source: https://docs.sumvin.com/concepts/agent-identities Every agent you connect gets its own identity under your Sigil, which you can see and disconnect on its own. An agent identity is one connection's own identity under your [Sigil](/concepts/sigil). Every connection gets one: each chat assistant, each coding agent, and the CLI. Two agents acting for you are never the same agent. Each proves it belongs to you, and each can be told apart from the others. ## What it guarantees * **One identity per connection.** Connecting Claude and ChatGPT gives you two agent identities, not one shared one. * **Agents can't see each other.** A connected agent can read its own identity. It can't list or inspect any other agent you have connected. * **Only you can disconnect an agent.** Disconnecting stops that connection being honoured, so the agent can't act for you any more. An agent can't disconnect itself or another agent. * **Disconnecting one leaves the rest alone.** Your other agents, and your Sigil, are unaffected. ## Agents and mandates A [Stamped Mandate](/concepts/stamped-mandates) is what lets an agent act. An agent asks for a mandate and you approve it. Your mandates belong to you, not to the agent that asked, so check what's already in place before you approve a new one. Disconnecting an agent stops it acting, but it doesn't revoke the mandates it asked for. Those stay valid until they expire or you revoke them, so revoke them separately. See [Revoke a mandate or disconnect an agent](/guides/revoke). ## Where an identity can be in its life | State | Means | | - | - | | `pending` | The connection's identity is being set up. | | `active` | Live, and linked to your Sigil. | | `failed` | It couldn't be set up. | | `retired` | Disconnected. It is no longer honoured. | **Coming soon:** a single list of every agent connected to your account, where you can disconnect any of them. Today, you disconnect an agent from that agent's own settings. **Try asking your agent:** "Which agent identity are you using with Sumvin?" ## Next Claude, ChatGPT and the CLI under one Sigil. Remove a mandate or an agent. # Envoy Source: https://docs.sumvin.com/concepts/envoy Envoy is Sumvin's money agent: your agent creates the errand, and Envoy runs it within your Stamped Mandates. **Private preview:** this is rolling out and may not be available on your account yet. Envoy is Sumvin's money agent. Your agent creates the [errand](/concepts/errands); Envoy runs it, inside the limits you grant. Envoy does the legwork: it asks you what it needs to know, then, once you've signed, it searches, compares, checks the merchant, and makes the purchase. ## What Envoy can't do * **Act without a mandate.** Envoy spends only within a [Stamped Mandate](/concepts/stamped-mandates) you signed. * **Sign for you.** You ask, and you sign the errand's bounds before Envoy searches. Until you do, Envoy waits. After that, it searches, checks the merchant, watches for your conditions, and settles within what you signed. * **Go past your limits.** The mandate's ceiling and expiry bind Envoy the same way they bind any agent. You don't need to connect Envoy or talk to it directly. Your own agent creates errands through the connector or the CLI, and Envoy runs them. ## Next What Envoy carries out. The limits it acts within. # Errands Source: https://docs.sumvin.com/concepts/errands An errand is a long-running purchase task that runs under a Stamped Mandate. **Private preview:** this is rolling out and may not be available on your account yet. An errand is a long-running purchase task that runs under a Stamped Mandate. "Reorder my usual coffee beans" is an errand. So is "buy the cheapest direct flight under \$400 to Chicago next month". You ask in your own words, and your agent asks you anything it needs to know. You sign the errand's bounds: the most it may spend, the currency, any conditions, and when the authorisation lapses. Then Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase. Every purchase stays within the [Stamped Mandate](/concepts/stamped-mandates) you signed. ## What an errand guarantees * **Starting an errand spends nothing and searches nothing.** Nothing happens until you sign. Creating an errand doesn't authorise any spending. * **Your agent can't sign for you.** Signing is something you do yourself. * **Once you sign, a match within your bounds is bought without asking you again.** You sign before the search, so there is no second look at the pick. * **Every purchase stays inside the mandate.** An errand can't spend past the ceiling or the expiry of the mandate behind it. * **You can stop it.** Decline it instead of signing, cancel it at any point before it finishes, or revoke the mandate behind it. ## Lifecycle An errand moves through these states. Your agent reports them by name. | Stage | State | Means | | - | - | - | | Working it out | `qualifying` | Your agent is reading your ask. | | Waiting on you | `pending_clarification` | It has a question for you, before you sign. | | | `pending_approval` | Waiting for your signature on the errand's bounds. Nothing has been searched yet. | | Signed and under way | `approved` | You signed. The search is about to start. | | | `searching` | Looking for options within what you signed. | | | `validating` | Checking an option, and the merchant selling it, against what you signed. | | | `monitoring` | Watching for your conditions to be met, such as a price. | | | `executing` | Buying now. | | Finished | `completed` | Settled. Done. | | | `failed` | It couldn't be done. | | | `expired` | Its time ran out, including when you don't sign in time. | | | `cancelled` | Stopped: you cancelled or declined it, or its mandate was revoked. | The four finished states are final. A finished errand never changes again. You can answer questions only while an errand is `qualifying` or `pending_clarification`, before you sign. You can cancel it in any state that isn't finished. Declining at the signature step cancels it: nothing is signed, searched or spent. Revoking a mandate cancels every unfinished errand under it, even one that is mid-search. ## Repeat errands Some things you want done more than once. Every errand already goes ahead without asking you again once you've signed it. A repeat errand goes one step further: one signature covers several matching errands, each within your mandate and the conditions you set. You choose this mode; your agent doesn't choose it for you. ## How errands pay **Coming soon:** payments arrive in a fast-follow release. Sumvin is a [Visa Intelligent Commerce Launch Partner](/concepts/partners), and errands are built on Visa Intelligent Commerce. Payments aren't part of this preview: they arrive in a fast-follow release, with its own waitlist. Signing an errand from the connector arrives with them. Card purchases follow Visa's dispute processes. While payments are in preview, we handle each dispute ourselves, with care, especially if you think your agent got it wrong. Email [hello@sumvin.com](mailto:hello@sumvin.com). See [Trust and safety](/concepts/trust-and-safety). **Try asking your agent:** "Reorder my usual coffee beans." ## Next Ask, sign, then search, check, watch and settle. Let a routine purchase go ahead within your limits. # Glossary Source: https://docs.sumvin.com/concepts/glossary Every public Sumvin term, defined by what it does. ## Terms ### Agent Software that acts for you, such as Claude or ChatGPT. ### Agent identity One connection's own identity under your Sigil. Every connection gets one. You can disconnect each one on its own. See [Agent identities](/concepts/agent-identities). ### Approval page The Sumvin page where you read and sign a Stamped Mandate, including an errand's bounds before it searches. It opens in your own browser, and you sign there with your passkey. Your agent can give you the link; it can't sign there. ### CLI The `sumvin` command-line tool, for developers building and experimenting on Sumvin. The connector is the recommended way to use Sumvin. See [Install the CLI](/get-started/cli/install). ### Coming soon Not available yet, including in this preview. Payments are coming soon, in a fast-follow release. One of the three status labels in these docs. ### Connector Sumvin added to an AI assistant, such as Claude or ChatGPT. The recommended way to use Sumvin. See [Connect your agent](/get-started/connect). ### Counterparty Anyone your agent deals with: a merchant, a service or another agent. A counterparty can check a Stamped Mandate your agent presents. ### Disconnect Stop honouring one agent identity. Your other agents and your Sigil are unaffected. Mandates that agent asked for stay valid until they expire or you revoke them. ### Envoy Sumvin's money agent. Your agent creates an errand; Envoy runs it, inside the limits of your Stamped Mandates. See [Envoy](/concepts/envoy). ### Errand A standing purchase: a long-running purchase task that runs under a Stamped Mandate and goes ahead only when your terms are met. You ask, you sign its bounds, then Sumvin searches, checks the merchant, watches for your conditions, and settles. One pre-authorised mandate can back many errands. See [Errands](/concepts/errands). ### Live Available to everyone. One of the three status labels in these docs. ### Pre-authorised A mode in which one signature covers several matching errands, within its mandate and the conditions you set. The default is to sign each errand's bounds before it searches; a match within them is then bought without asking you again. ### Private preview Rolling out. It may not be available on your account yet. One of the three status labels in these docs. ### Repeat errand An errand you want done more than once, running in pre-authorised mode. See [Repeat errands](/guides/repeat-errands). ### Revoke Permanently withdraw a Stamped Mandate. Anything relying on it stops, including errands using it. ### Sigil Your proof of personhood: a verified identity for you and your agents. Your agents carry it as proof that a real, verified person stands behind them. See [Sigil](/concepts/sigil). ### Stamped Mandate A signed authorisation that says what an agent may do for you: sharing data, proving who it acts for, or spending, each with the limits you set. Sumvin's own object: not an AP2 mandate or a card-network mandate. See [Stamped Mandates](/concepts/stamped-mandates). ### Verification Proving who you are, once: your phone number, then your identity. It is what your Sigil is issued on. See [Verify your identity](/get-started/first/verify). ## Technical note Two renames are underway; the objects are the same. A Stamped Mandate was previously called a PINT (purchase-intent token). The old name still appears in some wire names and SDK types, in the current CLI command group `sumvin pint`, and in two MCP tools, `pint_query` and `pint_revoke`. An Errand was previously called an IPA (Intelligent Purchase Authorization). The old name may still appear in some wire paths and SDK types. # Examples Source: https://docs.sumvin.com/concepts/mandates/examples Worked Stamped Mandates for each use case: what you ask, what the mandate says, and what a verifier sees. Each example starts with what you ask your agent, then shows the mandate written in the [mandate language](/concepts/mandates/language). Hostnames use `example.com`, and identifiers are made up. Only the purchase example can be drafted by an agent today. The others show how the same language expresses use cases that are rolling out. See [Use cases](/concepts/mandates/use-cases) for the status of each. ## Buy within a ceiling Private preview **You ask:** "Buy a pair of running shoes this week, up to $50, but only if they're $45 or less." | Part | Value | | - | - | | Scopes | `sr:us:pint:spend:visa_checkout?max=50.00¤cy=USD` | | Resources | `sr:us:errand:{errand id}` | | Conditions | `sr:us:condition:price_target?op=lte&value=45¤cy=USD` | | Expiry | Seven days from signing | * The ceiling is \$50.00, in dollars, not cents. * The mandate is bound to one errand. It can't pay for anything else. * The condition is signed with the mandate. The purchase proceeds only while the price is at most \$45. The approval page puts the conditions in plain words, such as: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Purchase proceeds only while all of the following hold: - the price is at most 45 USD ``` A verifier sees scopes `sr:us:pint:spend:visa_checkout?max=50.00¤cy=USD`, a ceiling of `50.00` `USD`, and whether the mandate stands. ### A standalone spending limit **You ask:** "Set up a spending limit of \$50 for groceries this week." | Part | Value | | - | - | | Scopes | `sr:us:pint:spend:visa_checkout?max=50.00¤cy=USD` | | Resources | None | | Expiry | Seven days from signing | The approval page reads: "Authorise spending of up to 50.00 USD. This authorisation lapses on" followed by the date and time in UTC. One mandate like this can back several errands; each purchase draws a part of it as a [smaller mandate](/concepts/mandates/limits#narrowing-one-mandate-into-a-smaller-one). ## Share that you are verified Private preview **You ask:** "Tell the wine shop I'm over 18 so I can check out." | Part | Value | | - | - | | Scopes | `sr:us:pint:sigil:age_over_18` | | Audience | `shop.example.com` | | Expiry | One hour from signing | The shop learns one fact: a verified person over 18 stands behind this agent. It learns nothing else about you. To share your verification status instead, the scope is `sr:us:pint:sigil:kyc_status`. Sharing your full verified details with a provider uses `sr:us:pint:sigil:kyc_read`, with `reason` and `requestor` naming why and with whom. It can't be addressed to a website by hostname; the provider must be one Sumvin knows. ## Read a month of transactions Private preview **You ask:** "Look through my September transactions and tell me where my money went." | Part | Value | | - | - | | Scopes | `sr:us:pint:accounts:read`
`sr:us:pint:transactions:read?from_date=1788220800&to_date=1790812800` | | Expiry | One day from signing | * `1788220800` is 1 September 2026, 00:00 UTC, and `1790812800` is 1 October 2026, 00:00 UTC, both in Unix seconds. * The agent can read your linked accounts, and only transactions inside the range. A request for August is refused. * Linking a new account needs `sr:us:pint:accounts:link?provider=meld` as well. ## Prove a person sent the agent Private preview **You ask:** "Book a table for two at the steakhouse on Friday at 8." | Part | Value | | - | - | | Scopes | `sr:us:pint:sigil:proof_of_personhood` | | Audience | `reservations.example.com` | | Expiry | One hour from signing | The booking site receives a mandate addressed to it, in the `x-sumvin-pint-token` header of the agent's request, that says a unique, verified person sent this agent. It checks the mandate on its own server; an online check that it still stands is coming soon. It doesn't learn who you are. The same mandate can't be used at another site, and it can't carry any other kind of scope, such as spending, because it is addressed by hostname. ## Next Ask, read, sign. Read a mandate someone presents. # The mandate language Source: https://docs.sumvin.com/concepts/mandates/language How a Stamped Mandate is written: scopes say what an agent may do, resources say what it is bound to, and parameters and conditions set the limits. A Stamped Mandate is written in a small language of identifiers. Every part of a mandate that says what is allowed is one of these identifiers, so a mandate reads the same to you on the approval page, to your agent, and to whoever checks it. The language is about to be open-sourced, so that others can propose and contribute new use cases. These pages are its public description. ## The parts of a mandate | Part | Written as | Says | | - | - | - | | **Scopes** | One or more scope identifiers | What the agent may do, each with its own limits. At least one is required. | | **Resources** | Zero or more resource identifiers | What the mandate is bound to, such as one errand. | | **Conditions** | Zero or more condition identifiers | Facts that must hold before a purchase goes ahead, such as a price. | | **Audience** | A party identifier or a hostname | Who the mandate is addressed to. | | **Expiry** | A time | When the mandate stops standing. | A mandate grants only what its scopes grant, and only within their parameters, its resources, its conditions and its expiry. Anything not written in it is not permitted. ## Identifiers Every identifier starts with the scheme `sr` and a region, separated by colons: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:{region}:{family}:... ``` The region is `us` for everything Sumvin issues today. The third segment names the family, and each family has its own shape: | Family | Shape | Used for | | - | - | - | | Scope | `sr:us:pint:{domain}:{action}[?{params}]` | What an agent may do. See [Scopes](/concepts/mandates/scopes). | | Mandate | `sr:us:pint:{id}` | One specific mandate. | | Errand | `sr:us:errand:{id}` | One specific errand. | | Person | `sr:us:person:...` | A person's own account. | | Condition | `sr:us:condition:{type}?{params}` | A fact that must hold. See [Resources and conditions](/concepts/mandates/resources#conditions). | Scopes and mandates share a family. A scope has five segments, a domain and an action; a mandate identifier has four, ending in an opaque id. The two are never confused: a five-segment identifier is always a scope, never a thing a mandate is bound to. **On the wire.** The third segment of a scope or mandate identifier is the literal word `pint`. A Stamped Mandate was previously called a PINT, and the identifiers keep that segment. `sr:us:pint:spend:visa_checkout` is a scope; `sr:us:pint:3f9c2a7e5b1d4c8e9a6f0b2d7e4c1a58` is a mandate. ## Scope syntax ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:us:pint:{domain}:{action}?{key}={value}&{key}={value} ``` | Piece | Rules | | - | - | | `domain` | The area the scope covers, such as `sigil`, `spend`, `errand` or `accounts`. | | `action` | What may be done there, such as `read`, `manage`, `search` or `visa_checkout`. | | Parameters | Optional, after a single `?`, as `key=value` pairs joined by `&`. | The rules a scope must pass before anyone can sign it: * **Exactly five segments** before any `?`: `sr`, a region, `pint`, a domain and an action. None may be empty. * **Known name.** The domain and action must be a scope in the [catalogue](/concepts/mandates/scopes). An unknown name is refused, not ignored. * **Declared parameters only.** Each scope declares the parameters it accepts. An undeclared key is refused. * **Required parameters present.** Some scopes can't be signed without certain parameters. `spend:visa_checkout` needs both `max` and `currency`. * **No empty values.** `max=` is refused. * **Values of the right type.** See the table below. ## Parameter types | Type | Written as | Example | | - | - | - | | Amount | A plain decimal number in the display unit of the currency or asset the scope names. No exponent, no spaces, ASCII digits only. | `max=25.50` | | Integer | ASCII digits. | `time=604800` | | Timestamp | Unix time in seconds, as an integer. | `from_date=1788220800` | | Currency | An ISO 4217 code. | `currency=USD` | | Provider | Lowercase letters, digits and `_`, from the scope's own list. | `provider=meld` | | Text | Free text, or one of a fixed list where the scope declares one. | `doc_type=passport` | Amounts are covered in full in [Limits and narrowing](/concepts/mandates/limits#spending-ceilings). Numbers are read only from ASCII digits. A digit from another script is refused, so a number in a signed mandate reads the same to every person and every program. ## How the parts combine * **Scopes add up.** A mandate with two scopes grants both, and each scope keeps its own limits. `accounts:read` plus `transactions:read?from_date=…` lets an agent read your accounts, and your transactions only in that range. * **Parameters narrow a scope.** A scope with no parameters grants its whole action. Each parameter you add can only take something away. * **Resources and conditions narrow the whole mandate.** A mandate bound to one errand can be used for that errand only. A mandate with conditions can't complete a purchase until all of them hold. * **One spending limit per mandate.** A spending mandate carries exactly one scope that states a ceiling. * **What you sign is what is checked.** Scopes, resources and conditions are signed exactly as written: in the same order, with nothing removed, merged or reordered. When your agent drafts a spending mandate, its scopes are sorted and duplicates removed once, before you see the approval page, so the page shows the form you sign. * **Additive to the service's own rules.** A mandate restricts what an agent may do. It never lifts a check the service already makes, such as requiring you to be verified. ## Older names Some scopes were renamed. The older names are still accepted in mandates signed before the rename, and they mean exactly the same as the new ones. Use the new names. | Older name | Current name | | - | - | | `sr:us:pint:perpetual:search` | `sr:us:pint:errand:search` | | `sr:us:pint:identity:kyc_status` | `sr:us:pint:sigil:kyc_status` | | `sr:us:pint:identity:kyc_read` | `sr:us:pint:sigil:kyc_read` | | `sr:us:pint:identity:proof_of_personhood` | `sr:us:pint:sigil:proof_of_personhood` | | `sr:us:pint:identity:age_over_18` | `sr:us:pint:sigil:age_over_18` | ## Next Every scope family and what it grants. What a mandate is bound to, and what must hold. Ceilings, units, expiry, and why a mandate only narrows. The answer a counterparty gets. # Limits and narrowing Source: https://docs.sumvin.com/concepts/mandates/limits How a Stamped Mandate states spending ceilings, time limits and expiry, and why a mandate can only ever be narrowed. A mandate's limits live in two places: parameters on its scopes, and the mandate's own expiry. Both are signed. Neither can be raised after you sign. ## Spending ceilings A spending ceiling is the `max` parameter on a spend scope. It is the most the mandate can ever authorise. **`max` is an amount in the display unit of the currency or asset the scope names.** It is written the way you would read it on a receipt, never in cents, pence or other minor units. | Written | Means | | - | - | | `max=25¤cy=USD` | 25.00 US dollars | | `max=25.00¤cy=USD` | 25.00 US dollars | | `max=25.50¤cy=USD` | 25.50 US dollars | | `max=2500¤cy=JPY` | 2,500 yen | Rules for a ceiling: * **Fractions are allowed** up to the currency's own precision: two places for USD and EUR, none for JPY, three for KWD. * **Too precise is refused.** `max=25.001¤cy=USD` is refused, never rounded or cut down. Rounding either way would sign a different number from the one you read. * **Positive only.** A draft with a ceiling of zero or less is refused before you are asked to sign it. * **Exactly one.** A spending mandate states exactly one ceiling. A draft with none, or with two, is refused. A [read mandate](/concepts/mandates/scopes#read-mandates) spends nothing and states no ceiling. * **Written one way.** When Sumvin writes a ceiling itself, it uses exactly the currency's precision: 25 US dollars is written `max=25.00`, and 2,500 yen is written `max=2500`. The approval page shows the ceiling in plain words at the currency's own precision, such as "Authorise spending of up to 25.00 USD." Anything that reports a ceiling back to you or to a verifier reports it in the same display unit, such as `12.50`, never `1250`. A ceiling that can't be read back is reported as unreadable, never as unlimited. ## Time limits | Limit | Where | Unit | | - | - | - | | Expiry | The mandate itself | A point in time. After it, the mandate no longer stands. | | Search window | `time` on `errand:search` | A length of time, in **seconds**. `604800` is seven days. | | Date range | `from_date`, `to_date` on `transactions:read` | Points in time, in Unix **seconds**. | | Purchase window | `not_before`, `not_after` on a `time_window` condition | Points in time, in Unix **milliseconds**. | An expiry must be in the future when the mandate is made. A search window is also capped by Sumvin's own upper limit, and the shorter of the two applies. ### How long a mandate lasts When your agent asks you for a mandate directly, two clocks start: * **The time to answer.** You have 24 hours to sign or decline. If the request lapses unanswered, nothing is granted. * **The mandate's own expiry.** Once you sign, the mandate lasts 90 days by default. Your agent may ask for any length from 1 to 90 days. The approval page shows the date it lapses before you sign. A mandate can't be extended. In the last 7 days before a read mandate lapses, your agent is told so and can offer to ask you for a new one. Renewing means signing a new mandate; until you do, the old one keeps working to its expiry. ## A mandate only narrows A mandate can never grant more than what you signed. Every rule below takes authority away; none adds it. * **Your agent can't widen a mandate.** More authority always means a new mandate that you sign. * **Each parameter narrows its scope.** A ceiling, a currency, a card, a date range, a provider: each one limits what the scope allows. * **Resources and conditions narrow the whole mandate.** * **Revocation and expiry end it.** Neither can be undone. ### Narrowing one mandate into a smaller one A mandate can be narrowed into a smaller one, for example so that one purchase draws a part of a larger spending mandate. The smaller mandate: * names the larger one in its [resources](/concepts/mandates/resources); * has a ceiling at or below the larger one's; * keeps the same currency, and the same pinned card if there is one; * can't expire later than the larger one; * stops standing the moment the larger one is revoked or expires. A smaller mandate that breaks any of these rules is refused. When you revoke a mandate, every smaller mandate drawn from it that is still in use is revoked with it. ## Next How a counterparty reads these limits. Choose the limits for your agent. # Resources and conditions Source: https://docs.sumvin.com/concepts/mandates/resources What a Stamped Mandate is bound to, who it is addressed to, and the conditions that must hold before a purchase goes ahead. Scopes say what an agent may do. Resources say what the mandate is bound to, the audience says who it is for, and conditions say what must be true first. ## Resources A resource is an identifier for one specific thing. A mandate with resources applies to those things only. A mandate with none is bound to nothing beyond its scopes. | Resource | Shape | Binds the mandate to | | - | - | - | | Errand | `sr:us:errand:{id}` | One errand. The mandate can be used for that errand's purchase and no other. | | Mandate | `sr:us:pint:{id}` | Another mandate. A smaller mandate drawn from a larger one names the larger one here. See [Narrowing](/concepts/mandates/limits#a-mandate-only-narrows). | | Person | `sr:us:person:...` | Your own account. | Resource rules: * Each resource must be a well-formed identifier of a known family. Anything else is refused. * A resource identifier takes no parameters. A `?` in a resource is refused. * A scope name is never a resource. `sr:us:pint:spend:visa_checkout` in the resources is refused. * A condition is never a resource. Conditions have their own place in the mandate. * Resources are signed exactly as written: the same order, nothing removed or merged. ## Audience Every mandate is addressed to one party. A mandate addressed to one party is not valid for another. | Addressed to | Written as | | - | - | | Your own account | Your account's identifier. This is what a mandate is addressed to when no one else is named. | | A service Sumvin knows | That service's identifier. | | Any website | Its bare hostname, in lowercase, such as `reservations.example.com`. | A hostname must be exactly that: lowercase letters, digits, hyphens and dots, with no scheme, port, path or `@`. `https://reservations.example.com/` and `Reservations.example.com` are refused, not tidied up, because two spellings of one site could be read as two different sites. Naming a website grants it nothing on its own. A mandate addressed to a website by hostname may carry only these scopes: * `sr:us:pint:sigil:kyc_status` * `sr:us:pint:sigil:proof_of_personhood` * `sr:us:pint:sigil:age_over_18` Anything else, such as spending or reading your data, must be addressed to a party Sumvin knows. ## Conditions A condition is a fact that must hold before a purchase can go ahead without asking you again. Conditions apply to purchases only. Every condition on a mandate must hold: they combine with AND. There is no OR, and no nesting. ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:us:condition:{type}?{key}={value}&{key}={value} ``` Every condition takes at least one parameter. Each key may appear once, and no value may be empty. | Type | Holds when | Parameters | | - | - | - | | `price_target` | The best price compares to a target as stated. | `op`, `value`, `currency` (all required) | | `budget_cap` | The basket total is at most a figure. | `max`, `currency` (both required) | | `availability` | The offer has one of the listed availability states. | `statuses` (required, comma-separated, such as `in_stock,pre_order`) | | `time_window` | The purchase happens inside a window. | `not_before`, `not_after` (at least one; Unix time in **milliseconds**) | | `flight_route` | The flight runs between two airports. | `origin`, `destination` (required, IATA codes), `max_stops` (optional; `0` means direct only) | | `coverage_minimum` | Coverage is at least a percentage. | `min_pct` (required, 0 to 100) | | `jurisdiction` | The seller is in one of the listed countries. | `allowed` (required, comma-separated ISO 3166-1 alpha-2 codes) | `op` on `price_target` is one of: | `op` | Means | | - | - | | `lte` | At most the target | | `gte` | At least the target | | `lt` | Below the target | | `gt` | Above the target | | `eq` | Exactly the target | Amounts in conditions are written as plain decimals with no trailing zeros, such as `value=180` or `value=179.5`. Every condition appears in plain words on the page where you approve the mandate. A condition that can't be described in plain words can't be signed. ```text Example theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:us:condition:price_target?op=lte&value=180¤cy=USD sr:us:condition:jurisdiction?allowed=GB,IE ``` Reads as: "the price is at most 180 USD" and "the seller is in GB, IE". ## Next Ceilings, units and expiry. Resources and conditions in a full mandate. # Scopes Source: https://docs.sumvin.com/concepts/mandates/scopes Every Stamped Mandate scope family, what each scope grants, and the parameters it takes. A scope says one thing an agent may do. Each scope belongs to a family, named by its domain. This page lists the families and what every scope in them grants. **Needs a verified Sigil** means the scope can only be used for a person who has completed [verification](/get-started/first/verify). A mandate carrying it does nothing for an unverified account. Parameters are written as described in [The mandate language](/concepts/mandates/language#parameter-types). A parameter marked *required* must be present for the scope to be signed at all. ## Sigil: facts about you Attestations about the verified person behind the agent, and one read of the agent's own identity. | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:sigil:kyc_status` | Attests your current identity verification status. | None | Yes | | `sr:us:pint:sigil:proof_of_personhood` | Attests that you are a unique, verified person. | None | Yes | | `sr:us:pint:sigil:age_over_18` | Attests that you are 18 or older. | None | Yes | | `sr:us:pint:sigil:kyc_read` | Reads your verified identity details and documents. | `doc_type`, `reason`, `requestor` (all optional) | Yes | | `sr:us:pint:sigil:agent_read` | Reads the identity of the connected agent making the request, and whether it is linked to your Sigil. Reads no financial data and can't see your other agents. | None | No | `kyc_read` parameters: * `doc_type`: limit the read to one kind of document, such as `passport` or `id_card`. * `reason`: why the details are shared. One of a fixed list. * `requestor`: the provider that receives them. One of a fixed list. Sharing your details with a provider needs a `kyc_read` scope that carries **both** `reason` and `requestor`. The lists grow as providers are added. The three attestations (`kyc_status`, `proof_of_personhood`, `age_over_18`) are the only scopes a mandate may carry when it is addressed to a website by its hostname. See [Resources and conditions](/concepts/mandates/resources#audience). ## Spend: paying for things Purchases, which run as [errands](/concepts/errands). | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:spend:visa_checkout` | Card checkout through Visa Intelligent Commerce, up to a ceiling. | `max` (required), `currency` (required) | Yes | | `sr:us:pint:spend:card` | Pins a checkout to one of your enrolled cards. Without it, the card is chosen when the purchase is made. | `id` (required): the card's id | Yes | `max` on `spend:visa_checkout` is the most one checkout may charge, in the display unit of `currency`. See [Spending ceilings](/concepts/mandates/limits#spending-ceilings). ## Errand: purchase tasks Starting, reading and managing [errands](/concepts/errands). | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:errand:search` | Start an errand: a long-running search for something to buy. | `time` (required), `max` | Yes | | `sr:us:pint:errand:triage` | Start an errand from a suggestion you accepted. | None | Yes | | `sr:us:pint:errand:task` | Start an errand from a task you gave an assistant. | None | Yes | | `sr:us:pint:errand:insights` | Start an errand from a generated suggestion. | None | Yes | | `sr:us:pint:errand:read` | Read your errands, their details and their history. | None | No | | `sr:us:pint:errand:manage` | Answer an errand's questions, decide on it, or cancel it. | None | No | `errand:search` parameters: * `time`: how long the errand may keep searching, in seconds. `604800` is seven days. Sumvin also applies its own upper limit, and the shorter of the two wins. * `max`: an optional purchase ceiling. It is **not enforced**, because this scope names no currency to measure it in. Put the ceiling that counts on `spend:visa_checkout`. Starting an errand spends nothing. Paying needs a `spend` scope as well. ## Accounts and transactions: open-banking data Linking accounts and reading their data through [Meld](/concepts/partners). | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:accounts:link` | Link your accounts through an open-banking provider. | `provider` (optional): `meld` | No | | `sr:us:pint:accounts:read` | Read your linked accounts and balances. | None | No | | `sr:us:pint:transactions:read` | Read your transaction history, details and receipts. | `from_date`, `to_date` (optional, Unix seconds) | No | With `from_date` or `to_date`, the agent can ask only for transactions inside that range. A request reaching outside it is refused. ## Proofs: facts about your money Proving something about your money to someone else without showing them the figures. | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:proofs:balance` | Proves your balance is at least an amount, without disclosing the balance itself. | `min` (required), `currency` (required), `timing` (optional) | Yes | `proofs:balance` parameters: * `min`: the amount being proven, in the display unit of `currency`. It follows the same rules as a spending ceiling: fractions up to the currency's precision, positive only. See [Spending ceilings](/concepts/mandates/limits#spending-ceilings). * `currency`: the ISO 4217 code the amount is stated in, such as `USD`. * `timing`: when the balance is checked. `live` checks it each time a proof is made, and is the default. `snapshot` checks the most recent balance on record. `frozen` checks it once and holds the answer for the life of the mandate. ## Read mandates An agent asking you directly for a mandate asks for one of two kinds: * **Spend**: the spend scopes above, with exactly one spending ceiling. * **Read**: any of `accounts:read`, `transactions:read` and `proofs:balance`. A read mandate spends nothing and carries no ceiling. A request mixing the two kinds is refused. To grant both, sign two mandates. See [Time limits](/concepts/mandates/limits#time-limits) for how long each lasts. ## Mandates: asking for and checking mandates | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:mandates:propose` | Draft a mandate and put it to you to sign. Drafting grants nothing until you sign. | None | No | | `sr:us:pint:mandates:read` | Read the mandates you have been asked to sign, and where each request has got to. | None | No | | `sr:us:pint:mandates:verify` | Check a mandate somebody else presents: what it permits, up to how much, and whether it still stands. Reads nothing about the person who signed it. | None | No | | `sr:us:pint:pints:read` | Read the mandates you have signed, including what each one permits. | None | No | | `sr:us:pint:pints:revoke` | Revoke a mandate you have signed. Revocation is permanent. | None | No | `mandates:read` covers only your own requests. Checking a mandate that belongs to someone else always needs `mandates:verify`. ## Onboarding: setting up your account | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:onboarding:read` | Read how far you have got in setting up your account, and the state of your Sigil. | None | No | | `sr:us:pint:onboarding:verify` | Start identity verification and hand back a link for you to complete it. | None | No | ## Your account Reading what your Sumvin account holds. Your linked accounts and transactions are covered by the accounts and transactions family above. | Scope | Grants | Parameters | Needs a verified Sigil | | - | - | - | :-: | | `sr:us:pint:assets:read` | Read the assets you hold, with balances and prices. | None | No | | `sr:us:pint:wallets:read` | Read your wallets, including addresses, networks and nicknames. | None | No | ## Not listed here The catalogue also holds scopes for products these docs don't cover, and a few reserved names with nothing behind them yet. A mandate naming a scope that is not in the catalogue at all is refused. ## Next What a mandate is bound to. Scopes put together for each use case. # Use cases Source: https://docs.sumvin.com/concepts/mandates/use-cases What Stamped Mandates are for: sharing data, reading open-banking data, proving a person sent an agent, purchases, and the uses coming next. A Stamped Mandate can express any authorisation that fits its [language](/concepts/mandates/language): what an agent may do, on what, within what limits, for whom and until when. The first four use cases on this page are the ones Sumvin supports or is rolling out. The ones under [More use cases](#more-use-cases) follow. They are examples, not a complete list. Today an agent can ask you to sign a **spending** mandate. The payments it authorises are coming soon. The other use cases are rolling out, and each is labelled below. ## Share your data Private preview Let an agent tell a merchant or provider something true about you, and nothing more. The mandate names exactly what is shared and with whom. * **That you are verified.** The merchant learns your identity verification status. It doesn't learn your name or documents. * **That you are over 18.** The merchant learns that one fact. * **Your verified identity details.** For a provider that has to hold them, such as one that would otherwise ask you to verify again. You sign for this separately, and the mandate says why the details are shared and who receives them. Identity verification is carried out by [Sumsub](/concepts/partners). ```text Scopes theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:us:pint:sigil:kyc_status sr:us:pint:sigil:age_over_18 sr:us:pint:sigil:kyc_read?doc_type=passport ``` See [Examples](/concepts/mandates/examples#share-that-you-are-verified). ## Read open-banking data Private preview Let an agent link your accounts through [Meld](https://www.meld.io) and read your balances and transactions, limited to a date range if you want. Writing through Meld, such as initiating a transfer, is planned and not available yet. ```text Scopes theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:us:pint:accounts:link?provider=meld sr:us:pint:accounts:read sr:us:pint:transactions:read?from_date=1788220800&to_date=1790812800 ``` See [Examples](/concepts/mandates/examples#read-a-month-of-transactions). ## Prove a person sent the agent Private preview Sites that take bookings, reservations and tickets block automated traffic to stop abuse. As more people send agents to do these jobs, a site can't tell a person's agent from a bot farm, and one blanket ID per AI assistant would not tell it which person is behind a given request. A mandate lets the request say it directly: a verified person asked this agent to come here. Your agent presents a mandate that carries proof of personhood and is addressed to that site by its hostname. It travels with the agent's request, in the `x-sumvin-pint-token` header. The site checks, on its own server, that a real, verified person approved it and that it is addressed to that site. It doesn't learn who you are. An online check that it still stands is coming soon. "Book a steakhouse for dinner on Friday" becomes a request the restaurant's booking system can check, rather than one it has to guess about. ```text Scope, addressed to a site theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:us:pint:sigil:proof_of_personhood → reservations.example.com ``` See [Examples](/concepts/mandates/examples#prove-a-person-sent-the-agent). ## Make purchases Coming soon **Coming soon:** payments arrive in a fast-follow release. Let an agent buy something within a ceiling you set, in a currency you name, until an expiry. Purchases run as [errands](/concepts/errands). Sumvin is a [Visa Intelligent Commerce Launch Partner](/concepts/partners), and errands are built on Visa Intelligent Commerce. Payments aren't part of this preview: they arrive in a fast-follow release, with its own waitlist. You can add conditions, such as a target price, that must hold before the purchase goes ahead. ```text Scopes theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sr:us:pint:spend:visa_checkout?max=50.00¤cy=USD sr:us:pint:errand:search?time=604800 ``` See [Examples](/concepts/mandates/examples#buy-within-a-ceiling). ## More use cases The same language covers more than the four above. Each use case below is labelled with where it stands. ### Prove your age or eligibility Private preview Let an agent show a site that you meet a requirement, such as being over 18, without handing over your date of birth or your documents. The site learns the one fact it needs, and that a verified person stands behind it. ### Reuse your verification to open an account Private preview Opening an account with a provider usually means verifying your identity again. A mandate lets you share the verification you have already completed with that provider, for that purpose, so you don't repeat it. You sign for each provider separately, and the mandate says who receives your details and why. ### Manage subscriptions Coming soon Let an agent look after your subscriptions: start one within limits you set, keep track of renewals, and cancel one when you ask. The mandate sets which services it may act on, how much it may commit you to, and until when. ### Pass a narrower mandate to another agent Coming soon An agent can hand a narrower mandate to another agent. The second agent can do less than the first, never more, and everything still traces back to what you signed. ### Refunds and support requests Coming soon Let an agent ask a merchant for a refund or raise a support request for you. The mandate shows the merchant that you sent the agent and what it may ask for, so the request can be handled without you repeating yourself. ### Better treatment for verified agents Coming soon A site can choose to treat an agent that carries a mandate differently from anonymous automated traffic, for example by letting it through where it would otherwise be blocked, or by offering it the same terms a signed-in customer gets. The site decides what it offers; the mandate gives it something it can check. ### Share trip details for one journey Coming soon Let an agent share the details a trip needs, such as traveller names or loyalty numbers, with the airline, hotel or booking site handling that journey, and nobody else. The mandate limits what is shared, with whom, and for how long. ### Spending mandates for a business Coming soon Let a business give its agents spending authority with the same controls a person has: a ceiling, a currency, the kinds of purchase allowed, and an expiry. Each agent's authority stays within what the business signed. ## A language others can extend The scopes and resources on these pages form a small, open language. It will be open-sourced soon, so that others can propose and contribute new use cases. ## Next How a mandate is written. A worked mandate for each use case. # What a verifier checks Source: https://docs.sumvin.com/concepts/mandates/verification What a merchant, service or site learns when it checks a Stamped Mandate an agent presents, and which answer to act on. A verifier is anyone an agent presents a Stamped Mandate to: a merchant, a service, a site, or another agent. A mandate identifier on its own proves nothing, and a mandate can be revoked at any moment after it was signed. So a verifier checks it before acting on it. ## How an agent presents a mandate An agent presents a Stamped Mandate to a site as a token issued by Sumvin, in the `x-sumvin-pint-token` request header: ```http theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} x-sumvin-pint-token: ``` The token is addressed to the site's hostname. The site checks it on its own server, offline, against Sumvin's published keys, and accepts only a token addressed to itself. How to run that check is in the [verifier quickstart](/sdk/verify/quickstart). An online check for these tokens, which would also catch a mandate revoked since it was signed, is coming soon. A mandate can also be looked up by its identifier, such as `sr:us:pint:3f9c2a7e5b1d4c8e9a6f0b2d7e4c1a58`. How to run that check is in [Check a mandate](/guides/check-a-mandate). ## What the check answers | Answer | Means | | - | - | | **Recognised** | Whether Sumvin knows a mandate with this identifier. An unknown identifier is an answer, not an error: act on nothing. | | **Stands** | Whether the mandate permits anything right now. **This is the answer to act on.** | | **Status** | Where the mandate has got to. See the states below. | | **Scopes** | What it permits, as the [scope identifiers](/concepts/mandates/scopes) it was signed with, each with its own limits. | | **Ceiling** | The most it would ever authorise, as an amount in display units and what that amount is counted in, such as `25.00` and `USD`. | | **Signed by the account holder** | Whether the person signed this mandate themselves, or it was narrowed from one they signed. | | **Signed at, expires at** | When it was signed and when it stops standing. | | **Narrowing depth** | How many larger mandates this one was narrowed from. Zero is the ordinary case. | ### Stands, not status A mandate **stands** only when all of these are true: * its status is `active`; * it has not passed its expiry; * every larger mandate it was narrowed from is itself still intact. A mandate can read `active` while a larger mandate above it has been revoked. It no longer permits anything. Only **stands** accounts for that. ### Ceiling The ceiling is stated the way a person reads it: `12.50`, never `1250`. If the ceiling can no longer be read back out of the mandate's scopes, it is reported as missing. Treat a missing ceiling as unverifiable, never as unlimited. ### States | State | Means | | - | - | | `pending` | Prepared but not yet signed. Permits nothing. | | `active` | Signed and usable. | | `consumed` | Already spent against. | | `revoked` | Withdrawn by the person. | | `expired` | Its time ran out. | Only `active` can permit anything, and none of the last three ever becomes `active` again. ## What a verifier never learns * **Who the person is.** No name, email or other contact details. * **Anything above the mandate it was shown.** The narrowing depth is a count, not a list. The larger mandates each permit more than the one presented, so their identifiers are never returned. Checking a mandate grants nothing and changes nothing. It is a read. ## Next Run the check. What a verifier sees for each use case. # Partners Source: https://docs.sumvin.com/concepts/partners The partners behind Sumvin: Visa Intelligent Commerce for errand payments, Sumsub for identity verification, and Meld for open-banking data access. Sumvin works with partners for the parts of the story that belong to them. **Errand payments.** Sumvin is a Visa Intelligent Commerce Launch Partner, and errands are built on Visa Intelligent Commerce. Payments aren't part of this preview; they arrive in a fast-follow release. **Identity verification.** When you verify your identity, Sumsub runs the check, and your documents stay with Sumsub. **Open-banking data access.** Meld links your accounts, so an agent you give a Stamped Mandate to can read your balances and transactions. **Coming soon:** payments arrive in a fast-follow release. ## Next How errand payments will work. What stays with Sumsub. # Privacy Source: https://docs.sumvin.com/concepts/privacy What Sumvin holds about you, what your agent sees, and what anyone your agent deals with sees. A Sigil proves that a verified person stands behind an agent. It doesn't hand that person's details to everyone the agent meets. ## What we hold | We hold | We don't hold | | - | - | | Your email and phone number. | Copies of your identity documents or your selfie. They stay with [Sumsub](/concepts/partners), our identity verification partner. | | Your name and date of birth, as read from your document. | Your passwords. We never see or handle them. | | The result of your verification, and when it happened. | | | A reference to your verification record at Sumsub. | | | Your agents, the mandates you have signed, and your errands and their history. | | How Sumsub handles and keeps your documents and selfie is set out in Sumsub's own [privacy notice](https://sumsub.com/privacy-notice-service/). ## What your agent sees Your agent sees what its tools return, and only for your account: * whether you are verified, and your next step if you aren't; * your Sigil, and its own agent identity; * the mandates it asked for, and the errands it runs; * the account information you agreed to share when you connected it. Your agent doesn't see your identity documents. It can't see your other agents. ## What a counterparty sees When your agent presents a Stamped Mandate to a merchant, a service or another agent, they can learn: * what the mandate permits, and any amount it allows; * whether you signed it; * whether it still stands. They don't learn your name or your email from it. ## Next The guarantees behind every mandate. What a counterparty does with one. # Sigil Source: https://docs.sumvin.com/concepts/sigil A Sigil is your verified identity, which every agent you connect carries as proof that a real person stands behind it. A Sigil is your verified identity. Your agents carry it as proof that a real, verified person stands behind them. An agent on its own can't prove who it acts for. A Sigil answers that question once, for every agent you connect. ## What it guarantees * **A person verified once.** You get a Sigil after you verify your identity. You don't verify again for each agent. * **Agents you can tell apart.** Every agent you connect has its own [agent identity](/concepts/agent-identities) under your Sigil. Each one proves it belongs to you, and each one stays distinguishable from the others. * **Yours.** A Sigil belongs to one person. An agent can present it; it can't create one, transfer one, or verify on your behalf. ## What you do with it You don't use a Sigil directly. It is what the rest of Sumvin stands on: 1. You [verify your identity](/get-started/first/verify), and your Sigil is issued. 2. You connect agents. Each gets an [agent identity](/concepts/agent-identities) linked to your Sigil. 3. You sign [Stamped Mandates](/concepts/stamped-mandates) that say what your agents may do. 4. Your agents run [errands](/concepts/errands) within those mandates. A new account can be fully verified and not have a Sigil yet. Issuance is rolling out, and your agent will tell you where it has got to. **Try asking your agent:** "Show me my Sigil." ## Next Verify once and see your Sigil. One identity per connection, under your Sigil. # Stamped Mandates Source: https://docs.sumvin.com/concepts/stamped-mandates A Stamped Mandate is a signed authorisation that says what one agent may do for you, on what, within what limits and until when. A Stamped Mandate is the authority an agent presents to prove it may act for you. It is not only for spending. The same framework covers sharing your data, proving you are a real person, reading financial data through a provider, and paying for things. You sign every mandate yourself. Your agent can ask for one; it can't sign one. A Stamped Mandate is Sumvin's own object. It is not an AP2 mandate or a card-network mandate, and it doesn't claim to work with them. ## Three layers ```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} flowchart LR S["Sigil
who you are"] --> M["Stamped Mandate
what an agent may do"] M --> E["Errand
a purchase task"] ``` | Layer | Answers | Page | | - | - | - | | **Sigil** | Is a real, verified person behind this agent? | [Sigil](/concepts/sigil) | | **Stamped Mandate** | What may this agent do for them, and within what limits? | This page | | **Errand** | Which purchase is this agent carrying out right now? | [Errands](/concepts/errands) | A Sigil is identity. It never authorises anything on its own. A mandate is the authorisation. An errand is one kind of work that runs under a mandate: a purchase. ## What a mandate says | Part | What it says | | - | - | | **What** | The actions it permits, written as [scopes](/concepts/mandates/scopes), such as "check out by card" or "prove this person is verified". | | **On what** | The things it is bound to, written as [resources](/concepts/mandates/resources), such as one errand. | | **Limits** | Parameters on each scope, such as a spending ceiling, a currency or a date range, plus any conditions you set. See [Limits and narrowing](/concepts/mandates/limits). | | **For whom** | The party it is addressed to: a service Sumvin knows, or a website named by its hostname. | | **Until when** | An expiry. After it, the mandate no longer stands. | Three properties hold for every mandate: * **Signed by you, on your own page.** You read what the mandate says in plain words on a Sumvin page in your own browser, then approve it with your passkey or decline. * **Revocable.** You can withdraw it at any time. Revocation is permanent. * **Checkable.** Whoever your agent deals with can check what it permits and whether it still stands, without learning who you are. See [What a verifier checks](/concepts/mandates/verification). ## What mandates are for The use cases below are examples, not a complete list. See [Use cases](/concepts/mandates/use-cases) for each one in detail. Share that you are verified, or share verified identity details, with a merchant or provider. Let an agent read your linked accounts and transactions through Meld. Show a booking site that a verified person sent this agent. Let an agent buy within a ceiling you set. Purchases run as errands. ## How a mandate is made 1. **Your agent asks.** It drafts the mandate and gives you a link to a Sumvin page. 2. **You read it.** The page shows what you would be signing, in plain words, including any ceiling in your own money's terms. 3. **You sign, or you don't.** Only you can approve it, with your passkey, in your own browser. An agent can ask for a mandate; it can't approve one, for itself or any other agent. A request ends in one of four states: | State | Means | | - | - | | `proposed` | Waiting on you. Nothing is authorised yet. | | `stamped` | You signed. The mandate now stands. | | `declined` | Refused, or withdrawn before you answered. Nothing was granted. | | `expired` | The request lapsed unanswered. Nothing was granted. | The approval link is given to your agent once. If it is lost, your agent asks again rather than looking it up. ## Two modes for purchases **Sign each errand.** This is the default. You ask, and you sign the errand's bounds before anything is searched: the item, the most it may spend, any conditions, and when your authorisation lapses. Then Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase. A match found within your bounds is bought without asking you again. **Pre-authorised.** One signature covers several matching errands, so each one doesn't wait for a new signature, as long as it stays within your mandate and any conditions you set, such as a price. This is what makes [repeat errands](/guides/repeat-errands) possible. Your agent only chooses it when you have clearly asked for it. Either way, the mandate is the outer limit. A pre-authorised errand can't spend past its ceiling or its expiry. ## Revoking You can revoke a Stamped Mandate at any time. A revoked mandate never becomes active again. Anything relying on it stops, including errands that were using it and any smaller mandate drawn from it. To give the authority back, sign a new mandate. Disconnecting an agent is separate from revoking the mandates it asked for. A disconnected agent can't act for you, but the mandates it asked for stay valid until they expire or you revoke them. Revoke them separately. See [Revoke a mandate or disconnect an agent](/guides/revoke). **Try asking your agent:** "Set up a spending limit of \$50 for groceries this week." ## Next How scopes, resources and limits fit together. Ask, read, sign. Amount, merchant, expiry. For anyone an agent presents one to. # Trust and safety Source: https://docs.sumvin.com/concepts/trust-and-safety The guarantees Sumvin makes when your agent acts for you, and what happens if something goes wrong. Your agent acts for you only in ways you have agreed to, and you can stop it at any time. These are the guarantees behind that. ## The guarantees Every [Sigil](/concepts/sigil) starts with a real person verifying their identity. Agents inherit that proof; they never provide it. Your agent can ask for a [Stamped Mandate](/concepts/stamped-mandates). Only you can approve one, with your passkey, on a Sumvin page in your own browser. A connected agent's access can't be used to approve. This holds even if other people can message your agent, as with a shared OpenClaw: they can ask for a mandate, but they can't approve one without your passkey. An agent can't approve its own mandate, widen one, or approve a purchase for itself. More authority always means a new mandate that you sign. An agent gets only what you agreed to when you connected it. It can't see your other agents, and a mandate caps what it can do, what on, and until when. Revoke a mandate and everything relying on it stops, including errands using it. Disconnect an agent and that connection is no longer honoured; mandates it asked for stay valid until they expire or you revoke them. Neither needs the agent's cooperation. You can see the mandates you have signed, every errand's history, and where each one stands. Anyone your agent presents a mandate to can check that you signed it and that it still stands. **These guarantees are the connector's. The CLI is different.** The CLI is mainly for developers and people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). The CLI runs on your own machine and signs with a key stored there. An agent running in your terminal can reach whatever you can reach, including approving Stamped Mandates the CLI signs for you. `--yes` skips the prompt that would have stopped to ask you. Approve things yourself, and never give an unattended agent `--yes`. ## If something goes wrong * **Your agent asks for something you didn't expect.** Decline it. Nothing is granted until you sign. * **A mandate is broader than you want.** Revoke it and sign a narrower one. * **An agent is misbehaving, or you've stopped using it.** Disconnect it, then revoke the mandates it asked for. Your other agents are unaffected. * **A card purchase is wrong.** Payments are [coming soon](/reference/status-labels). Card purchases follow Visa's dispute processes. While payments are in preview, we handle each dispute ourselves, with care, especially if you think your agent got it wrong. Email [hello@sumvin.com](mailto:hello@sumvin.com). * **Anything else.** Email [hello@sumvin.com](mailto:hello@sumvin.com). ## Next Stop a mandate or an agent. What we hold, and who sees what. # Install the CLI Source: https://docs.sumvin.com/get-started/cli/install Install the sumvin command-line tool for your platform. **Private preview:** this is rolling out and may not be available on your account yet. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. The `sumvin` command-line tool gives your terminal the same capabilities as the connector: sign in, verify your identity, and manage Stamped Mandates and errands without leaving a shell. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} brew install sumvin/tap/sumvin ``` ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} npx sumvin login ``` Or with bun: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} bunx sumvin login ``` Either name works. `sumvin` is a thin alias for the `@sumvin/cli` package, so `npx @sumvin/cli login` runs the same thing. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} curl -fsSL https://get.sumvin.com/install.sh | sh ``` Installs to a directory on your `PATH` and needs neither Node nor Bun. Pin a version with an environment variable: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} SUMVIN_VERSION=v0.1.0 curl -fsSL https://get.sumvin.com/install.sh | sh ``` Download the binary for your platform from [Sumvin/cli-releases](https://github.com/Sumvin/cli-releases), check it against `SHA256SUMS` from the same release, then move it onto your `PATH`. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} chmod +x sumvin mv sumvin /usr/local/bin/sumvin ``` Supported platforms: macOS (Apple Silicon and Intel) and Linux (x64 and arm64, glibc only — Alpine/musl isn't supported). Windows isn't supported yet. The CLI's source isn't public yet. We plan to open-source it. It's built on the [Sumvin TypeScript SDK](https://github.com/Sumvin/sdk-ts), which is already open source, so you can use the same building blocks in your own tools today. ## Verify the install ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin --version ``` This prints the installed version. If it doesn't run, check that the binary is on your `PATH`. **Next:** [Sign in](/get-started/cli/sign-in) to connect the CLI to your account. # Sign in Source: https://docs.sumvin.com/get-started/cli/sign-in Connect the CLI to your Sumvin account and check who you're signed in as. **Private preview:** this is rolling out and may not be available on your account yet. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin login ``` The CLI never sees your password. It gives you a short code and a link, opens your browser to a sign-in page, and waits. ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} To sign in, visit: https://… and enter the code: WDJB-MJHT Check the code shown in your browser matches the one above. ``` Check the code in your browser against the one in your terminal, then approve. Once you do, the CLI finishes on its own: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Signed in. Token expires 2026-09-29. ``` If your browser doesn't open automatically, the CLI also prints a complete link with both codes built in. That link is a live credential for this sign-in — treat it like a password. Don't paste it into a chat, a log, or a shared channel. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin whoami ``` ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Signed in as sumvin-cli@my-laptop Status: active Expires: 2026-09-29 14:02:11 UTC Last used: 2026-08-05 09:41:55 UTC ``` This checks with your account directly, so a token that's expired or been revoked shows up honestly rather than as a stale success. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin logout ``` This revokes the token on your account and removes it from this machine. Running it when you're already signed out does nothing harmful — it confirms you're signed out. ## Where your sign-in lives Signing in stores a token on this machine, valid for 90 days. It's saved to a file only your user account can read, and it's revoked immediately, everywhere, the moment you run `sumvin logout` — not just on this machine. If you're already signed in and run `sumvin login` again, the CLI asks before replacing your current token. **Next:** [Give your agent the CLI](/get-started/cli/with-your-agent), or see the [command reference](/reference/cli/auth). # Use the CLI with your agent Source: https://docs.sumvin.com/get-started/cli/with-your-agent Let a terminal agent drive the Sumvin CLI on your behalf. **Private preview:** this is rolling out and may not be available on your account yet. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. A packaged skill for terminal agents (Claude Code, Cursor, and similar tools) is on the way. Until it ships, any agent that can run shell commands can already drive `sumvin` today — tell it how, using the instructions below. ## The `--json` contract Every `sumvin` command accepts a `--json` flag. Instead of the human-readable text, it prints exactly one JSON document to standard output and nothing else — no progress messages, no partial lines, nothing on standard error to interleave with it. The shape is consistent across every command: ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 0, "command": "whoami", "data": { }, "next": [ ] } ``` A few things worth telling your agent explicitly: * `ok` means the command ran to completion. It is **not** the answer to a yes/no question — a mandate that fails verification is still a successful, `ok: true` run. Read `exit_code` (`0` succeeded, `1` the run failed, `2` the run succeeded and the answer is no) for the actual verdict. * `data` carries the result on success; `error` carries a structured code, title, and detail on failure. * `next` suggests the command to run after this one, so an agent can chain steps without guessing. * Running `sumvin --json` with no command returns the entire command surface as a single catalog — an agent can learn every command, flag, and exit code from one call, without reading `--help` text written for humans. ## Tell your agent to use it Paste this into a terminal-agent session that has `sumvin` on its `PATH`: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Use the sumvin CLI to help me manage my Sumvin account. Always pass --json and read the "exit_code" field for the real result — "ok": true only means the command ran, not that the answer was yes. Run `sumvin --json` first to see the full list of commands, their flags, and what each exit code means. Never run a command that signs, approves, or spends without asking me first and showing me exactly what it will do. ``` An agent with shell access to `sumvin` can read anything your signed-in account can read. It can also sign: the CLI signs with the key on your machine, so an agent in your terminal can approve a Stamped Mandate or sign an errand's bounds — and an errand signed that way searches and buys a match within those bounds without asking you again. `--yes` skips the prompt that would have stopped to ask you. Sign things yourself, and never give an unattended agent `--yes`. ## What's coming A packaged skill will let you add the CLI to a terminal agent with one command, instead of pasting instructions by hand. It isn't published yet. **Try asking your agent:** "Show me every sumvin command and what it does." # Connect your agent Source: https://docs.sumvin.com/get-started/connect Add the Sumvin connector to Claude, ChatGPT, ChatGPT Work, Claude Code, OpenClaw or Hermes Agent, then sign in. **Private preview:** this is rolling out and may not be available on your account yet. Sumvin is a connector your agent talks to. Every client uses the same address: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} https://mcp.sumvin.com/mcp ``` This is the recommended way to use Sumvin. Building or experimenting from a terminal? Developers can use the [CLI](/get-started/cli/install) instead. Pick your client. Each tab has three parts: add the connector, sign in, check it worked. When you sign in, sign in or create a Sumvin account. You can connect before you have an account; your agent helps you finish creating one. Works on claude.ai and in Claude Desktop. Add it once on claude.ai. Go to **Customize > Connectors**, select **Add custom connector**, and enter: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} https://mcp.sumvin.com/mcp ``` Name it `Sumvin` and select **Add**. Leave the other settings as they are. Select **Connect** and sign in or create a Sumvin account in the window that opens. Sumvin shows as connected under **Customize > Connectors**. In a chat, open the **+** menu, then **Connectors**, and make sure Sumvin is on. On a Team or Enterprise plan, an Owner adds the connector under **Organization settings > Connectors** (**Add**, then **Custom**, then **Web**). Each member then finds it under **Customize > Connectors** and selects **Connect**. Needs developer mode, on ChatGPT on the web. Custom apps aren't available in the ChatGPT mobile app. Custom connectors may be limited on Plus and Pro. Full use needs a Business, Enterprise or Edu plan with developer mode turned on. Go to **Settings > Apps > Advanced settings** and turn on **Developer mode**. On a workspace plan, an admin may need to allow it first; see below. In **Settings > Apps**, select **Create** and enter: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} https://mcp.sumvin.com/mcp ``` Name it `Sumvin` and choose **OAuth** for authentication. Select **Scan Tools**, which lists Sumvin's tools before you sign in, then **Create**. Sign in or create a Sumvin account when ChatGPT asks. Sumvin appears under **Settings > Apps**, labelled **Dev**. In a new chat, select Sumvin from the tools menu. ChatGPT may ask you to confirm a Sumvin tool call before it runs. On a ChatGPT Business, Enterprise or Edu workspace, admins control custom apps: * An admin allows developer mode under **Workspace settings > Permissions & roles > Connected Data**. On Business, only admins and owners can use developer mode. * An admin can also add Sumvin from **Workspace settings > Apps > Create**, then publish it from **Workspace settings > Apps > Drafts**. * Once it's published, members find Sumvin under **Settings > Apps**, marked **custom**, and each member signs in with their own Sumvin account. On Business, a published app can't be updated. If Sumvin adds tools, an admin recreates and republishes the app. ChatGPT Work is the mode in ChatGPT for longer tasks. In the ChatGPT desktop app, on any plan, you add Sumvin as an MCP server. In the ChatGPT desktop app, open **Settings**, then **MCP servers**, and select **Add server**. Name it `sumvin`, choose **Streamable HTTP**, and enter: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} https://mcp.sumvin.com/mcp ``` Save the server, then select **Restart**. In the server list, select **Authenticate** next to Sumvin. Sign in or create a Sumvin account in your browser. In the composer, type `/mcp`. Sumvin is listed. For now, Sumvin works in ChatGPT Work in the ChatGPT desktop app. Keep **Work locally** selected in the composer. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} claude mcp add --transport http --scope user sumvin https://mcp.sumvin.com/mcp ``` `--scope user` makes Sumvin available in every project. Your Sumvin identity belongs to you, not to one repository. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} claude mcp login sumvin ``` Or run `/mcp` inside Claude Code and choose Sumvin. Sign in or create a Sumvin account in your browser. `/mcp` lists `sumvin` as connected. If you added Sumvin on claude.ai and sign in to Claude Code with the same Claude account, it may already be there. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} openclaw mcp add sumvin --url https://mcp.sumvin.com/mcp --transport streamable-http --auth oauth ``` ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} openclaw mcp login sumvin ``` Follow the link it prints, and sign in or create a Sumvin account. If your browser can't reach the machine running OpenClaw, use the `--code` command it prints instead. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} openclaw mcp probe sumvin ``` The probe connects and lists Sumvin's tools. By default, OpenClaw uses one shared sign-in for each server. Anyone who can talk to your OpenClaw acts on Sumvin as you. If other people use your OpenClaw, set up per-requester sign-in first; see OpenClaw's [Transports and OAuth](https://docs.openclaw.ai/cli/mcp/transports). **What they still can't do: approve.** Anything that needs your authority still needs a [Stamped Mandate](/concepts/stamped-mandates) that you approve yourself, with your passkey, on a Sumvin page in your own browser. Someone messaging your OpenClaw can ask for a mandate, but they can't approve one without your passkey. That is a real step up for OpenClaw: it can act for you, while the authority stays with you. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} hermes mcp add --url https://mcp.sumvin.com/mcp --auth oauth sumvin ``` Hermes opens your browser the first time it connects. Sign in or create a Sumvin account. To sign in again later, run `hermes mcp login sumvin`. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} hermes mcp test sumvin ``` Then start a new `hermes chat`, or run `/reload-mcp` in one that's already open, so Sumvin's tools load. Sign-in finishes on the machine where Hermes runs. If Hermes runs on a remote host, see Hermes Agent's [OAuth over SSH](https://hermes-agent.nousresearch.com/docs/guides/oauth-over-ssh). ## Troubleshooting Check the address is exactly `https://mcp.sumvin.com/mcp`, including `/mcp` at the end. Remove the connector and add it again. Restart your client. Remove the connector and add it again, then finish sign-in in the browser window your client opens. Claude Code users can run `claude mcp login sumvin` again. Make sure Sumvin is switched on for this conversation: the **Connectors** item in Claude's **+** menu, or Sumvin in ChatGPT's tools menu. In Hermes Agent, run `/reload-mcp`. If you don't have a Sumvin account yet, your agent still sees Sumvin's tools, and calling one gives you a sign-up link. See [Your first conversation](/get-started/first-conversation). * **Claude**: **Customize > Connectors**, then **Remove** on Sumvin. * **Claude Code**: `claude mcp remove sumvin`. This also deletes the sign-in Claude Code stored. * **ChatGPT**: manage the app under **Settings > Apps**. * **ChatGPT Work** (desktop app): manage Sumvin under **Settings > MCP servers**. * **OpenClaw**: `openclaw mcp logout sumvin`, then `openclaw mcp unset sumvin`. * **Hermes Agent**: `hermes mcp remove sumvin`. Disconnecting a client stops it reaching Sumvin. To withdraw what an agent was allowed to do, see [Revoke access](/guides/revoke). **Try asking your agent:** "What can you do with Sumvin?" # Your first conversation Source: https://docs.sumvin.com/get-started/first-conversation What your agent can do right after you connect, and why it asks you to finish setting up first. **Private preview:** this is rolling out and may not be available on your account yet. Once Sumvin is connected, your agent knows where you are in setting up and what it can do for you now. It tells you the next step instead of guessing. What happens first depends on where you are: | You are | Your agent can | | - | - | | New, with no Sumvin account | Give you a link to create one. Nothing else yet. | | Signed up, not yet verified | Show your progress and give you a link to get verified. | | Verified | Show your Sigil, ask you for a Stamped Mandate, and run errands within it. | ## If you don't have an account yet You can connect before you have a Sumvin account. Until you create one, your agent sees a single tool, and that tool gives you a sign-up link. It hands you a link. Open it in your browser. Your agent can't fill it in for you. Use the same sign-in you used when you connected. An account created under a different sign-in won't reach this connection. Tell your agent you're done. It now sees the full set of Sumvin tools. If your agent says sign-up can't be started from the conversation right now, try again later. There's no separate sign-up page yet. ## Before you're verified Getting verified means confirming your phone number, then your identity. Until that's done, anything that gives your agent spending authority waits. Ask for it early and your agent answers with the next step, not an error: * **Verification not started**: your agent asks you to start it. * **Verification in progress**: nothing has gone wrong. Your agent asks you to check back once it's finished. This is by design. Only a verified person can give an agent authority to act for them. ### Where you are Ask your agent where you are. It reads your progress stage by stage. Reading it changes nothing. | Stage | Means | | - | - | | Phone | Confirm your phone number with a code. | | Identity | Verify your identity with [Sumsub](https://sumsub.com). | | Complete | Every stage your setup needs is done. | Each stage is **done**, **up next**, **still ahead** or **skipped**. A skipped stage doesn't apply to your account. Your agent reads something like this: ```json Example progress theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "current_stage": "kyc_verification", "stages": [ { "stage": "phone_verification", "status": "completed" }, { "stage": "kyc_verification", "status": "current" } ] } ``` ### Getting verified Your agent can give you one link that covers both stages in a single browser visit. Open it and follow the page. There's nothing for your agent to do afterwards except check your progress again. The link is yours alone, works once and expires. If it stops working, ask your agent for a new one. If you're already verified, your agent says so and gives you no link. If verification is busy, your agent will tell you to try again later. ## Once you're verified Ask your agent to show your Sigil, your verified identity. If it says your Sigil hasn't been issued yet, that's expected while issuance is rolling out. See [Your Sigil](/get-started/first/sigil). ## Things your agent can't do here Some parts of your account are managed only in the Sumvin app or the Sumvin CLI. If your agent reaches for one, it tells you where to go instead. Confirm your phone and your identity in one browser visit. **Try asking your agent:** "Where am I with my Sumvin setup?" # Run your first errand Source: https://docs.sumvin.com/get-started/first/errand Ask your agent to do one thing for you; you answer any question, sign the errand's bounds, and follow it as Sumvin searches, checks the merchant, watches and settles. **Private preview:** this is rolling out and may not be available on your account yet. An errand is a purchase you ask your agent to make, run within a [Stamped Mandate](/get-started/first/stamped-mandate). You ask in your own words. You sign the errand's bounds: the most it may spend, the currency, any conditions, and when the authorisation lapses. Then Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase. Nothing is searched until you sign, and once you have signed, a match within your bounds is bought without asking you again. Sumvin is a [Visa Intelligent Commerce Launch Partner](https://www.visa.com/en-us/solutions/intelligent-commerce), and errands are built on Visa Intelligent Commerce. **Coming soon:** payments arrive in a fast-follow release. Payments aren't part of this preview. They arrive in a fast-follow release, with its own waitlist. ## The shape of an errand ```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} flowchart LR A[You ask] --> C{Question?} C -- yes --> D[You answer] D --> E[You sign] C -- no --> E E --> F[Sumvin searches] F --> G[Checks the merchant] G --> H[Watches for your conditions] H --> I[Settles] ``` You sign once, before anything is searched. With a repeat errand, one signature covers several matching errands. See [Repeat errands](/guides/repeat-errands). ## Run it Tell your agent what you want, in your own words. It starts an errand with `errand_create`, keeping your phrasing, because that is what the errand is checked against later. Starting an errand doesn't search for anything or authorise any spending. It needs the most it may spend and the currency, because that is what you sign. If the errand needs more detail, your agent asks you, for example about size or budget. Answer in the conversation; your agent passes your answers on with `errand_action`. Before anything is searched, the errand waits for you at `pending_approval`. You see what you're signing: your ask, the most it may spend, any conditions, and when the authorisation lapses. Your agent can't sign for you; you sign it yourself. Signing an errand from the connector is coming soon. It arrives with payments. Until then, an errand you run from the connector stays waiting at this step. Once you've signed, Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase, without asking you again. Ask your agent how it's going. It reads the errand with `errand_query` and its history with `errand_events_query`. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand create "Reorder my usual coffee beans" --max 30 --currency GBP ``` ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Errand created (qualifying). The agent is now qualifying your request. Run `sumvin errand get` to follow its progress. ``` `--max` (the most it may spend, such as `30` or `29.50`) and `--currency` (a three-letter code, such as `GBP` or `USD`) are required, because they are what you sign. Creating the errand authorises nothing. The command also prints a key. If your connection drops before you see a reply, run the same command again with `--idempotency-key ` and no second errand is created. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand get ``` Questions appear numbered under **Clarification questions**. Answer them by number: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand clarify --answer 1="The 1kg bag" ``` When the status is `pending_approval`, nothing has been searched yet. Review the errand's bounds and sign: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand approve ``` The CLI shows the statement, the spend limit, any conditions and the expiry, and asks you to confirm. A match found within these bounds is bought without asking you again. The first time, you set up a signing key; see [Stamped Mandate](/get-started/first/stamped-mandate). To decline, run `sumvin errand reject `. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand events ``` After you sign, the errand searches, checks the merchant, watches for your conditions, and settles. Events are listed oldest first: status changes, questions sent and answered, your signature requested and received, and the purchase starting and finishing. ## What you'll see | Status | What it means | | - | - | | `qualifying` | Reading your ask. | | `pending_clarification` | Waiting for you to answer a question, before you sign. | | `pending_approval` | Waiting for you to sign the errand's bounds. Nothing has been searched yet. | | `approved` | You signed. The search is about to start. | | `searching` | Looking for options within what you signed. | | `validating` | Checking an option, and the merchant selling it, against what you signed. | | `monitoring` | Watching for the conditions you set, such as a price or stock level. | | `executing` | Buying now. | | `completed` | Settled. Done. | | `failed` | It didn't go through. The errand says why. | | `expired` | It ran out of time, including when you don't sign in time. | | `cancelled` | You cancelled or declined it, or its mandate was revoked. | `completed`, `failed`, `expired` and `cancelled` are final. A signed errand isn't a completed purchase yet: it goes on to search, check the merchant, watch and settle, within the limit you signed and only while its conditions hold. It doesn't ask you again. ## Stop an errand You can stop an errand at any point before it's final. Ask your agent to cancel it, or run: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand cancel ``` ## What can go wrong Starting errands is rolling out. If your agent or the CLI says your account can't start errands yet, the rest of your setup is unaffected. An errand takes answers only while it's waiting on a question. Check its status first. An errand you don't sign in time can't be signed any more. Nothing was searched or spent. If it's still waiting, decline it, then start a new one. Read the errand's history: ask your agent, or run `sumvin errand events `. If the errand was cancelled because you revoked its mandate, the history says so. **Try asking your agent:** "Reorder my usual coffee beans." # See your Sigil Source: https://docs.sumvin.com/get-started/first/sigil Your Sigil is your verified identity; once it is ready, every agent you connect carries proof that a real person stands behind it. **Private preview:** this is rolling out and may not be available on your account yet. Your Sigil is your verified identity. Once it is ready, every agent you connect carries proof that a real, verified person stands behind it. You don't request a Sigil. It is issued to you after [verification](/get-started/first/verify) is approved. This step is where you see it. ## See it Ask your agent to show you your Sigil. It calls `sigil_show`. Your agent tells you which state your Sigil is in. The states are listed below. Nothing is pushed to your agent when your Sigil is ready. If it's on its way, ask again shortly; your agent reads the latest state each time. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin sigil show ``` When verification is approved, `sumvin kyc status --wait` also prints a line about your Sigil. `sumvin sigil show` gives the full picture. The first line names the state: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} State: minted ``` For agents and scripts, `sumvin sigil show --json` returns the same answer with the state in `data.state`. ## What your agent shows you Your agent words it in its own way. When your Sigil is ready, expect something like this: ```text Your Sigil theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Your Sigil is ready. Sigil Ready Token id 12345 Issued 1 September 2026, 09:30 UTC Verified by Phone number and identity document Stands for You, a verified person Carried by This agent, and any other agent you connect From now on, anything I do through Sumvin carries proof that a verified person stands behind it, and that I act for you. ``` The token id and issue time are your Sigil's public record. When your Sigil is ready, `sigil_show` returns them as `token_id` and `minted_at` (Unix milliseconds). In the terminal, `sumvin sigil show` prints the token id: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} State: minted Sigil minted — token 12345. Mint status: completed ``` `sumvin sigil show --json` carries it as `data.did_token_id`. You don't need either to use Sumvin. ## What you'll see | State | What it means | What to do | | - | - | - | | **Ready** | Your Sigil exists. | Nothing. Go on to [your first Stamped Mandate](/get-started/first/stamped-mandate). | | **On its way** | Your Sigil is being issued now. | Check again shortly. | | **Not issued yet** | You're verified, and your Sigil hasn't been issued. This is a normal answer. | Check again later. | | **Something went wrong** | Issuing your Sigil didn't succeed, and it won't fix itself. | Email [hello@sumvin.com](mailto:hello@sumvin.com). Asking again won't change it. | | **Couldn't be read** | Sumvin couldn't read your account right now. This says nothing either way. | Try again. | If you haven't finished verification, the terminal shows `not_verified` and points you to `sumvin kyc start`. Your agent reports **Not issued yet** in that case, so ask it to check your setup as well. Either way, go back to [Verify](/get-started/first/verify). | Plain state | From your agent (`sigil_show`) | In the terminal (`sumvin sigil show`) | | - | - | - | | Ready | `minted` | `minted` | | On its way | `mint_in_flight` | `in_flight` | | Not issued yet | `mint_not_started` | `not_started` | | Something went wrong | `mint_failed` | `failed` | | Couldn't be read | `lookup_unavailable` | exits with an error | | Not verified yet | `mint_not_started` (your agent can confirm with `onboarding_status`) | `not_verified` | | Not recognised by this CLI version | not applicable | `unknown`: upgrade the CLI | ## What can go wrong Keep checking back. If it moves to **Something went wrong**, email [hello@sumvin.com](mailto:hello@sumvin.com). This is an ordinary answer, not a fault. Being verified and having a Sigil are separate facts, and issuing can follow verification. Check again later. Each check is a fresh read. If your agent treats the first answer as final, ask it to check again. **Try asking your agent:** "Show me my Sigil." # Approve your first Stamped Mandate Source: https://docs.sumvin.com/get-started/first/stamped-mandate Your agent proposes a spending mandate — one kind of Stamped Mandate — you review it on your own page, and you approve exactly what you see with your passkey; your agent can never approve its own mandate. **Private preview:** this is rolling out and may not be available on your account yet. **Coming soon:** payments arrive in a fast-follow release. A Stamped Mandate is an authorisation you sign for what an agent may do for you. It belongs to your account, not to the agent that asked for it. This is your first one, and it's a spending mandate: what your agent may spend on, how much, and until when. It's one kind among several — see [what a mandate can authorise](/concepts/mandates/use-cases). Your agent asks. You decide. **Your agent can never approve its own mandate.** It can propose one and check what you decided. Only you can approve it, with your passkey, on a Sumvin page in your own browser, away from the conversation. ## Before you start * You're [verified](/get-started/first/verify). A request from an account that isn't verified yet is refused, and your agent tells you which step is missing. * To approve from your agent: you've created your signing key, the passkey you approve with. You do this in your browser at the end of [verification](/get-started/first/verify). The terminal uses its own key instead; see the terminal tab below. ## Approve Tell your agent what you want it to be able to do, and how much it may spend. It proposes a mandate with `mandate_request` and tells you, in your own money's terms, the most it would ever authorise. Nothing is granted yet. Asking twice for the same thing doesn't create two requests; it re-opens the one you already have. In chat apps that support it, a **Spending authority** card appears in the conversation. It shows the limit (**Up to**), what it **Spends on**, when the request **Lapses** if you don't answer, and, once signed, how long the mandate **Lasts until**. Choose **Review and sign**; your browser opens. A request to read your linked accounts or prove your balance shows **Reads**, **Proves** or **Reads and proves** in place of **Spends on**, and has no limit. Everywhere else, your agent gives you a link to open instead. The link is issued once. If it's lost, ask your agent to request the mandate again. You normally create your signing key at the end of verification. If you didn't, the page says this account can't approve requests yet and offers **Set up your signing key**. Follow it and create a passkey when your browser asks. Then ask your agent to request the mandate again. You do this once. Later reviews go straight to the request. The page is headed **An agent is asking for spending authority** and shows who you're approving as. Under **Your signature binds** it lists the statement, what the mandate spends on, and how long it lasts. What you see here is exactly what you sign. Choose **Grant this authority** and confirm with your passkey, or choose **Decline**. Soon after you create your signing key, the page may say your account is finishing setup; it carries on by itself. Declining authorises nothing and needs no signature. The page confirms **Authority granted** or **Request declined**, and tells you to return to your agent. The card updates to show your decision. Your agent learns the outcome by checking with `mandate_status`; nothing is pushed to it, so it may need a moment before it checks. In the terminal, you approve a Stamped Mandate when an [errand](/get-started/first/errand) is waiting for your signature, before it searches. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin keys generate sumvin keys add-to-safe ``` `keys generate` creates a signing key on this machine. `keys add-to-safe` registers it to your account and waits until the registration is confirmed. Your key stays on your machine. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand approve ``` The CLI shows the statement, the spend limit on its own line, and the expiry, then asks you to confirm: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Errand: You are signing this errand's bounds, not a chosen product. Nothing has been searched for yet; a match found within these bounds is bought without asking again. Authorise a purchase: “Order two boxes of A4 paper”, spending up to 200.00 USD. The purchase is paid with your Visa card ending 4242. It proceeds only while all of the following hold: - the price is at most 180 USD - availability is one of: in_stock A match found within these bounds is bought without asking again. This authorisation lapses on 12 Aug 2026, 07:30 UTC. Ceiling: Up to USD 200.00 Expires: 2026-08-12T07:30:00.000Z (6:59:12) Sign this errand's bounds? A match within them will be bought without asking you again. ``` You are signing bounds, not a chosen product. Read the ceiling as carefully as the statement: it is shown on its own line, and it is what your signature binds. Answer `y` to sign. The errand then searches within your bounds. Anything else sends nothing. To decline instead: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand reject ``` Declining cancels the errand. Nothing is signed, nothing is searched, and nothing is spent. ## What you'll see | Status | What it means | | - | - | | Waiting on you | You haven't answered yet. Nothing is authorised. | | Granted | You signed. Your agent can now spend within this limit. | | Declined | Nothing was authorised. | | Lapsed | The request expired unanswered. Nothing was authorised. Ask your agent to request it again. | | Replaced | A newer request replaced this one. Use the latest card. | Your agent sees these as `proposed`, `stamped`, `declined` and `expired`. If a request ended some other way than you answering it, for example it was withdrawn, your agent receives a reason it can read back to you. ## Two ways to approve For a purchase, the order is always the same: you ask, you sign, then Sumvin searches, checks the merchant, watches for your conditions, and settles. A Stamped Mandate can cover that in one of two ways: * **Sign each errand.** You sign each errand's bounds before it searches. A match found within them is bought without asking you again. This is the default. * **Pre-authorise repeat errands.** One signature, with limits, covers several matching errands, so each one doesn't wait for a new signature. See [Repeat errands](/guides/repeat-errands). ## What can go wrong Ask your agent for the review link and open it yourself. You'll see **Your account setup isn't finished**. Finish [verification](/get-started/first/verify), then ask your agent to request the mandate again. You can still decline the request so your agent isn't left waiting. You haven't created your signing key. Choose **Set up your signing key**, create your passkey, then ask your agent to request the mandate again. You can still decline the request so your agent isn't left waiting. Your signing key couldn't be unlocked on this device. Nothing was authorised. Try again with the passkey you created, or ask your agent to try again if this keeps happening. You're signed in as someone other than the account your agent named. Sign in with the right account, then try again. **Link expired** means the request lapsed; ask your agent to request it again. **Already decided** means there is nothing left to do. You can't approve an expired mandate. Run `sumvin errand reject ` to close the errand, then start a new one. Run `sumvin errand approve` again; each run fetches the current terms. If it fails again, check your key with `sumvin keys show`. **Try asking your agent:** "Set up a spending limit of \$50 for groceries this week." # Verify your identity Source: https://docs.sumvin.com/get-started/first/verify Verify your phone number, then an identity document, then create the passkey you approve with, in one trip to your browser. **Private preview:** this is rolling out and may not be available on your account yet. Verification proves that a real person stands behind your agent. It is the step that unlocks your [Sigil](/get-started/first/sigil). The order is the same on every path: **your phone number first, then an identity document, then your signing key**. You make one trip to your browser, and you come back to the conversation or the terminal you started from. ## Before you start * A Sumvin account, reached through [your agent](/get-started/connect) or [the CLI](/get-started/cli/sign-in). * A phone that can receive a text message. * An identity document, and a device with a camera and a browser. * A browser that can save a passkey, such as Chrome or Safari with iCloud Keychain or Google Password Manager. ## Verify Ask your agent to help you get verified. It checks where you are with `onboarding_status`, then calls `kyc_start` to get your verification link. If you are already verified, your agent tells you so and there is nothing more to do. Your agent gives you the link exactly as it came back. Open it in your browser and sign in to your Sumvin account if the page asks. The link works once and belongs to you alone. If it stops working, ask your agent for a new one rather than reusing the old one. If your phone number isn't verified yet, the page shows **Verify your phone**. Enter your number, then the code that arrives by text message. The page brings you straight back to the same verification afterwards. Follow the on-screen prompts to capture your document. When you finish, the page shows **Verification submitted** and **Keep this tab open. Next, create your signing key.** Keep the tab open. Once your identity is approved, the same page continues to **Create your signing key**. Choose **Create your signing key** and create a passkey when your browser asks. If the page then asks, choose **Confirm with your passkey** and use the passkey you just created. The page shows **Signing key created** and tells you to return to your conversation. Your passkey is saved to iCloud Keychain or Google Password Manager, so it also works on your other devices that share it. You approve every [Stamped Mandate](/get-started/first/stamped-mandate) with it. Tell your agent you're done. It checks `onboarding_status` again and tells you what is left. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin kyc status ``` `pending` means you haven't started. `approved` means you are already verified and can skip ahead to [your Sigil](/get-started/first/sigil). ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin kyc start ``` The CLI asks for your phone number in international format, then for the six-digit code from the text message. You type the code yourself; it can't be scripted. ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Phone number (E.164, e.g. +14155551234) +447700900123 We sent a verification code to +447700900123. 6-digit code from the SMS 123456 Phone number +447700900123 verified. ``` The same command then prints your verification link and opens it: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Finish verifying your identity here: https://… Next: `sumvin kyc status --wait` ``` The link is printed before the browser opens, so on a machine with no browser you can open it on any other device. Treat it like a password: it works once and belongs to you. Sign in if the page asks, then follow the prompts to capture your document. When you finish, the page shows **Verification submitted** and **Keep this tab open. Next, create your signing key.** Keep the tab open. Once your identity is approved, the same page continues to **Create your signing key**. Choose **Create your signing key** and create a passkey when your browser asks. If the page then asks, choose **Confirm with your passkey** and use the passkey you just created. The page shows **Signing key created** and tells you to return to your terminal. Your passkey is saved to iCloud Keychain or Google Password Manager, so it also works on your other devices that share it. It is what you approve a [Stamped Mandate](/get-started/first/stamped-mandate) with in your browser, from your agent. In the terminal, you approve with a separate key kept on your machine; see [`sumvin keys`](/reference/cli/keys). ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin kyc status --wait ``` A line prints only when your status changes. Stopping the wait loses nothing: verification carries on, and running the command again picks it back up. ## What's checked Our identity-verification partner, [Sumsub](https://sumsub.com/), checks that your document is genuine and that it belongs to you. You photograph your ID document, then take a selfie so Sumsub can match your face to it. Sumvin checks that your phone number is yours. Your name and date of birth are read from your document during the check. There's nothing to type in beforehand. Your document goes from your browser to the verification page, never through your agent. What we keep, and what your agent and others can see, is on [Privacy](/concepts/privacy). ## What you'll see | Status | What it means | What to do | | - | - | - | | Pending | You haven't started. | Start verification. | | In progress | Your document is being checked. | Check again shortly. | | Approved | You're verified. | Go to [your Sigil](/get-started/first/sigil). | | More information needed | The check needs another attempt. | Run it again: **Verify again** on the page, or `sumvin kyc start` in the terminal. | | Not approved | Verification was declined. This is final. | [Contact support](/support) if you think the decision is wrong. | In the terminal these read `pending`, `in_progress`, `approved`, `retry` and `rejected`. ## What can go wrong The page shows **Link expired** or **Link already used**. Ask your agent for a new link, or run `sumvin kyc start` again. If you have more than one link open, use the newest. The page shows **Different account**. Choose **Sign out and switch account**, then sign in with the account that started verification. Run `sumvin kyc start` again to have the code sent again, or ask your agent for a fresh link. Check the number's country code. Phone requests and wrong codes are both limited, so leave a gap between attempts. The page shows **Too many attempts** or **Verification unavailable**. Nothing is lost. Try again later; retrying straight away is refused the same way. Make sure your phone number is confirmed, then start again. If it still won't start, email [hello@sumvin.com](mailto:hello@sumvin.com). Your verification carries on without it, but you can't approve anything until you create one. The first time you open a review page, it offers **Set up your signing key**. Follow it, create your passkey, then ask your agent to request the mandate again. Your browser or passkey provider can't be used for your signing key. Continue in Chrome or Safari with an iCloud Keychain or Google Password Manager passkey: scan the code on the page, or choose **Open link**, and sign in to Sumvin there. Or choose **Try again**. The page shows **Passkey prompt canceled**. Nothing is lost. Try again when you're ready. A declined verification can't be retried with the same documents, and your agent can't start a new one for you. [Contact support](/support) if you believe the decision is wrong. "More information needed" is different: resubmitting is exactly what to do. **Try asking your agent:** "Help me get verified with Sumvin." # How it works Source: https://docs.sumvin.com/get-started/how-it-works The four Sumvin nouns, how they connect you to your agent, and the guarantees between them. Four nouns sit between you and your agent: your **Sigil**, an **agent identity**, a **Stamped Mandate** and an **errand**. ```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} flowchart LR P([You]) -- "verify once" --> S[Sigil] S -- "one per connection" --> I[Agent identity] A([Your agent]) -- "acts as" --> I P -- "sign" --> M[Stamped Mandate] M -- "limits" --> I A -- "runs" --> E[Errand] E -- "within" --> M E -- "presents" --> V([Merchant or service]) V -.->|checks| M ``` ## The nouns | Noun | What it is | | - | - | | [Sigil](/concepts/sigil) | Your verified identity. Proof that a real, verified person stands behind your agents. | | [Agent identity](/concepts/agent-identities) | The identity one connection uses under your Sigil. Claude, your terminal and any other agent each get their own. | | [Stamped Mandate](/concepts/stamped-mandates) | An authorisation you sign: what one agent may do — share data, prove who it acts for, or spend — and the limits it must keep to. | | [Errand](/concepts/errands) | A standing purchase your agent creates and Envoy runs, within a Stamped Mandate. Payments are coming soon. | ## The guarantees * **A person signs every mandate.** Your agent can ask for a Stamped Mandate. It cannot approve one. You approve it with your passkey, in your own browser, on a page your agent cannot touch. * **You sign what you see.** The limits on the approval page are the limits your agent gets. * **Each agent is separate.** Every connection has its own identity, so you can tell your agents apart and revoke one without touching the others. * **Limits are specific.** A mandate names what it covers, its expiry, and any amount it allows. Your agent cannot act outside them. * **You can take it back.** Revoke a mandate or disconnect an agent at any time. [Revoke access](/guides/revoke) * **The other side can check.** A merchant or service can confirm that a verified person stands behind the agent, and that the request is inside what that person signed. [Check a mandate](/guides/check-a-mandate) For the full picture, read [Trust and safety](/concepts/trust-and-safety) and [Privacy](/concepts/privacy). ## In order You meet the nouns in the order you use them. Add the Sumvin connector to your agent. Developers can use the CLI. Your phone, then your ID. One trip to the browser. What it is and what it proves. Review the limits and sign. **Try asking your agent:** "Explain what a Stamped Mandate lets you do for me." # What is Sumvin Source: https://docs.sumvin.com/get-started/what-is-sumvin Sumvin gives your agent a verified identity and limits you sign, so it can act for you and prove it. Sumvin is identity for agents. It lets an agent prove who it acts for, and what it has been allowed to do. ## The problem Agents already act for people. They book, buy, reorder and reply. The service on the other side sees a request from software and has two questions it cannot answer: * **Who is this agent acting for?** A real person, or no one at all. * **Within what limits?** What the person allowed, how much, and until when. Without answers, the agent is either blocked, or trusted with more than anyone meant to give it. ## What Sumvin adds Three things, each built on the one before. Your proof of personhood: a verified identity for you and your agents. You confirm your phone and your ID once. From then on, your agent carries proof that a real, verified person stands behind it. [About Sigils](/concepts/sigil) An authorisation you sign. It says what one agent may do — share data, prove who it acts for, or spend — and the limits it must keep to. Your agent can ask for one. Only you can approve it, with your passkey, in your own browser. [About Stamped Mandates](/concepts/stamped-mandates) A standing purchase, run within a Stamped Mandate. Your agent creates the errand; Envoy, Sumvin's money agent, runs it. Sumvin is a Visa Intelligent Commerce Launch Partner, and errands are built on Visa Intelligent Commerce. Payments are coming soon, in a fast-follow release. [About errands](/concepts/errands) ## Why it matters to you * **You set the limits.** Your agent never decides what it is allowed to do. * **You see every agent.** Each agent you connect has its own identity under your Sigil, and you can revoke any one of them. * **You can stop it.** Revoke a Stamped Mandate and the agent loses that permission. ## Why it matters to whoever your agent deals with A merchant or service receiving a request from your agent can check two facts before acting: a verified person stands behind this agent, and this request falls inside the limits that person signed. They do not need to trust the agent. They check the mandate. [Check a mandate](/guides/check-a-mandate) ## Where to go next The four nouns and the guarantees between them. Add Sumvin to the agent you already use. The recommended way in. **Try asking your agent:** "What can you do with Sumvin?" # Sign or decline an errand Source: https://docs.sumvin.com/guides/approve-or-decline Before your errand searches, you sign its bounds or decline it. Signing from the connector arrives with payments. **Coming soon:** payments arrive in a fast-follow release. Signing an errand from the connector arrives with payments. You ask. You sign. Then Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase. Once you've asked, and answered any question it has, your errand stops at `pending_approval`. Nothing has been searched yet. It waits for you to sign its bounds: the item, in your own words; the most it may spend, and the currency; any conditions; and when your authorisation lapses. Your agent cannot sign for you, from any surface. From the connector, you sign with your passkey, on a Sumvin page in your own browser. Before it searches, your errand proposes a Stamped Mandate covering its bounds, and waits for your signature. From the connector, this step arrives with payments. Coming soon, with payments. Your agent can tell you an errand is waiting at `pending_approval`, but can't sign it for you. Check what's waiting with: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand get ``` Then bring up the mandate itself: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand approve ``` The CLI fetches the mandate and prints it before asking you to sign. When you review it, you see three things: * **The statement** — your ask, in your own words, and any conditions (a price target, being in stock). * **The spend ceiling** — the most it may spend. Read this separately from the statement: two requests can use identical wording and still carry different ceilings, so the ceiling is always shown on its own line. * **When it lapses.** You are signing bounds, not a chosen product. Nothing has been picked yet. Coming soon, with payments. You'll sign in your own browser with your passkey, the one you created at the end of [verification](/get-started/first/verify). Answer `y` at the prompt, or run non-interactively with: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand approve --yes ``` Only use `--yes` when you are the one running the command. Never hand it to an unattended agent. Once you sign, the errand searches, checks the merchant, and watches for your conditions. A match found within your bounds is bought without asking you again. Declining is final. It cancels the errand. Nothing is signed, nothing is searched, and nothing is spent. Coming soon, with payments. Until then, you can ask your agent to cancel the errand. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand reject ``` An errand you don't sign in time expires, and signing is no longer possible. Start a new errand instead. ## See also * [Stamped Mandates](/concepts/stamped-mandates) — what a mandate is and what signing one means. * [Set limits](/guides/set-limits) — what you can constrain in a mandate before you sign. **Try asking your agent:** "Is my last errand still waiting for my signature?" # Check a mandate an agent shows you Source: https://docs.sumvin.com/guides/check-a-mandate Verify a Stamped Mandate presented to you before acting on it. If an agent presents you with a Stamped Mandate — as proof it's allowed to act on someone's behalf — check it before you rely on it. Holding an identifier or a token proves nothing on its own; a mandate can be withdrawn at any moment after it was granted. Pass the mandate identifier you were given to `mandate_verify`. It tells you: * Whether the identifier is recognised at all. * Whether it **still stands right now** — this is the one to read, not just its status label. A mandate can still show as active while the broader authority it depended on has since been withdrawn; `stands` accounts for that, a status label alone does not. * What it permits, and its ceiling. * Whether it was signed by the account holder themselves. * When it expires. Checking a mandate this way changes nothing and grants nothing — it only answers whether the one you were shown is good. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint verify ``` Verifies the token you were given — its signature, its claims, and whether it's still valid — and tells you plainly whether it checks out. Neither check tells you anything about who granted the mandate beyond what it authorises — no name, no contact details. It answers exactly one question: is this good to act on. ## See also * [Stamped Mandates](/concepts/stamped-mandates) — what a mandate is and what it can limit. * [Trust and safety](/concepts/trust-and-safety) — the guarantees behind every mandate. **Try asking your agent:** "Verify this mandate before you act on it." # Connect more than one agent Source: https://docs.sumvin.com/guides/multiple-agents Use Claude, ChatGPT and the CLI under the same Sigil, each with its own agent identity. Your Sigil is one verified identity. You can put more than one agent behind it, and each one is kept separate. Every MCP connection you add — Claude, ChatGPT, or anything else — gets its own agent identity the moment it first connects, under your Sigil. The CLI works differently: signing in with `sumvin login` authenticates you directly, rather than registering a separate connector identity. A connected agent can only see its own identity, not a list of every agent you've connected. Ask any one of them: > "Show me your agent identity." and it reports its own key and registration status (the tool behind this is `agent_identity_show`) — nothing about any other agent you've connected. A Stamped Mandate belongs to your account, not to the agent that asked for it. Revoking one mandate doesn't touch your others. Disconnecting an agent doesn't revoke the mandates it asked for: they stay valid until they expire or you revoke them. See [Revoke a mandate or disconnect an agent](/guides/revoke). Before you approve a new mandate, check which mandates are already in place. **Coming soon:** a single list of every agent connected to your account. Today, each agent can show you only its own identity. ## See also * [Agent identities](/concepts/agent-identities) — what an identity is and how it's minted. * [Revoke a mandate or disconnect an agent](/guides/revoke) — disconnecting one agent without touching the others. **Try asking your agent:** "Show me your agent identity." # Set up repeat errands Source: https://docs.sumvin.com/guides/repeat-errands Authorise a purchase once, with conditions, so matching errands don't need your approval each time. **Coming soon:** payments arrive in a fast-follow release. Every errand runs in the same order: you ask, you sign, then Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase. So every errand normally waits for your signature before it searches for anything — see [Sign or decline an errand](/guides/approve-or-decline). You can also sign once against a set of conditions, and let that one signature cover several errands that match them, without asking you again. For example: "reorder my usual coffee beans whenever it's under \$12" gives your agent a standing condition to check against, rather than a single one-off purchase. You still see the statement, the spend ceiling, and the expiry, and you still sign it yourself — the same as any other mandate. Signing it once is what covers every purchase that matches the conditions you set, until the mandate expires. While the mandate is active, your agent can act on it without stopping to ask you again — but only within the ceiling, the conditions, and the expiry you signed. Anything outside those still needs a new mandate. From the terminal, each errand needs its own signature before it searches — there's no flag to sign once for several yet. This mode is currently reachable only through your connected agent. ## See also * [Set limits](/guides/set-limits) — what a mandate can constrain. * [Stamped Mandates](/concepts/stamped-mandates) — the two ways a mandate can be used. **Try asking your agent:** "Reorder my usual coffee beans whenever it's under \$12, without asking me each time." # Revoke a mandate or disconnect an agent Source: https://docs.sumvin.com/guides/revoke Withdraw a Stamped Mandate, disconnect an agent, or sign out of the CLI. Three separate things can be withdrawn, and each stops something different. Revoking a mandate withdraws its authority, and withdraws every credential already issued from it — anything currently relying on it stops working. This cannot be undone: a revoked mandate never becomes active again. Ask your agent to revoke it. Find the mandate first (your agent can look it up for you), confirm it's the one you mean, and then revoke it — the tool behind this is `pint_revoke`. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint list sumvin pint revoke ``` Revoking an already-revoked mandate isn't a no-op — it comes back as an error telling you it's already withdrawn, which means the earlier revocation is still in force. Disconnecting an agent stops it reaching your Sumvin account, so it can't act for you any more. To disconnect Claude, ChatGPT or any other connected assistant, remove the Sumvin connector from that agent's own settings. See [Connect your agent](/get-started/connect) for where that lives on each client. Disconnecting an agent doesn't revoke the Stamped Mandates it asked for. They stay valid until they expire or you revoke them. Revoke them separately, as in the step above. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin logout ``` This removes your access token from your machine and, where possible, revokes it on the server too. It's safe to run more than once. **Coming soon:** a single list of every agent connected to your account, where you can disconnect any of them. ## See also * [Stamped Mandates](/concepts/stamped-mandates) — what a mandate grants, and what revoking one takes away. * [Agent identities](/concepts/agent-identities) — how each connection is tracked separately. **Try asking your agent:** "Revoke the mandate you're using for grocery orders." # Set limits on what your agent can spend Source: https://docs.sumvin.com/guides/set-limits What a Stamped Mandate can limit, and why those limits can't change once you've signed. **Coming soon:** payments arrive in a fast-follow release. A Stamped Mandate is the only way your agent gets to spend anything. Every mandate limits the same three things, and you see all three before you sign. When your agent asks you to authorise a purchase, it proposes: * **How much** — an amount, in a real currency. * **What it's for** — a plain-language statement of what the mandate covers, plus any conditions attached to it (a price ceiling, which sellers qualify, a delivery deadline). * **How long it lasts** — an expiry. After that point, the mandate can no longer be used, even if it was never fully spent. You see the amount, the statement, and the expiry together before you sign — see [Sign or decline an errand](/guides/approve-or-decline) for where that happens on each surface. For an errand, the most it may spend and the currency are set when you ask, and you sign them before anything is searched: you ask, you sign, then Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase. Once you sign, those three things are set. Your agent cannot raise the amount, widen what the mandate covers, or extend the expiry after the fact — it can only come back and ask you for a new mandate. A spending mandate covers a purchase your agent makes as an errand. Sumvin is a [Visa Intelligent Commerce Launch Partner](https://www.visa.com/en-us/solutions/intelligent-commerce), and errands are built on Visa Intelligent Commerce. Payments aren't part of this preview: they arrive in a fast-follow release, with its own waitlist. Other ways of moving money aren't part of this yet. ## See also * [Stamped Mandates](/concepts/stamped-mandates) — what signing one actually grants. * [Sign or decline an errand](/guides/approve-or-decline) — where you review and sign. * [Repeat errands](/guides/repeat-errands) — authorising more than one purchase at once. **Try asking your agent:** "Set up a spending limit of \$50 for groceries this week." # Sumvin Source: https://docs.sumvin.com/index Identity for every agent: a verified Sigil, limits you sign, and errands run within them.

Sumvin documentation

Identity for every agent.

Your agent acts for you. Sumvin lets it prove who it acts for, and stay inside the limits you sign.

Both paths are in private preview.

One path, five steps

  1. 01 Connect Add the connector to your agent. Developers can use the CLI.
  2. 02 Verify Your phone, then your ID. One trip to the browser.
  3. 03 Sigil Proof of personhood. Your agent carries proof that a verified person stands behind it.
  4. 04 Stamp Sign what your agent may do, and the limits it must keep to.
  5. 05 Errand Your agent creates the errand; Envoy runs it, inside those limits. Payments are coming soon.

Partners

Agent-readable

These docs are written for your agent as much as for you. Point it at /llms.txt for the index of every page, or at /skill.md for what it can do here.

New here? Start with what Sumvin is and how it works.

# sumvin login, logout, whoami Source: https://docs.sumvin.com/reference/cli/auth Sign in, sign out, and check your session from the terminal. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. Every command below accepts the [global flags](/reference/cli/json-output): `--api-url`, `--json`, `--debug`, `--help`. ## `sumvin login` Signs in using a device code: the CLI shows you a code and a link, you approve in your browser, and the CLI stores a token on this machine once you do. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin login ``` **Flags** | Flag | Effect | | - | - | | `--api-url ` | Sign in against a different Sumvin environment. | | `--json` | Print a result object instead of the sign-in narration. Never includes the token itself. | **Output states** * A fresh sign-in prints a code and a link, then `Signed in. Token expires .` once you approve. * If you're already signed in, the CLI asks before replacing your current session. * If the code expires before you approve, the CLI reports the sign-in as expired and you re-run it. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin login --json ``` ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 0, "command": "login", "data": { "pat_id": "pat_01H", "expires_at": 1893456000000 }, "next": [ { "command": "sumvin whoami", "reason": "Confirm you're signed in." } ] } ``` ## `sumvin logout` Revokes the stored token on your account, then removes it from this machine, in that order. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin logout ``` **Output states** * Signed in: `Signed out.` * Already signed out: `Already signed out.` — this is not an error; running `logout` when there's nothing to sign out of is a no-op. * If your account can't be reached, the local copy is still removed. Revoke the token from the Sumvin app as well if that matters to you. ## `sumvin whoami` Shows the session you're currently signed in with, checked live against your account rather than read from a local file. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin whoami ``` **Output states** * Signed in: name, status (`active`, `revoked`, or `expired`), expiry, and when it was last used. * Not signed in, or the stored session no longer works: `You're not signed in.` ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin whoami --json ``` ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 0, "command": "whoami", "data": { "token": { "id": "pat_01H", "name": "sumvin-cli@my-laptop", "status": "active", "expires_at": 1893456000000, "last_used_at": 1704153600000 } } } ``` ## Exit codes All three commands use `0` for success and `1` for failure — there is no "answer is no" case here, only "the run worked" or "it didn't." # sumvin errand Source: https://docs.sumvin.com/reference/cli/errand Create and manage agentic purchase errands from the terminal. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. An errand is a long-running purchase task that runs under a Stamped Mandate. You ask. You sign. Then Sumvin searches, checks the merchant, watches for your conditions, and settles the purchase. `sumvin errand` covers the whole lifecycle: creating one, signing or declining its bounds, checking on it, and answering its questions. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand create "" --max --currency sumvin errand list sumvin errand get sumvin errand events sumvin errand clarify --answer 1= sumvin errand approve sumvin errand reject sumvin errand cancel ``` **Private preview:** this is rolling out and may not be available on your account yet. **Coming soon:** payments arrive in a fast-follow release. `errand create` is available to accounts in the early-access group. The other verbs — `list`, `get`, `events`, `clarify`, `cancel` — work for any account that already has errands. ## `sumvin errand create` Submits a plain-language request, with the most it may spend and the currency. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand create "Order two boxes of A4 paper" --max 200 --currency USD ``` Creating an errand authorises nothing. The errand then waits at `pending_approval` for your signature before it searches for anything — see `sumvin errand approve` below. **Flags** | Flag | Effect | | - | - | | `` (required) | Plain-language description of what you want done. | | `--max ` (required) | The most the errand may spend, as a positive amount in major units — for example `200` or `180.50`. | | `--currency ` (required) | The currency of `--max`, as a three-letter code — for example `GBP` or `USD`. | | `--intent-type` | `product`, `service`, or `composite`. Defaults to `product`. | | `--idempotency-key ` | Lets you retry safely after a dropped connection without creating a duplicate — the CLI prints one automatically for you to reuse. | **Output states** * Created: the errand's ID and its starting status. * Retried with the same idempotency key: the same errand, reported as already existing rather than duplicated. * Not in the early-access group: the command refuses and tells you so. * Missing or malformed limit: if `--max` or `--currency` is missing or isn't in the right shape, the CLI refuses before contacting Sumvin: `An errand needs the most it may spend and the currency it is in. Set it with --max and --currency , e.g. --max 200 --currency GBP.` * Limit refused by Sumvin: an unsupported currency, or an amount finer than the currency holds, is refused — the CLI shows the reason with the same hint. ## `sumvin errand list` and `sumvin errand get` ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand list --status pending_approval sumvin errand get --expand mandate ``` `list` filters by status, intent type, and sort order. `get` shows one errand in full, and can expand its mandate or spend details inline. **Errand statuses**, in lifecycle order: `qualifying`, `pending_clarification`, `pending_approval`, `approved`, `searching`, `validating`, `monitoring`, `executing`, `completed`, `failed`, `expired`, `cancelled`. At `pending_approval`, nothing has been searched yet. ## `sumvin errand events` Lists the activity log for one errand — every status change and clarification, in order. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand events ``` ## `sumvin errand clarify` Answers a question the agent asked before it can continue. Questions come before you sign. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand clarify --answer 1="White, 80gsm" ``` Each `--answer N=` answers question `N` from `sumvin errand get`. Repeat the flag to answer more than one question in the same call. ## `sumvin errand approve` and `sumvin errand reject` After you create an errand, and answer any question it has, it waits for your signature before it searches for anything. `approve` signs the errand's bounds: what you asked for, the most it may spend and the currency, any conditions, and when the authorisation lapses. Approving needs a local signing key — see [`sumvin keys`](/reference/cli/keys) — because your approval has to be provably yours, not something Sumvin's own systems could produce on your behalf. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand approve ``` The CLI shows you the mandate before asking for confirmation: ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} Errand: ipa_01HQ8ZK3M4N5P6R7S8T9V0W1X2 You are signing this errand's bounds, not a chosen product. Nothing has been searched for yet; a match found within these bounds is bought without asking again. Authorise a purchase: “Order two boxes of A4 paper”, spending up to 200.00 USD. The purchase is paid with your Visa card ending 4242. It proceeds only while all of the following hold: - the price is at most 180 USD - availability is one of: in_stock A match found within these bounds is bought without asking again. This authorisation lapses on 12 Aug 2026, 07:30 UTC. Ceiling: Up to USD 200.00 Expires: 2026-08-12T07:30:00.000Z (6:59:12) Sign this errand's bounds? A match within them will be bought without asking you again. ``` You're signing bounds, not a chosen product. Once you sign, a match found within them is bought without asking you again — there's no second look at the pick. Read the ceiling and the conditions as carefully as the statement — they are what decides whether a match is bought. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand reject ``` Rejecting is terminal: the errand is cancelled and its reservation released. Nothing is signed, searched, or spent. It needs no key, because it authorises nothing. **Flags (both commands)** | Flag | Effect | | - | - | | `--yes` | Skip the confirmation prompt. Required in any non-interactive session. Never give it to an unattended agent: it approves without you. | **Output states** * Approved: the errand moves on to search, checks the merchant, watches for your conditions, and settles the purchase — all within the bounds you signed. * Rejected: the errand is cancelled. * "Not awaiting approval": only an errand in `pending_approval` can take a decision. * "Mandate has expired": approving is refused once the deadline passes — reject it and start a new errand. ## `sumvin errand cancel` Stops an errand that's still in progress. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin errand cancel ``` ## Exit codes Every verb uses `0` for success and `1` for failure. Cancelling an errand that's already in a terminal status still exits `0` — the end state you wanted already holds. **Try asking your agent:** "Check whether my last errand needs anything from me." # The --json contract Source: https://docs.sumvin.com/reference/cli/json-output How every sumvin command speaks to a script or an agent. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. Every `sumvin` command accepts `--json`. Instead of formatted text, it prints exactly one JSON document to standard output and nothing else — no progress messages, no partial output, nothing on standard error to interleave with it. ## The envelope **Success:** ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 0, "command": "pint get", "data": { "…": "…" }, "_links": { "…": "…" }, "next": [ { "command": "…", "reason": "…" } ] } ``` **Error:** ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": false, "exit_code": 1, "command": "pint get", "error": { "code": "PINT-404-001", "title": "Mandate not found. Check the ID and try again.", "detail": "No mandate with that id.", "status": 404, "trace_id": "abc-123" }, "next": [ { "command": "sumvin pint list", "reason": "See your mandates." } ] } ``` `data` is present only when `ok` is `true`; `error` is present only when `ok` is `false`. `error`'s fields are always present — `null` rather than omitted — so a script never has to check for a missing key before reading one. ## `ok` is not the verdict `ok` means the command completed — it reached your account, got an answer, and didn't crash. It does **not** mean "the answer is yes." The clearest example: verifying a Stamped Mandate that turns out to be invalid is a completely successful run whose answer is no. ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 2, "command": "pint verify", "data": { "valid": false } } ``` **Always read `exit_code` (or the command's own verdict field, such as `data.valid`) for check-style commands. Never branch on `ok` alone.** ## Exit codes | Code | Meaning | | - | - | | `0` | Success. | | `1` | The run itself failed and decided nothing. | | `2` | The run succeeded, and the answer is no. Only two commands use this: `sumvin pint verify` and `sumvin kyc status --wait`. | Every other command uses only `0` and `1`. A bare `sumvin kyc status` or `sumvin sigil show` reports state rather than judging it, so even an unwelcome result — a rejected verification, a failed Sigil — is still a successful read and exits `0`. ## `_links` vs `next` * **`_links`** — what can be done to this result, translated into a runnable `sumvin` command. Reflects what's actually available right now: it only lists actions your account can currently take. * **`next`** — what the CLI suggests you do now. Appears on errors (pointing at how to fix the problem) and on results with an obvious follow-up. A `command` in either field is always a complete, runnable command with real arguments filled in — never a placeholder. ## Discovery Running `sumvin --json` with no command returns the entire command surface as one catalog: every command, its flags, its arguments, and what each exit code means. An agent can learn the whole CLI from a single call, without reading text written for humans. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin --json | jq '.data.commands' ``` Running `sumvin --help --json` returns just that command's descriptor the same way. ## The stdout/stderr guarantee Under `--json`, nothing the CLI writes for a human — error lines, progress narration, `--debug` diagnostics — reaches standard error. Everything is either a field of the envelope or suppressed entirely. `sumvin --json 2>&1` is always safe to parse. Long-running commands (`sumvin kyc status --wait`, `sumvin keys add-to-safe`) print nothing at all until they finish. Silence under `--json` is expected, not a hang. ## An env var, if you'd rather not repeat the flag ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} SUMVIN_CLI_OUTPUT_JSON=1 sumvin login ``` An explicit `--json` on a single call always wins over the environment variable. ## Credential safety `--json` never emits a signing key or an access token. `sumvin login --json` returns the token's id and expiry, never the token; `sumvin whoami --json` returns token metadata, never the token; `sumvin keys add-to-safe --json` returns the registered address, never the key. **Try asking your agent:** "Run `sumvin --json` and tell me what commands are available." # sumvin keys Source: https://docs.sumvin.com/reference/cli/keys Manage the local signing key you use to approve mandates and errands yourself. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. This group is entirely optional. Without it, Sumvin's agent signs on your behalf whenever a Stamped Mandate is created. You reach for `sumvin keys` when you'd rather approve things yourself, from a key you hold, on a machine you chose. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin keys generate # create the key sumvin keys add-to-safe # register your key with your account sumvin keys show # see the key's address and registration status ``` Registering a key with your account can't be undone yet. There's currently no command to remove a registered key — plan for that before you register one. ## `sumvin keys generate` Creates a signing key and stores it on this machine. **Flags** | Flag | Effect | | - | - | | `--force` | Replace an existing key. Not reversible — see below. | | `--json` | Print a result object instead of the formatted view. | **Output states** * Success prints the key's address. The key itself is never printed, by this command or any other — only the address, which is safe to share. * If a key already exists, the command refuses and tells you to use `--force` or run `sumvin keys show` to see the one you have. If your existing key has already been registered with your account, overwriting it without a way to unregister the old one leaves that old key with standing authority and no copy of it on this machine — `--force` proceeds anyway, deliberately. ## `sumvin keys add-to-safe` Registers your local key's address with your account and waits for the registration to settle. **Flags** | Flag | Effect | | - | - | | `--timeout ` | How long to wait for the registration to settle. Defaults to 5 minutes. | | `--json` | Silence the progress narration and print one result once it settles. | Only the key's public address ever leaves this machine. **Output states** * `pending` while the registration is in progress, then a confirmation once it's active. * Registration can fail. A failed registration is a failed run, not a state to retry blindly — check `sumvin keys show` before trying again. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin keys add-to-safe --json ``` ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 0, "command": "keys add-to-safe", "data": { "address": "0x1234567890abcdef1234567890abcdef12345678", "signer_status": "active" } } ``` ## `sumvin keys show` Shows your local key's address and whether it's registered with your account. **Flags** | Flag | Effect | | - | - | | `--json` | Print a result object instead of the formatted view. | **Output states** * If you've generated a key, its address and registration status (registered, not registered, or unchecked if you're signed out). * If no key exists yet, the command says so and points at `sumvin keys generate`. ## Exit codes All three commands use `0` for success and `1` for failure — a registration that fails to settle is a failed run, not a negative answer. # sumvin kyc Source: https://docs.sumvin.com/reference/cli/kyc Verify your identity from the terminal. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. Verification is what unlocks the parts of Sumvin that need a verified person behind them. The CLI drives everything except two steps a human has to do: typing a code that arrives by SMS, and photographing a document in a browser. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin kyc start # verify your phone, then open the browser step sumvin kyc status # where verification has got to right now sumvin kyc status --wait # block until there's a result ``` Both commands need a signed-in session — see [`sumvin login`](/reference/cli/auth). `sumvin kyc start` can't be scripted. It needs a browser and a code sent by SMS. Build automation around `sumvin kyc status --json` instead. ## `sumvin kyc start` Checks where you already are, verifies your phone number if that hasn't happened yet, then opens a single-use browser link for the document step. **Flags** | Flag | Effect | | - | - | | `--phone ` | Your phone number, in international format. You're still prompted for the SMS code — there's no flag for that. | | `--json` | Print a result object instead of the running commentary. | **Example** ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin kyc start --phone +14155551234 ``` **Output states** * A fresh run prompts for your phone (if needed) and the SMS code, then prints a browser link that expires in about 15 minutes. * Re-running after an interruption picks up where you left off — it skips a phone step you already completed and reuses your existing verification record. * Already verified: the command tells you so and mints nothing. * Previously declined: the command refuses. A declined verification can't be retried with the same documents. ## `sumvin kyc status` Reports where verification has got to. Always exits successfully — it reports state, it doesn't judge it. **Flags** | Flag | Effect | | - | - | | `--wait` | Poll until there's a result instead of a snapshot. | | `--timeout ` | How long `--wait` keeps polling. Defaults to 15 minutes. | | `--refresh` | Ask the verification provider for a live answer. Ignored together with `--wait`. | | `--json` | Print the result object instead of the formatted view. | **Example** ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin kyc status --wait --timeout 30m ``` **The five statuses** | Status | Meaning | | - | - | | `pending` | You haven't started. | | `in_progress` | A verification is under way and hasn't returned a result. | | `retry` | More information was requested — resubmit with `sumvin kyc start`. | | `approved` | Verified. | | `rejected` | Declined. Terminal — the same documents can't be resubmitted. | Once approved, `sumvin kyc status` also reports whether your Sigil exists yet. "Not started" is a normal, expected answer here — see [Sigil](/reference/cli/sigil). **Exit codes** | Invocation | Result | Exit | | - | - | - | | `sumvin kyc status` | any status | `0` | | `sumvin kyc status --wait` | approved | `0` | | `sumvin kyc status --wait` | rejected, or more information requested | `2` | | `sumvin kyc status --wait` | timed out with no answer yet | `1` | ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin kyc status --wait --json ``` ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 0, "command": "kyc status", "data": { "status": "approved", "verified_at": 1754818264000, "rejected_at": null, "reject_reason": null, "sigil": { "did_mint_status": null, "did_token_id": null } }, "next": [ { "command": "sumvin sigil show", "reason": "See the full picture." } ] } ``` # Stamped Mandates (sumvin pint) Source: https://docs.sumvin.com/reference/cli/pint Create, list, revoke, and verify Stamped Mandates from the terminal. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. A Stamped Mandate is a signed authorisation for what an agent may do. This command group creates and manages the spending kind — how much an agent may spend, and until when — because that's what `pint` supports today. The command group is still named `pint` in the CLI — the rename to match the public name hasn't landed yet. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint create # create a Stamped Mandate sumvin pint list # list your Stamped Mandates sumvin pint get # show one in full sumvin pint revoke # revoke one sumvin pint verify # verify a Stamped Mandate token independently ``` ## `sumvin pint create` Creates a Stamped Mandate and prints the token. **Flags** | Flag | Required | Effect | | - | - | - | | `--scope ` | yes, repeatable | What the mandate grants. Your account or agent tells you the exact value to pass. | | `--statement ` | yes | Human-readable description of what the mandate authorizes. | | `--expires ` | no (default `24h`) | How long the mandate is valid — `30m`, `24h`, `7d`, and so on. | | `--max-amount ` | no (default `0`) | Spend cap. `0` authorizes no spend. | | `--max-amount-token ` | yes | The currency or token the cap is denominated in. | | `--sign local` | no | Sign the mandate yourself with a local key instead of letting Sumvin's agent sign it — see [`sumvin keys`](/reference/cli/keys). | | `--json` | no | Print a result object instead of the printed token. | **Example** ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint create \ --scope \ --statement "Delegate signing for one hour" \ --expires 1h \ --max-amount 0 \ --max-amount-token ``` **Output states** * Success prints the mandate's identifier, its token, who it's addressed to, its scopes, and its expiry. * Missing required flags, or a scope your account isn't verified for, are rejected before anything is created — see the errors below. ## `sumvin pint list` Lists your Stamped Mandates. **Flags** | Flag | Effect | | - | - | | `--status ` | Filter by status: `pending`, `active`, `expired`, `revoked`. | | `--limit ` / `--cursor ` | Paginate results. | | `--sort ` / `--order ` | Sort by creation or expiry, ascending or descending. | | `--json` | Print a result object instead of the formatted list. | ## `sumvin pint get` Shows one Stamped Mandate in full. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint get ``` **Flags** | Flag | Effect | | - | - | | `--expand ` | Include related records inline (repeatable). | | `--json` | Print a result object instead of the formatted view. | ## `sumvin pint revoke` Revokes a Stamped Mandate. Idempotent — revoking one that's already revoked succeeds without complaint. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint revoke ``` ## `sumvin pint verify` Verifies a Stamped Mandate token independently — its signature, claims, issuer, expiry, audience, scopes, and revocation status. All seven checks are always shown, so a broken signature is never confused with an expired or revoked token. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint verify "" ``` **Flags** | Flag | Effect | | - | - | | `--audience ` | Compare against a specific audience instead of your own account. | | `--offline` | Skip the network calls entirely. The audience and revocation checks then report as unverified rather than passing or failing. | | `--json` | Print a result object instead of the formatted checklist. | **Output states** * All seven checks pass: the mandate is valid. * Any check fails: the mandate is not valid, and the failing check is named — this is a completed, successful run whose answer is "no." ## Exit codes | Command | `0` | `1` | `2` | | - | - | - | - | | `create`, `list`, `get`, `revoke` | succeeded | failed | — | | `verify` | valid | the check itself couldn't complete | not valid | `sumvin pint verify` completing and reporting an invalid mandate is exit `2`, not `1` — the run succeeded, and the answer is no. Read the exit code, not just whether the command ran. ## Common errors | Message | Meaning | | - | - | | "Couldn't determine your account's spending identity." | Finish onboarding in the Sumvin app before creating a mandate. | | "Your account isn't verified yet for this scope." | Complete identity verification first — see [`sumvin kyc`](/reference/cli/kyc). | | "Mandate not found." | Check the ID, or run `sumvin pint list`. | # sumvin sigil Source: https://docs.sumvin.com/reference/cli/sigil Check the state of your Sigil from the terminal. **The CLI is for developers.** It's mainly for people building and experimenting on Sumvin. The recommended way to use Sumvin is the [MCP connector](/get-started/connect), or the API if you're building (docs coming). An agent running in your terminal can approve Stamped Mandates that the CLI signs for you. Never give an unattended agent `--yes`. Shows the state of your Sigil — your verified agent identity. This is a read-only group: a Sigil is issued automatically once verification finishes, so there's nothing to trigger here, only to check. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin sigil show ``` Needs a signed-in session — see [`sumvin login`](/reference/cli/auth). **Flags** | Flag | Effect | | - | - | | `--json` | Print a result object instead of the formatted view. | ## The six states | State | Meaning | | - | - | | `not_verified` | You haven't completed identity verification yet. | | `not_started` | You're verified, but nothing has started yet. This is a normal, common answer — it doesn't mean anything is wrong. | | `in_flight` | Your Sigil is being issued. Check back shortly. | | `failed` | Issuing didn't complete after repeated attempts. This needs support's attention, not another retry. | | `minted` | Your Sigil exists. | | `unknown` | This CLI build doesn't recognise the state your account returned. Update the CLI, or check the Sumvin app. | **Example** ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin sigil show --json ``` ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "ok": true, "exit_code": 0, "command": "sigil show", "data": { "state": "minted", "kyc_status": "approved" } } ``` `data.state` is the field to branch on — read it rather than the prose. ## Exit codes `0` for any of the six states above, including `failed` — reading your Sigil's state is a successful read even when the state itself isn't good news. `1` if you're not signed in or the read itself couldn't complete. See [Sigil](/concepts/sigil) for what a Sigil is and why it matters, and [`sumvin kyc`](/reference/cli/kyc) for the verification a Sigil depends on. # Errors Source: https://docs.sumvin.com/reference/errors Every error the Sumvin MCP connector can return, what it means, and what to do about each one. Every error Sumvin returns carries a short code, so an agent or a person can tell one failure from another without parsing prose. This page covers the codes you can meet through the MCP connector and the account setup it depends on. It isn't the full list Sumvin's systems use internally. ## Reading a code A code has three parts, and sometimes a fourth: `DOMAIN-STATUS-SEQUENCE`, then `-R` if the failure is worth retrying. * `MCP-401-001`: the area (`MCP`), the HTTP status it came with (`401`), and which failure in that area (`001`). No `-R`, so it's **terminal**: sending the same request again gets the same answer. Something has to change first: the credential, the input, a setting. * `MCP-429-001-R`: ends in `-R`, so it's **retryable**: the same request, sent again after a short wait, can succeed without anything changing. Honour `retry_after` when the error carries one, and back off between attempts. That's the whole rule, so a client can decide without a lookup table: retry when the code ends in `-R`, stop otherwise. ## What an error looks like A tool call that fails comes back as an error result. Its text leads with a message written for the agent, followed by the same error as JSON, and the JSON is also the result's structured content: ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "code": "KYC-503-002", "title": "Verification at daily capacity", "detail": "Identity verification has reached today's capacity. Wait for the daily allowance to reset at 00:00 UTC.", "retryable": false, "retry_after": 5400, "trace_id": "0af7651916cd43dd8448eb211c80319c", "_links": { "docs": { "href": "https://docs.sumvin.com/reference/errors#kyc-503-002" }, "sumvin:skill": { "name": "sumvin-sigil", "href": "skill://sumvin-sigil/references/errors.md#limits", "tool": "sumvin_guide", "args": { "name": "sumvin-sigil", "file": "references/errors.md" }, "why": "Which limits exist and what to tell the person." }, "next": { "tool": "kyc_start", "args": {} }, "support": { "href": "https://docs.sumvin.com/support" } } } ``` * `code`, `title` and `detail` say what went wrong. `detail` is specific to this call. * `retryable` is `true` exactly when the code ends in `-R`. `retry_after` is the number of seconds to wait when the error names one, and `null` otherwise. * `trace_id` identifies this call in Sumvin's logs. Quote it with the code if you [contact support](/support). * `_links.docs` is this code's entry on this page. `_links["sumvin:skill"]` names the guide to load, with the `sumvin_guide` call that loads it. `_links.next`, when present, is the call most likely to move things on. `_links.support` is how to reach Sumvin. ### Refused before the tool runs Some refusals happen at the connection, before any tool runs, and arrive as an HTTP status with a problem body rather than as the error above. Each has its entry below: * [`MCP-401-001`](#mcp-401-001) * [`MCP-429-001-R`](#mcp-429-001-r) * [`MCP-429-002-R`](#mcp-429-002-r) * [`MCP-503-001`](#mcp-503-001) The rest of this page groups the codes by the kind of fix they call for. ## Retryable Nothing about the request was wrong. Wait for `retry_after` seconds when it is set, or a few seconds when it is not, then send the same call again. Back off between attempts and stop after a few. ### `KYC-429-003-R` **Too many verification links this hour.** The person has asked for as many verification links as an hour allows. Have them finish with the latest link if it is still open; otherwise wait for `retry_after`. ### `KYC-503-003-R` **Verification briefly unavailable.** Identity verification could not confirm its capacity just now. Wait for `retry_after` and call again. ### `MCP-429-001-R` **Too many requests from this connection.** Wait for the `Retry-After` time, then send the same request again. ### `MCP-429-002-R` **Too many requests from this network address.** Wait for the `Retry-After` time, then send the same request again. ### `MCP-503-002-R` **Guide temporarily unavailable.** The guide could not be loaded just now. Try again in a minute, and carry on without it if it is still missing. ### `MCP-503-003-R` **A service Sumvin depends on is busy.** A service behind this tool timed out or asked Sumvin to slow down. Wait a few seconds and send the same call again. ### `MCR-503-002-R` **Approval check briefly unavailable.** The approval could not be checked just now. It clears on its own; check the outcome with `mandate_status` in a minute. ### `UST-503-001-R` **Strategy schedule not updated.** The schedule could not be saved just now. Wait a moment and send the same call again. ### `WAL-409-002-R` **Primary wallet changed at the same time.** Another change to the primary wallet landed first. Wait a moment and send the same call again. ### `WAL-409-003-R` **Wallet still being set up.** The smart wallet is still being set up. Wait a minute and send the same call again. ## Auth This connection has no credential Sumvin accepts. Ask the person to connect their Sumvin account to this app; retrying the call will not change the answer. ### `MCP-401-001` **Account not connected.** This connection has no Sumvin account behind it. Ask the person to connect their Sumvin account to this app, then carry on with what they asked. ### `MCR-401-001` **Approval needs a signature.** This is answered on the person's approval page, not to you. Tell them what it says and let them finish there; check the outcome with `mandate_status`. ### `MCR-401-002` **Approval signer not recognised.** This is answered on the person's approval page, not to you. Tell them what it says and let them finish there; check the outcome with `mandate_status`. ### `MCR-401-003` **Approval signer not registered.** This is answered on the person's approval page, not to you. Tell them what it says and let them finish there; check the outcome with `mandate_status`. ### `MCR-401-004` **Approval signer does not own the wallet.** This is answered on the person's approval page, not to you. Tell them what it says and let them finish there; check the outcome with `mandate_status`. ### `MCR-401-005` **Approval signature invalid.** This is answered on the person's approval page, not to you. Tell them what it says and let them finish there; check the outcome with `mandate_status`. ## Limits A limit was reached. Tell the person when it resets, using `retry_after` when it is set, and do not try again before then. ### `KYC-429-002` **Daily verification attempts used.** The person has used today's identity-verification attempts. Tell them when it resets, from `retry_after`, and do not try before then. ### `KYC-503-002` **Verification at daily capacity.** Sumvin has reached today's identity-verification capacity. Tell the person when it resets, from `retry_after`, and do not try before then. ## Verification The person has to verify something about themselves first, such as their phone number or their identity. Follow `next` when it is set; the guide explains each step. ### `KYC-403-001` **Identity not verified yet.** This needs the person's identity verified. If they have already submitted, it is being reviewed; check their status rather than asking them to submit again. Next: call `onboarding_status`. ### `KYC-403-002` **Identity verification not started.** This needs the person's identity verified, and they have not started. Hand them their verification link. Next: call `kyc_start`. ### `KYC-403-004` **Phone number not verified.** Identity verification needs a verified phone number first. `kyc_start` takes the person through both, phone first. Next: call `kyc_start`. ### `KYC-403-005` **Identity verification declined.** The reviewer decided not to verify this person, and that decision is final. Tell them, and point them to support if they believe it is wrong. ### `KYC-503-001` **Verification not set up here.** Identity verification is not configured in this environment. Nothing the person does will change that, so do not retry. ## Permission The credential behind this connection does not allow this. Do not retry with different arguments; the detail says what is missing and how the person can grant it. ### `MCP-403-001` **Connection does not allow this.** The person did not grant this connection the access this tool needs. The detail names it; the person grants it by reconnecting this app with that access. Use a tool the connection already covers meanwhile. ### `MCP-403-002` **Tool not available on this connection.** This connection does not serve that tool. Read the detail: it says whether the person needs an account first, or manages this in the Sumvin app. ### `MCP-403-003` **Account cannot be served.** The person's account cannot be used for this right now. The detail says why; relay it, and point them to support if they think it is wrong. ### `MCP-403-004` **No authorization for this action.** Nothing authorizes this agent to take this action for the person. Do not retry; ask the person whether they want to approve it. ### `MCR-403-001` **Mandate request belongs to someone else.** That request was made to a different person. Do not act on it. ### `PINT-403-001` **Approval does not cover this.** The person's approval for this agent does not include what this tool needs. Do not retry with other arguments; ask the person to approve the access the detail names. ### `PINT-403-007` **Asks for more than its parent allows.** This asks for more than the mandate it draws on authorises. Ask for less, or ask the person for a wider mandate. ### `PINT-403-008` **Parent mandate no longer usable.** The mandate this draws on has expired, been withdrawn or cannot be spent against. Read the person's mandates before going further. Next: call `pint_query`. ### `WAL-403-006` **Signing key cannot be primary.** That wallet is the key the account signs with, and cannot also be its primary wallet. Choose another wallet. ## Validation The arguments were not accepted. Read the detail, correct the arguments it names, and call again. Ask the person when the right value is not yours to guess. ### `BUD-400-003` **Budget period missing.** A budget of this kind needs a period. Include one and call again. ### `BUD-400-005` **Budget period too long.** The period is longer than a budget allows. Shorten it and call again. ### `CRD-400-001` **Card change not possible.** The card cannot move to that state from the one it is in. The detail says why; read the card before trying something else. ### `GEN-400-001` **Request not valid.** The tool could not use what it was given. The detail says what to change. ### `IPA-422-003` **Errand needs a spend limit.** An errand needs a spend limit the person has agreed to. Ask them for one, then create the errand with it. ### `MCP-422-001` **Invalid tool arguments.** The arguments do not match the tool's schema. The detail names each field and what is wrong with it; correct them and call again. ### `MCP-422-002` **Tool arguments not accepted.** The arguments were well formed but the tool could not use them, for example an unknown category. The detail lists what it accepts. ### `MCR-400-002` **Approval signature unreadable.** This is answered on the person's approval page, not to you. Tell them what it says and let them finish there; check the outcome with `mandate_status`. ### `MCR-422-001` **Mandate request not accepted.** The request could not be turned into something the person can approve. The detail says which part; fix it with the person and ask again. ### `MCR-422-002` **Mandate names the wrong wallet.** The request names a wallet that cannot hold this mandate. Check the person's wallets and ask with the right one. Next: call `wallet_query`. ### `MCR-422-003` **Mandate network not supported.** Mandates cannot be issued on that network. Ask with a supported one. ### `PINT-422-003` **Mandate contradicts how it was signed.** The mandate's contents and the way it was signed disagree. Do not retry it; ask the person to approve a new request. ### `PINT-422-004` **Mandate cannot be stated.** Sumvin could not state what this mandate would authorise, for example because a limit or currency is missing. The detail says which; fix it and ask again. ### `PINT-422-006` **Approval has expired.** The approval this draws on has expired, so nothing can be issued under it. Ask the person whether they want to approve a new request. Next: call `pint_query`. ### `UST-400-001` **Strategy needs a service connection.** This strategy needs a service connection the person has not set up. They set it up in the Sumvin app first. ### `WAL-400-001` **Not a wallet address that can be used.** That address cannot be used here; only a wallet the person signs with directly can. Check the address with the person. ### `WAL-400-004` **Primary network cannot change.** The primary wallet's network is fixed once set. Leave it as it is. ### `WAL-400-005` **Network not supported for wallets.** A smart wallet cannot be set up on that network. Use a supported one. ### `WAL-400-006` **Nothing to update.** The call named no change to make. Include the field you mean to change. ### `WAL-400-007` **Primary wallet cannot be demoted.** A primary wallet stops being primary only when another one is promoted. Promote the wallet the person wants instead. ## Not found Nothing by that name or identifier is visible to this connection. Check the identifier against a query tool's results before trying again. ### `BUD-404-001` **Budget not found.** No budget with that identifier is visible here. List the person's budgets to find the right one. ### `CON-404-001` **Connection to a service not found.** The service connection this needs is not set up for the person. They set it up in the Sumvin app. ### `CRD-404-001` **Card not found.** No card with that identifier is visible here. List the person's cards to find the right one. ### `IPA-404-001` **Errand not found.** No errand with that identifier is visible to this connection. List the person's errands to find the right one. Next: call `errand_query`. ### `MCP-404-001` **Unknown tool.** No tool has that name. Check it against `tools/list`, which returns everything this connection can call. ### `MCP-404-002` **Unknown guide.** No guide has that name. The detail lists the guides there are. Next: call `sumvin_guide` with `{"name": "sumvin-sigil"}`. ### `MCP-404-003` **Unknown guide file.** That guide has no file by that name. The detail lists its files; omit the file to load the guide itself. Next: call `sumvin_guide` with `{"name": "sumvin-sigil"}`. ### `MCR-404-001` **Mandate request not found.** No mandate request with that identifier is visible to this connection. Read the person's requests to find the right one. Next: call `mandate_status`. ### `PINT-404-001` **Mandate not found.** No mandate with that identifier is visible to this connection. List the person's mandates to find the right one. Next: call `pint_query`. ### `RUL-404-001` **Rule not found.** No rule with that identifier is visible here. List the person's rules to find the right one. ### `RUN-404-001` **Strategy run not found.** No run with that identifier is visible here. List the strategy's runs to find the right one. ### `STR-404-001` **Strategy not found.** No strategy with that identifier is visible here. List the strategies to find the right one. ### `WAL-404-001` **Wallet not found.** No wallet with that identifier is visible to this connection, or the account has no smart wallet yet. List the person's wallets to check. Next: call `wallet_query`. ## Conflict The thing you are acting on is not in a state that allows this. Read its current state with the matching query tool, then decide with the person what to do; sending the same call again will not help. ### `MCP-409-001` **Not ready for this action.** What you are acting on is not waiting for this action right now. Read its current state before deciding with the person what to do. Next: call `errand_query`. ### `MCP-409-002` **Cannot be cancelled now.** It has gone too far to cancel. Read its current state and tell the person what that means for them. ### `MCR-409-001` **Mandate request already answered.** The person has already answered this request. Read what they decided. Next: call `mandate_status`. ### `MCR-409-002` **Mandate no longer available.** The mandate behind this request can no longer be issued. Read the request's state and talk to the person about what they want. Next: call `mandate_status`. ### `MCR-409-003` **Too many open mandate requests.** The person already has as many requests waiting as are allowed. Read them, and let the person answer one before you ask for another. Next: call `mandate_status`. ### `MCR-410-001` **Mandate request expired.** The person did not answer in time, so the request lapsed. Ask them whether they still want it before you request it again. ### `PINT-409-002` **Mandate already withdrawn.** That mandate was already withdrawn, so there is nothing more to do to it. Next: call `pint_query`. ### `STR-409-001` **Strategy already on.** The person already has this strategy. There is nothing more to do. ### `USR-424-002` **Account setup not finished.** The person's account has no active signing key yet, so it cannot act. Check where their setup stands. Next: call `onboarding_status`. ### `UST-409-001` **Strategy not active yet.** The strategy is still being switched on. Read it again shortly. ## Server Something failed on Sumvin's side and retrying is not expected to help. Tell the person, and quote the `code` and `trace_id` if they contact support. ### `MCP-500-001` **Tool call failed.** The tool failed for a reason it cannot share. Do not retry it in a loop; tell the person, and quote the code and trace id if they contact support. ### `MCP-500-002` **Unrecognised refusal.** The tool refused with a reason this connection could not classify. The detail is what the tool said; tell the person, and quote the code and trace id if they contact support. ### `MCP-503-001` **Connector not set up here.** The connector is not configured in this environment. Nothing you or the person can change will fix it, so do not retry. ### `MCR-500-001` **Approval checking misconfigured.** Sumvin cannot check approvals because a setting is wrong. Nothing the person does will fix it; tell them. ### `MCR-503-001` **Mandates not set up here.** The approval page is not configured in this environment, so no mandate can be requested. Do not retry. ### `SYS-503-002` **Service not configured.** Sumvin could not authorize this request because the service is misconfigured. No argument change will help; tell the person. # Rate limits Source: https://docs.sumvin.com/reference/mcp/limits How the MCP connector limits requests, and how to handle a 429. The MCP connector limits how many requests it serves in a given window. There are two separate allowances, and either one can be reached independently: * **Per network address** — counted before any agent is identified, so a flood from one address is capped even before it authenticates. * **Per connected agent** — counted after the agent is identified, so several agents sharing a network address don't share this allowance, and one agent moving between addresses still has a single budget. Both are configured by Sumvin's operators and can change without notice, so this page doesn't publish exact numbers — they aren't fixed values you can rely on staying the same. ## When you're rate limited A request over either allowance gets back an HTTP `429` with a `Retry-After` header, given in seconds. Wait at least that long before trying again — retrying sooner gets the same refusal. ``` HTTP/1.1 429 Too Many Requests Retry-After: 30 ``` The two allowances carry different error codes so an agent can tell which one it hit — see [Errors](/reference/errors) for `MCP-429-001-R` and `MCP-429-002-R`. A `429` on this connector is availability protection, not a judgement about the request. Back off for the stated time and try again — there's nothing else to change about the call itself. # Refusals Source: https://docs.sumvin.com/reference/mcp/refusals What it means when a connected agent's tool call is refused, and what to do next. A connected agent's tool set is fixed (see [MCP tools](/reference/mcp/tools)), so calling something outside it always fails the same way: the tool is refused, not silently dropped. Every refusal names which of a small number of true reasons applies, and what to do about it. This page is for an agent reading a refusal it got back — it explains what each one means and what to try next. Most refusals come back as a normal tool result, not as a connection error. Read the result's text for the reason and the next step, rather than treating any error as the same kind of problem. The same result carries the [error object](/reference/errors#what-an-error-looks-like): its `code` has its own entry on the [Errors](/reference/errors) page, and its `_links` name the guide to load and the next call to make. ## The four refusals A connected agent's tools come from a small, named set. A call outside what this connection can use is refused for one of four distinct reasons — the reason matters, because "connect the account", "hand the person this sign-up link" and "ask the account holder to open the app" are different instructions. The connector has been added but no Sumvin account is connected to it yet. Tools are listed before anyone signs in, so a client can reach for one first. **What to do:** nothing in the conversation — the client is prompted to connect the account and asks the person to sign in or create a Sumvin account. Once they have, call the tool again. Code: [`MCP-401-001`](/reference/errors#mcp-401-001). The name called doesn't match anything this server serves, on any connection. Most often a typo. **What to do:** check the name against `tools/list`, which returns everything this connection can actually call. Don't guess a corrected name and retry blind. Code: [`MCP-404-001`](/reference/errors#mcp-404-001). The tool exists and the account holder can use it, but not from a connected agent — it's held for the Sumvin app or the CLI. No scope or credential makes it appear here. **What to do:** don't retry with different arguments. Tell the account holder to do this themselves, in the app or the CLI. Call `tools/list` to see what this connection does serve instead. Code: [`MCP-403-002`](/reference/errors#mcp-403-002). The tool needs an account, and the person being helped doesn't have one. Someone with no account is listed the same tools as everyone else, so this is the refusal any of them returns. **What to do:** the refusal carries a sign-up link — hand it to the person to open in their browser. Once they've signed up they can come back to the same conversation and carry on; the page they finish on also gives them a prompt to start a new conversation, if they'd rather. Don't retry tools until they say they've signed up. If the refusal carries no link, it points them at the Sumvin website instead. Code: [`MCP-403-002`](/reference/errors#mcp-403-002). ## Verify first A few tools need more than an account — they need a wallet set up, or the account holder's identity verified, before they'll do anything. [`mandate_request`](/reference/mcp/tools#mandate_request) is the clearest example: it checks these before asking the account holder to sign anything, so an unfinished setup never wastes their time on a request that couldn't be granted. A Stamped Mandate is granted against a wallet, and this account doesn't have one. **What to do:** tell the account holder to finish setting up their account, then ask again. Check [`onboarding_status`](/reference/mcp/tools#onboarding_status) for where they've got to. Code: [`WAL-404-001`](/reference/errors#wal-404-001). Spending authority needs the account holder's identity to be verified, and verification hasn't started. **What to do:** call [`kyc_start`](/reference/mcp/tools#kyc_start) to get the link, and ask them to complete it. Then try again. Code: [`KYC-403-002`](/reference/errors#kyc-403-002). Verification is underway but hasn't completed yet. Nothing has gone wrong. **What to do:** check back with [`onboarding_status`](/reference/mcp/tools#onboarding_status) once the account holder says they're done, then ask again. Code: [`KYC-403-001`](/reference/errors#kyc-403-001). ## Rate limited Too many requests in a short window gets a refusal with a wait time attached, not one of the reasons above. See [Limits](/reference/mcp/limits) for how to read it. ## General principle A refusal that names a true, specific reason is more useful to an agent than a bare failure — so read it before deciding what to try next. If a refusal says not to retry, don't: retrying gets the same answer until the underlying thing (an account, a wallet, a verified identity) changes. Every code an agent can meet, grouped by the kind of fix it needs, is on the [Errors](/reference/errors) page. # MCP tools Source: https://docs.sumvin.com/reference/mcp/tools Every tool a connected agent gets on the Sumvin MCP connector, grouped by what it's for. A connected agent doesn't see everything Sumvin can do. It sees a fixed set of tools, chosen for the account holder's own errands and identity — never budgets, card controls, or anything that isn't the agent's to touch. The account holder manages those in the Sumvin app or the CLI instead. These tools are visible before an account is connected, so a client can list them as soon as the connector is added. Each tool declares the OAuth scope it needs, and a client uses that to ask the person to connect their Sumvin account the first time a tool needs it. Calling a tool before then returns a refusal that asks the client to connect the account. Someone with no Sumvin account yet sees the same tools, but every one of them needs an account first. Calling any of them returns a refusal that carries a sign-up link to hand to the person — see [Refusals](/reference/mcp/refusals). Each tool is either **Read** (returns information, changes nothing) or **Write** (starts or changes something). Most tools work for anyone with an account; a few need the account holder's identity to be verified first — those are marked below. ## Getting started ### onboarding\_status Read Show where the account holder has got to in setting up their account: which steps are done, which are next, and how far the key they sign with has got. Reading it changes nothing. Each stage reads `current` (the one to do next), `pending` (still ahead), `submitted` (handed in and waiting on a review), `completed`, or `skipped` (waived for this account). The identity stage can also read `retry`: the reviewer asked for the ID capture again. The account holder retakes it on the verification page they already have open, and their phone stays confirmed. If that page is closed, call `kyc_start` for a fresh link. Or the identity stage can read `rejected`: the reviewer has made a final decision not to verify the account holder. Trying again won't change it, so your agent doesn't call `kyc_start` for them. It tells them plainly that their identity couldn't be verified and points them to Sumvin support. `recorded_at` is when the decision was made, and it stays final unless a reviewer later approves them. Each stage also carries `recorded_at`: when it reached its status, in epoch milliseconds. It's null while the stage is open, or when no time was recorded. While the account holder still owes a signing key, the answer carries `signing_key_url`: the browser page where they create and bind that key themselves. Your agent hands it to them to open; there's nothing it can call to bind the key on their behalf. **Try asking your agent:** "Where am I up to with Sumvin?" ### kyc\_start Write Get the link that starts identity verification, and hand it to the account holder. It's a single browser trip: they verify a phone number, then their identity, in one sitting. If they're already verified, this says so instead of handing over a link. If the reviewer has made a final decision not to verify the account holder, the call is refused with the code `KYC-403-005` and no link is made. Starting again won't change the decision, so your agent tells them plainly and points them to Sumvin support instead of retrying. **Try asking your agent:** "Help me get verified with Sumvin." ## Identity ### sigil\_show Read Show the account holder's Sigil — their verified identity. Reports whether it's been issued yet, is being issued right now, or hasn't started. Not having one yet is a normal answer, not a problem. **Try asking your agent:** "Show me my Sigil." ### agent\_identity\_show Read Show this connection's own identity: its registration status, and whether it's linked to the account holder's Sigil yet. Answers only for the connection asking — it can't see any other agent the account holder has connected. **Try asking your agent:** "What's your identity under my Sigil?" ## Stamped Mandates A Stamped Mandate is a signed authorisation for what one agent may do. These tools cover the spending kind — how much an agent may spend, and until when — because that's what the mandate tools support today. These tools still show their internal name, `pint`, in two places: it's the same object as a Stamped Mandate, and the rename is in progress. ### mandate\_request Write · Needs verification Ask the account holder to authorise spending, and get the link that lets them review and sign it. This doesn't grant anything by itself — only the account holder can sign, on their own page, and an agent can't do that for them. Needs a wallet and a verified identity first; if either is missing, this says which one and where to go next. **Try asking your agent:** "Set up a spending limit of \$50 for groceries this week." ### mandate\_status Read Check what the account holder decided about a mandate that was requested: still waiting, signed, declined, or expired. There's no notification when they decide — call this again after giving them time to look. **Try asking your agent:** "Did I approve that spending limit yet?" ### mandate\_verify Read Check a Stamped Mandate someone else has presented: what it permits, up to how much, and whether it still stands. Use this before acting on a mandate a counterparty shows you — an identifier alone proves nothing, and a mandate can be withdrawn at any time after it's granted. **Try asking your agent:** "Check whether this mandate is still valid before we go ahead." ### mandate\_capacity\_query Read Read what's left to spend under the Stamped Mandate authorising an errand: its limit, what's settled, what's held by spending in flight, and what remains. **Try asking your agent:** "How much is left on the mandate for my grocery errand?" ### pint\_query Read List the Stamped Mandates issued to the account holder. Filter by status or by identifier. **Try asking your agent:** "Show me all my active spending limits." ### pint\_revoke Write Permanently withdraw a Stamped Mandate. This can't be undone — anything relying on it to spend stops being able to, immediately. Find the one to revoke with `pint_query` first. **Try asking your agent:** "Revoke the spending limit I set up for groceries." ## Payment methods An errand pays with the card the account holder has added. These tools let an agent check that a card is ready and, when it isn't, send the account holder to the page where they add one. The card is always entered on that page, by the account holder — never in the conversation. ### payment\_method\_query Read List the cards the account holder has added and whether each is ready. A card can pay for an errand only once it shows as verified. Card numbers are never shown — only the last four digits. **Try asking your agent:** "Is my card ready for purchases?" ### payment\_method\_add Read Get the link to the page where the account holder adds the card their errands pay with, along with the cards they already have. The tool changes nothing itself. A card can be added once identity verification has finished; wait for it to show as verified before starting an errand. **Try asking your agent:** "I need to add a card before you buy anything for me." ## Errands An errand is a long-running purchase task the account holder asked their agent to make, run within a Stamped Mandate. ### errand\_create Write Start a new errand from what the account holder asked for, in their own words, with the most they'll spend: `constraints.max_total` (whole purchase) or `constraints.max_price` (per item), plus `constraints.currency`. Without a spend limit the errand isn't created (`spend_limit_required`). Starting an errand doesn't authorise any spending on its own: the account holder asks, signs, and only then does Sumvin search, check the merchant, watch for their conditions, and settle the purchase. **Try asking your agent:** "Reorder my usual coffee beans." ### errand\_action Write Act on an errand that's already running: answer a question it's waiting on, or cancel it. Signing an errand isn't available here — only the account holder can sign it, before it searches, on their own page. A pick found within the bounds they signed is then bought without asking them again. **Try asking your agent:** "Cancel that coffee order — I changed my mind." ### errand\_query Read Read the account holder's errands: what they are, and where each one stands. Filter by status or by identifier. **Try asking your agent:** "What's the status of my coffee order?" ### errand\_events\_query Read Read one errand's history: what happened, and when, oldest first. **Try asking your agent:** "What's happened so far with my coffee order?" ## Account ### account\_query Read Read the account holder's linked accounts. **Try asking your agent:** "What accounts do I have linked?" ### wallet\_query Read Read the account holder's wallets. **Try asking your agent:** "Show me my wallets." ### transaction\_query Read Read the account holder's transactions: what they spent, where, and when. **Try asking your agent:** "What have I spent this week?" ### asset\_query Read Read reference data for the currencies and assets Sumvin supports. Not scoped to the account holder — this is general information, not a personal record. **Try asking your agent:** "What currencies does Sumvin support?" ## Server ### server\_info Read · No account needed Report the build identity of the Sumvin server this connection has reached. Useful for confirming the connection is live before trying anything else. **Try asking your agent:** "Are you connected to Sumvin?" ### sumvin\_guide Read · No account needed Load a Sumvin guide: what Sumvin is, how to use its tools safely, and the reference file for each task. Pass `name` (`sumvin-sigil`, or `sumvin-sigil-onboard` for someone without an account yet), and `file` for one of its reference files. It's the same content a host that supports skills installs from `skill://sumvin-sigil`, so a host that only calls tools still gets it. **Try asking your agent:** "How do you use Sumvin?" ## In the Sumvin app and CLI These tools answer only when the account holder's own Sumvin app or the Sumvin CLI calls the server. A connected agent never sees them: calling one from a connector is refused, and the refusal says to manage it in the app or the CLI instead. ### allocations\_query Read List what has been spent against an errand's mandate, newest first, and whether each spend has settled. ### budget\_query Read Read the account holder's budgets, by name, type, or the kind of spending they cover. ### budget\_upsert Write Create a budget, or replace one in full. ### budget\_delete Write Delete a budget. It stops counting spending; its history is kept. ### card\_query Read Read the account holder's cards and their current status. ### card\_action Write Freeze a card, or unfreeze it. Neither cancels the card or touches payments already made. ### rule\_query Read Read the account holder's rules. ### rule\_upsert Write Create a rule, or replace one in full. ### rule\_delete Write Delete a rule. It stops applying from then on. ### strategy\_list Read List the strategies the account holder can enrol in. ### user\_strategy\_query Read Read the strategies the account holder is enrolled in. ### user\_strategy\_create Write Enrol the account holder in a strategy, after checking that whatever it needs is in place. ### user\_strategy\_update Write Pause or restart an enrolment, or adjust its settings. ### user\_agent\_task\_query Read Read the runs queued or completed for the account holder's strategies. ### user\_agent\_task\_manage Write Queue a strategy run, or cancel one that hasn't started. ### wallet\_update Write Rename a wallet, or make it the account holder's main one. # Status labels Source: https://docs.sumvin.com/reference/status-labels What Live, Private preview and Coming soon mean on a documentation page. Every page in this documentation carries one of three labels, so you always know what to expect before you rely on it. Working today, as documented. You can connect to it, call it, or follow it right now. Rolling out. The page describes what it does or will do, but it may not be available on your account yet, and details can still change before it's generally available. Not part of this preview. The page describes what's on the way so you can plan for it. Payments are coming soon in a fast-follow release, with its own waitlist. An errand goes ask, sign, search, check the merchant, watch, settle: signing from the connector and the settle step arrive with payments. A page with no label anywhere on it is Live — the label only appears where it changes what you should expect. If a Private preview page doesn't work the way you'd expect on your account, that's the label doing its job, not a bug to report yet. # List and disconnect agents Source: https://docs.sumvin.com/sdk/agents/agent-identities List the agents connected under a person's Sigil and disconnect one. **Private preview:** this is rolling out and may not be available on your account yet. **First-party only today.** These calls need a personal access token, which isn't yet open to third-party apps. See [Sign in](/sdk/agents/sign-in). Each agent a person connects gets its own [agent identity](/concepts/agent-identities) under their Sigil. The person can see every one and disconnect any of them. Only the person can do this. A request made on their behalf, such as one carrying a Stamped Mandate token, is refused, so one agent can't discover or disconnect another, or itself. ## List connected agents ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { listAgentIdentities, unwrap } from "@sumvin/sdk"; const { data } = unwrap(await listAgentIdentities({ client })); for (const agent of data) { console.log(agent.id, agent.client_id, agent.status, agent.created_at); } ``` | Field | Means | | - | - | | `id` | The agent identity's identifier. Use it to disconnect. | | `client_id` | The application the agent was connected through. | | `status` | `pending` while it is being set up, `active` when live, `failed` if setup didn't finish, `retired` once disconnected. | | `generation` | How many times this application has been connected. It goes up each time it is connected again after a disconnect. | | `created_at` | When it was connected, in epoch milliseconds. | ## Disconnect an agent ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { revokeAgentIdentity } from "@sumvin/sdk"; const { error } = await revokeAgentIdentity({ client, path: { external_id: agent.id } }); ``` The agent stops being honoured straight away, including any access it already held. Disconnecting an agent that is already disconnected changes nothing. # Errands Source: https://docs.sumvin.com/sdk/agents/errands Start and follow purchase errands from the SDK. Not part of this preview. **Coming soon:** payments arrive in a fast-follow release. An [errand](/concepts/errands) is a purchase an agent carries out under a Stamped Mandate. The SDK already contains the errand operations, under the older wire name `ipa`: `createIpa`, `listIpas`, `getIpa`, `getIpaEvents`, `clarifyIpa` and `cancelIpa`. This page will document them when payments arrive. Until then, run errands through the [MCP connector](/get-started/first/errand). # Sign in as a person Source: https://docs.sumvin.com/sdk/agents/sign-in Sign a person in through their browser, get a personal access token, and authenticate SDK calls with it. **Private preview:** this is rolling out and may not be available on your account yet. **First-party only today.** Personal access tokens are issued to Sumvin's own apps and approved clients. They are not yet open to third-party apps, so an outside developer can't complete this flow. To give your own agent access to Sumvin, use the [MCP connector](/get-started/connect) or the [CLI](/get-started/cli/install). Acting for a person takes one credential: a **personal access token**. The person approves it in their own browser; your code never sees their password. `deviceLogin` needs an unauthenticated client. It calls `onUserCode` once, with the address and short code to show the person, then waits for them to approve. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { createSumvinClient, deviceLogin } from "@sumvin/sdk"; const signInClient = createSumvinClient({ baseUrl: "https://api.sumvin.com" }); const credential = await deviceLogin({ client: signInClient, onUserCode: ({ verificationUri, userCode }) => { console.log(`Open ${verificationUri} and enter ${userCode}`); }, }); ``` Show the address and code before you do anything else, such as opening a browser, so a person on a remote terminal can still sign in. `deviceLogin` returns the token and never stores it. Keep `credential.token` wherever you keep secrets. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { createSumvinClient, sumvinPat } from "@sumvin/sdk"; const client = createSumvinClient({ baseUrl: "https://api.sumvin.com", auth: [sumvinPat(() => readStoredToken())], }); ``` `sumvinPat` takes the token, or a function that returns it. In production, personal access tokens only work from approved Sumvin clients, identified by their user-agent. A request that carries the token from any other client, or with no user-agent, is refused with `403` and code `CLI-403-001`. ## When sign-in fails Each failure is its own error class, and all of them extend `DeviceLoginError`. | Error | Means | | - | - | | `DeviceLoginExpiredError` | The sign-in request expired, was declined, or was already used. Start again. | | `DeviceLoginNotFoundError` | The API doesn't recognise this sign-in request. | | `DeviceLoginConflictError` | Another process already finished this sign-in. | | `DeviceLoginTimeoutError` | Nobody approved it before it expired. | To stop waiting, pass an `AbortSignal` as `signal`. ## Carrying a Stamped Mandate An agent that holds a [Stamped Mandate](/concepts/stamped-mandates) token sends it with `pintToken`. It always travels **alongside** the personal access token, never instead of it: a request with only a mandate token is refused. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { createSumvinClient, pintToken, sumvinPat } from "@sumvin/sdk"; const client = createSumvinClient({ baseUrl: "https://api.sumvin.com", auth: [sumvinPat(() => readStoredToken()), pintToken(() => currentMandateToken())], }); ``` A mandate token only ever narrows what the request may do. It never grants more than the person's own access. # Read and revoke Stamped Mandates Source: https://docs.sumvin.com/sdk/agents/stamped-mandates List a person's Stamped Mandates, read one in full, see who it was issued to, and revoke it. **Private preview:** this is rolling out and may not be available on your account yet. **First-party only today.** These calls need a personal access token, which isn't yet open to third-party apps. See [Sign in](/sdk/agents/sign-in). A [Stamped Mandate](/concepts/stamped-mandates) is a signed authorisation for what an agent may do. The SDK's functions still carry the older wire name, `pint`: `listPints` lists Stamped Mandates. Every call below reads or changes the signed-in person's own mandates. Nobody else's are visible. ## List mandates Mandates are listed per wallet, so `listPints` needs the address of the wallet the person's mandates belong to. Get it from `listWallets`: it is the person's primary account wallet. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { listPints, listWallets, unwrap } from "@sumvin/sdk"; const { wallets } = unwrap(await listWallets({ client, query: { is_eoa: false } })); const wallet = wallets.find((w) => w.is_primary); if (!wallet) throw new Error("This account has no primary wallet yet."); const page = unwrap(await listPints({ client, query: { wallet: wallet.address } })); for (const { pint } of page.data) { console.log(pint.id, pint.status, pint.scopes); } ``` A person's account wallet is created after they finish [verification](/get-started/first/verify). Until then, `listWallets` succeeds but returns no account wallet, so they have no mandates to list. The wallet is created in the background, so it may not appear straight after verification; check again later. | Query | Default | Values | | - | - | - | | `wallet` | required | The wallet address. | | `status` | `active` | `pending`, `active`, `consumed`, `revoked`, `expired`. See [States](/concepts/mandates/verification#states). | | `sort` | `created_at` | `created_at` or `expires_at`. | | `order` | `desc` | `asc` or `desc`. | | `limit` | `20` | 1 to 50. | | `cursor` | none | The `cursor` from the previous page, when `has_more` is `true`. | ## Read one mandate ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { getPint } from "@sumvin/sdk"; const { pint } = unwrap(await getPint({ client, path: { pint_id: mandateId } })); ``` `mandateId` is the mandate identifier, such as `sr:us:pint:3f9c2a7e5b1d4c8e9a6f0b2d7e4c1a58`. You can only read your own. To show what a mandate allows in plain numbers, use the [ceiling reader](/sdk/verify/reading-scopes). The scopes themselves are described in [Scopes](/concepts/mandates/scopes). ## See who it was issued to A mandate can be issued as a token to more than one party. `listPintTokens` lists each one: who it is addressed to, when it was issued, when it expires, and whether it was revoked. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { listPintTokens } from "@sumvin/sdk"; const tokens = unwrap(await listPintTokens({ client, path: { pint_id: mandateId } })); ``` ## Revoke a mandate ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { revokePint } from "@sumvin/sdk"; const { error } = await revokePint({ client, path: { pint_id: mandateId } }); ``` Revoking is immediate and can't be undone. Every token issued against the mandate stops working with it. Revoking one that is already revoked returns `409` with its current state. ## Requesting a new mandate A new mandate is always approved by the person, with their passkey, in their own browser. Ask for one through the [MCP connector](/guides/set-limits) or the [CLI](/reference/cli/pint). # Make a client Source: https://docs.sumvin.com/sdk/client Create a Sumvin API client with createSumvinClient and pass it to every operation. **Private preview:** this is rolling out and may not be available on your account yet. Every call goes through a client you create once with `createSumvinClient`. Each operation takes that client as `{ client }`. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { createSumvinClient, listAgentIdentities } from "@sumvin/sdk"; const client = createSumvinClient({ baseUrl: "https://api.sumvin.com", auth: [/* see Sign in */], }); const { data, error } = await listAgentIdentities({ client }); ``` ## Options | Option | Required | What it does | | - | - | - | | `baseUrl` | Yes | The API address. | | `auth` | No | How requests authenticate. Leave it out for an unauthenticated client. See [Sign in](/sdk/agents/sign-in). | | `fetch` | No | Your own `fetch`, for proxies or runtimes where you don't want the global one. | | `headers` | No | Headers added to every request. | | `validation` | No | Response validation settings. Validation is on by default. | | `timeoutMs` | No | A per-request timeout, in milliseconds. No timeout by default. | ## What a call returns Each operation returns `{ data, error }`. Check `error` before you use `data`, or pass the result to `unwrap`, which returns `data` or throws. See [Errors](/sdk/errors). ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { unwrap } from "@sumvin/sdk"; const identities = unwrap(await listAgentIdentities({ client })); ``` # Handle errors Source: https://docs.sumvin.com/sdk/errors Catch every SDK error in one place and branch on its kind, status or error code. **Private preview:** this is rolling out and may not be available on your account yet. Every error the SDK throws or returns extends one base class. Catch with `isSumvinError`, then narrow. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { isApiError, isContractDriftError, isSumvinError, unwrap } from "@sumvin/sdk"; try { const identities = unwrap(await listAgentIdentities({ client })); } catch (e) { if (!isSumvinError(e)) throw e; if (isApiError(e)) { console.error(e.kind, e.status, e.errorCode); } else if (isContractDriftError(e)) { console.error(e.operationKey, e.reason); } } ``` | Guard | Means | | - | - | | `isApiError` | The request failed: the API answered with an error, or the network or transport failed. | | `isContractDriftError` | The API answered, but the response didn't match the shape the SDK expects. | The two never overlap, so check `isSumvinError` first and then each one. ## Kinds of request failure `ApiError.kind` is one of: | Kind | Means | | - | - | | `problem` | The API returned an error body with an error code. Read `errorCode` and `status`. | | `http` | An HTTP error with no error body. Read `status`. | | `network` | The request never got an answer. | | `abort` | The request was cancelled or timed out. | | `redirect-refused` | The API answered with a redirect, which the SDK refuses. | ## Branch on codes, not messages `message` is a diagnostic for developers. Build what your users see from `errorCode`, `status` and `kind`. The codes are listed in [Errors](/reference/errors). # Install the SDK Source: https://docs.sumvin.com/sdk/install Add @sumvin/sdk to a project, check your runtime, and pick the entry point you need. **Private preview:** this is rolling out and may not be available on your account yet. ```bash bun theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} bun add @sumvin/sdk ``` ```bash npm theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} npm install @sumvin/sdk ``` ```bash pnpm theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} pnpm add @sumvin/sdk ``` The package ships ESM and CommonJS builds with type definitions. Its only runtime dependency is `zod`. ## Runtimes | Runtime | Supported | | - | - | | Node.js 20 or later | Yes | | Evergreen browsers | Yes | | Cloudflare Workers | Yes | | Bun | Works, but the SDK's own test suite does not yet run under Bun in CI | ## Entry points | Import | What's in it | Extra packages | | - | - | - | | `@sumvin/sdk` | Every API operation, its types and schemas, plus authentication, errors and the ceiling reader. | None | | `@sumvin/sdk/react` | Query options for TanStack Query. | `react`, `@tanstack/react-query` | | `@sumvin/sdk/testing` | `fakeFetch`, for tests only. See [Testing](/sdk/testing). | None | ## Next Point the SDK at the API and choose how it authenticates. # TypeScript SDK Source: https://docs.sumvin.com/sdk/overview What the Sumvin TypeScript SDK does, the two jobs it covers, and who can use each part today. **Private preview:** this is rolling out and may not be available on your account yet. `@sumvin/sdk` is the TypeScript SDK for the Sumvin API. It gives you every API operation as a typed function, plus a small layer on top: authentication, one way to handle errors, and a reader for the limits a [Stamped Mandate](/concepts/stamped-mandates) carries. The SDK is open source at [github.com/Sumvin/sdk-ts](https://github.com/Sumvin/sdk-ts) and published on npm as [`@sumvin/sdk`](https://www.npmjs.com/package/@sumvin/sdk). ## Two jobs Sign in as a person and read or revoke their Stamped Mandates and connected agents. An agent shows you a Stamped Mandate. Check it offline and online before you act on it. ## Who can use what today | Part | Who can use it today | | - | - | | **Act for a person** | Sumvin's own apps and approved clients. Personal access tokens are not yet open to third-party apps. If you are building your own agent, connect it through the [MCP connector](/get-started/connect) or the [CLI](/get-started/cli/install) instead. | | **Check a mandate** | Any site can check a token addressed to its own website, with no key. Checks addressed to an organisation need a key from the developer dashboard, which is by invitation during the preview. These checks are plain HTTP calls and a standard JWT library; the SDK has no verification function yet. The SDK's [ceiling reader](/sdk/verify/reading-scopes) helps you read what a mandate allows. | ## Next Add the package and check your runtime. Get a key, then check a mandate offline and online. # Test your integration Source: https://docs.sumvin.com/sdk/testing Run SDK calls in your tests with no network, using fakeFetch from @sumvin/sdk/testing. **Private preview:** this is rolling out and may not be available on your account yet. `fakeFetch` is the scripted transport the SDK's own tests run on. Give it the responses you want, pass its `fetch` to your client, and read back the requests your code sent. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { createSumvinClient, listAgentIdentities, sumvinPat } from "@sumvin/sdk"; import { fakeFetch } from "@sumvin/sdk/testing"; const f = fakeFetch([{ status: 200, body: { _links: {}, data: [], offset: 0, limit: 20, total: 0 } }]); const client = createSumvinClient({ baseUrl: "https://api.test", fetch: f.fetch, auth: [sumvinPat("pat_test")], }); const { error } = await listAgentIdentities({ client }); expect(error).toBeUndefined(); expect(f.last().headers.get("x-sumvin-pat")).toBe("pat_test"); ``` Authentication, response validation, error handling and link following all run as they would against the API, so a test can check them end to end. `@sumvin/sdk/testing` is for tests only. It is kept out of the main entry point so it can't end up in a production bundle; don't import it from production code. # Get a key from the developer dashboard Source: https://docs.sumvin.com/sdk/verify/api-key Get an API key from the Sumvin developer dashboard, which is by invitation during the preview, and find your Organisation ID. **Private preview:** this is rolling out and may not be available on your account yet. A token an agent addresses to your website needs no key: you check it offline. A key is only for a service that already holds the signed request a person approved, for example for its own app. To [exchange that request](/sdk/verify/quickstart#services-that-already-hold-the-signed-request) and check it online, you need two things from the developer dashboard: an **API key** and your **Organisation ID**. **Developer dashboard access is by invitation during the preview.** You can't sign up yourself yet. Once you're invited, sign in at [dash.sis.sumvin.com](https://dash.sis.sumvin.com/sign-in). Your organisation has its own identifier. Open **Environments** and create one, for example `development`. Every key belongs to an environment, so you need at least one. Open **API Keys** and select **Create key**. Choose **Standard SIS Key**, pick your environment, and name the key after where it will run, such as `local-dev`. Copy the key when it is shown. It is shown once; if you lose it, revoke it and create another. A Standard key can both exchange a Stamped Mandate for a token addressed to you and check it online. A **Public RPC Key** can do neither. Open **Organisation → Settings**. The **Organisation ID** there is the audience your tokens are addressed to. You pass it to every offline check of a token addressed to your organisation. Keep the key on your server. Anyone holding it can act as your organisation. Never put it in a browser, a mobile app or source control. ## Use the key Send it as a bearer token: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} curl "https://sis.sumvin.com/v0/sis/pint/sr%3Aus%3Apint%3Atest/status" \ -H "Authorization: Bearer $SUMVIN_API_KEY" ``` A `404` with code `PINT-404-001` here means the key works: no mandate with that identifier has a token addressed to your organisation. A `401` or `403` means the key or its permissions are wrong; see [Checks and errors](/sdk/verify/checks#errors). ## Next Check a Stamped Mandate, and exchange a signed request you already hold. # Checks and errors Source: https://docs.sumvin.com/sdk/verify/checks Every step of checking a Stamped Mandate as a verifier: the offline check, and for services that hold the signed request, the exchange and online check, with their responses and error codes. **Private preview:** this is rolling out and may not be available on your account yet. This page is the reference for the [verifier quickstart](/sdk/verify/quickstart). An agent presents a Stamped Mandate as a token in the `x-sumvin-pint-token` request header, with no `Bearer` prefix, addressed to your site's hostname. You check it offline, on your own server, with no key. The exchange and the online check are only for a service that already holds the signed request a person approved, for example for the service's own app. An agent never sends a site the signed request. Both calls authenticate with your API key as `Authorization: Bearer `. | Step | Where | Key permission | | - | - | - | | Read the token | The `x-sumvin-pint-token` header on the agent's request | None | | Offline check | Your server, with `https://jwks.sumvin.com/.well-known/jwks.json` | None | | Exchange (signed request holders only) | `POST https://sis.sumvin.com/v0/sis/token/pint` | Exchange, included in a Standard key | | Online check (signed request holders only) | `GET https://sis.sumvin.com/v0/sis/pint/{id}/status` | Read mandates, included in a Standard key | ## Offline check Verify the token with any standard JWT library against: | Setting | Value | | - | - | | Key set | `https://jwks.sumvin.com/.well-known/jwks.json` | | Algorithm | `ES256` | | Issuer | `https://sis.sumvin.com` | | Audience | Your hostname, such as `reservations.example.com`, or your Organisation ID for a token from the exchange | Pin the algorithm to `ES256`, the only one Sumvin signs with, so a token signed any other way is refused rather than trusted. Pick the key by the identifier in the token's header, and let the library refresh the key set: keys rotate, so never copy one into your code. A token that fails any part of the check is a refusal. **Coming soon:** an online check for tokens addressed to a website. Until then, the offline check is the whole check: it tells you the token is genuine, addressed to you and unexpired, but not whether the person has revoked it since. ### From the CLI The [CLI](/reference/cli/pint) runs the same check: ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} sumvin pint verify "" --offline --audience "" ``` With `--offline` it makes no Sumvin API calls, so the revocation check reports as unverified. An unverified check never counts as a pass, so the overall answer is no and the command exits `2`; read the signature, issuer, expiry and audience lines individually. The CLI's own revocation check only answers for mandates you own. The CLI is itself in [Private preview](/get-started/cli/install). ## Exchange For a service that already holds the person's signed request. Send the signed request the person approved, unchanged, with `audience` set to your Organisation ID. Any other audience is refused. During the preview, some mandates can't be exchanged yet; those return `PINT-403-009`. | Answer | Means | | - | - | | `201` | A token addressed to your organisation was issued. | | `208` | This request was already exchanged for your organisation. The body is the same token. | The body carries `sig` (the token), `id` (the mandate identifier), `scopes` and `expires_at` (epoch milliseconds). One signed request can be exchanged by up to ten parties, each getting its own token addressed to itself. When the mandate expires or the person revokes it, every token issued against it stops working together. The person's verification is checked again at every exchange. A request signed while they were verified yields nothing new if their verification has lapsed since. ## Online check For a token from the [exchange](#exchange), addressed to your organisation. ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} curl "https://sis.sumvin.com/v0/sis/pint/$(printf %s "$MANDATE_ID" | jq -sRr @uri)/status" \ -H "Authorization: Bearer $SUMVIN_API_KEY" ``` URL-encode the mandate identifier: it contains colons. ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} { "_links": { "self": { "href": "/v0/sis/pint/sr%3Aus%3Apint%3A3f9c2a7e5b1d4c8e9a6f0b2d7e4c1a58/status" }, "pint": { "href": "/v0/sis/pint/sr%3Aus%3Apint%3A3f9c2a7e5b1d4c8e9a6f0b2d7e4c1a58" } }, "id": "sr:us:pint:3f9c2a7e5b1d4c8e9a6f0b2d7e4c1a58", "valid": false, "reason": "revoked", "revoked_at": 1758620000000 } ``` | Field | Means | | - | - | | `valid` | `true` when the mandate is neither revoked nor expired. **Act only on `true`.** | | `reason` | `null` when valid; otherwise `revoked` or `expired`. | | `revoked_at` | When it was revoked, in epoch milliseconds. Only set when revoked. | Rules of the online check: * **It answers only for mandates addressed to you.** A mandate with no token addressed to your organisation returns `404`, whether or not it exists. This is how one verifier is kept from probing another's mandates. * **Answers can be up to 30 seconds old.** The answer for each mandate is cached per organisation for 30 seconds. * **`valid` is this mandate's own state.** The fuller *stands* answer in [What a verifier checks](/concepts/mandates/verification#stands-not-status) also accounts for any larger mandate this one was narrowed from. That answer is available through the connector's `mandate_verify` tool; see [Check a mandate](/guides/check-a-mandate). To read the mandate's scopes, status and expiry, call `GET https://sis.sumvin.com/v0/sis/pint/{id}` with the same key. It follows the same rule: `404` unless a token for the mandate is addressed to your organisation. ## Errors Errors come back as a problem document with an error `code`, except a missing `Authorization` header, which returns `401` with `{"detail": "Not authenticated"}`. | Status | Code | Means | What to do | | - | - | - | - | | `401` | `SIS-401-001` | The key is invalid, expired or revoked. | Check the key, or create a new one. | | `401` | `SIS-401-002` | The key isn't attached to an organisation. | Create the key from the developer dashboard. | | `403` | `SIS-403-003` | The key lacks the permission this call needs. | Use a Standard key. | | `404` | `PINT-404-001` | No mandate with this identifier has a token addressed to your organisation. | Don't act. | | `400` | `PINT-400-002` | Exchange: `audience` isn't your Organisation ID. | Set it to your Organisation ID. | | `403` | `PINT-403-009` | Exchange: during the preview, some mandates can't be exchanged yet, and this is one of them. | Don't act. | | `409` | `PINT-409-002` | Exchange: the mandate has been revoked. | Don't act. | | `409` | `PINT-409-007` | Exchange: the signed request has already reached as many parties as it can. | Ask for a new mandate. | | `410` | `PINT-410-001` | Exchange: the mandate has expired. | Don't act. | More codes are listed in [Errors](/reference/errors). # Check a Stamped Mandate Source: https://docs.sumvin.com/sdk/verify/quickstart Before you act for an agent, check the Stamped Mandate token it sends your site, offline on your own server. **Private preview:** this is rolling out and may not be available on your account yet. An agent asks your site to do something and shows you a [Stamped Mandate](/concepts/stamped-mandates) as proof that a verified person allowed it. The agent sends it as a token addressed to your site's hostname. You check it on your own server, offline, against Sumvin's published keys: the token never leaves your server, and you need no API key. A passing check tells you the token is genuine, addressed to you and unexpired, and that the person approved exactly its [scopes](/concepts/mandates/scopes). A token addressed to a hostname carries identity attestations only: proof of personhood, verification status, over 18. It never tells you the person's name or contact details. See [What a verifier checks](/concepts/mandates/verification). These checks use plain HTTP and a standard JWT library. The SDK has no verification function yet. ## What the agent sends The agent sends the token in the `x-sumvin-pint-token` request header. The value is the bare token, with no `Bearer` prefix: ```http theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} x-sumvin-pint-token: ``` The token is addressed to one hostname, such as `reservations.example.com`. Accept only a token addressed to your own. ## Before you start * A JWT library. This page uses [`jose`](https://github.com/panva/jose): `bun add jose` or `npm install jose`. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} const token = request.headers.get("x-sumvin-pint-token"); if (!token) throw new Error("No Stamped Mandate presented"); ``` A request without the header carries no mandate. Treat it as any other unauthenticated request. Verify the token against Sumvin's published key set, with your hostname as the audience. The keys rotate, so let your library fetch and cache them rather than copying them. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { createRemoteJWKSet, jwtVerify } from "jose"; const sumvinKeys = createRemoteJWKSet( new URL("https://jwks.sumvin.com/.well-known/jwks.json"), ); await jwtVerify(token, sumvinKeys, { algorithms: ["ES256"], issuer: "https://sis.sumvin.com", audience: "reservations.example.com", }); ``` Pin the algorithm to `ES256`, the only one Sumvin signs with, so a token signed any other way is refused rather than trusted. `jwtVerify` throws if the token was altered, wasn't issued by Sumvin, isn't addressed to you, or has expired. Treat any throw as a refusal. **Coming soon:** an online check for tokens addressed to a website. Until then, the offline check is the whole check: it tells you the token is genuine, addressed to you and unexpired, but not whether the person has revoked it since. A token that passes its check still permits only what its scopes say. Compare them with what the agent is asking for, and act on nothing more. Any refusal means don't act. ## Services that already hold the signed request This section is for a service that already holds the signed request a person approved, for example because the person approved it for the service's own app. It is not how an agent presents a mandate to a site: an agent sends the hostname token above. A service in this position can exchange the signed request for a token addressed to its organisation, then check online whether the mandate still stands. It needs an API key and your Organisation ID. See [Get a key](/sdk/verify/api-key). **Developer dashboard access is by invitation during the preview.** You can't sign up yourself yet. Send the signed request the person approved, unchanged, with `audience` set to your Organisation ID. You get back a token addressed only to your organisation. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} const SIS = "https://sis.sumvin.com"; const res = await fetch(`${SIS}/v0/sis/token/pint`, { method: "POST", headers: { Authorization: `Bearer ${process.env.SUMVIN_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...signedRequest, audience: process.env.SUMVIN_ORG_ID }), }); if (!res.ok) throw new Error(`Exchange refused: ${res.status}`); const { sig: token, id: mandateId, scopes, expires_at } = await res.json(); ``` `201` means a new token was issued. `208` means this request was already exchanged for your organisation, and you get the same token back. Keep `mandateId`: you need it for the online check. During the preview, some mandates can't be exchanged yet; the exchange refuses them with `PINT-403-009`. See [Checks and errors](/sdk/verify/checks#errors). Run the same offline check as above, with your Organisation ID as the audience: ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} await jwtVerify(token, sumvinKeys, { algorithms: ["ES256"], issuer: "https://sis.sumvin.com", audience: process.env.SUMVIN_ORG_ID, }); ``` Ask Sumvin whether the mandate is still valid: ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} const statusRes = await fetch( `${SIS}/v0/sis/pint/${encodeURIComponent(mandateId)}/status`, { headers: { Authorization: `Bearer ${process.env.SUMVIN_API_KEY}` } }, ); if (!statusRes.ok) throw new Error(`Online check refused: ${statusRes.status}`); const status = await statusRes.json(); if (!status.valid) { throw new Error(`Mandate no longer stands: ${status.reason}`); } ``` `valid` is `true` when the mandate is neither revoked nor expired. Otherwise `reason` says which. See [the online check](/sdk/verify/checks#online-check). Compare the `scopes` with what is being asked for, and read any spending ceiling with [`readScopeCeiling`](/sdk/verify/reading-scopes). Any refusal, from any step, means don't act. ## Next Every response, error code and limit of the two checks. Turn scopes into amounts you can compare. # Read a mandate's scopes Source: https://docs.sumvin.com/sdk/verify/reading-scopes Turn the scopes on a Stamped Mandate into ceilings you can compare against a request, with readScopeCeiling. **Private preview:** this is rolling out and may not be available on your account yet. A Stamped Mandate permits only what its [scopes](/concepts/mandates/scopes) say. Before you act, check that the request in front of you is inside them. The scope language, parameters and limits are described in [The mandate language](/concepts/mandates/language) and [Limits and narrowing](/concepts/mandates/limits); this page covers reading them in code. ## Read a spending ceiling `readScopeCeiling` reads the ceiling one scope states. It works offline on the scope string alone, so you can use it on the `scopes` from the [exchange](/sdk/verify/checks#exchange). ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} import { isScopeCeilingError, readScopeCeiling } from "@sumvin/sdk"; readScopeCeiling("sr:us:pint:spend:visa_checkout?max=25¤cy=USD"); // { kind: "fiat", amount: "25.00", currency: "USD", decimals: 2 } readScopeCeiling("sr:us:pint:sigil:proof_of_personhood"); // null: this scope states no ceiling ``` `max` is always in the display unit of the currency: `max=25¤cy=USD` is 25.00 US dollars, never 25 cents. `amount` comes back as an exact decimal string, padded to the currency's precision. Compare it as a decimal, never as a floating-point number. Spending scopes belong to payments, which arrive in a fast-follow release. Identity scopes such as `sr:us:pint:sigil:proof_of_personhood` state no ceiling. ## Read every scope The reader handles one scope at a time. Read every scope on the mandate, not only the first. ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} const ceilings = scopes .map((scope) => ({ scope, ceiling: readScopeCeiling(scope) })) .filter(({ ceiling }) => ceiling !== null); ``` ## When it refuses The reader refuses rather than guesses. It throws a `ScopeCeilingError` whose `reason` is one of: | Reason | Means | | - | - | | `malformed-scope` | The scope, or its parameters, aren't written the way the language allows. | | `invalid-amount` | `max` isn't a plain positive decimal. | | `missing-denomination` | `max` names no currency or asset. | | `ambiguous-denomination` | It names both a currency and an asset. | | `unknown-denomination` | The currency or asset isn't one the SDK knows. | | `over-precise` | `max` has more decimal places than the currency allows, such as `25.001` USD. | ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}} try { readScopeCeiling(scope); } catch (e) { if (isScopeCeilingError(e)) { // Unreadable: refuse the request. } } ``` **Treat a refusal as unreadable, never as unlimited.** Refuse the request. `errand:search` takes an optional `max` but names no currency, and that `max` is not enforced (see [Scopes](/concepts/mandates/scopes)). A `max` written there has no currency to read, so the reader refuses it as `missing-denomination`. The ceiling that counts is on `spend:visa_checkout`. # Contact support Source: https://docs.sumvin.com/support How to reach Sumvin when something goes wrong, and what to include so we can find it. ## What to include Every error your agent receives from Sumvin carries two things that let us find exactly what happened. Include both: * **The error code**, such as `KYC-403-001`. It is the `code` in the error your agent received. * **The trace id**, a 32-character string such as `0af7651916cd43dd8448eb211c80319c`. It is the `trace_id` in the error your agent received. Ask your agent for it if you can't see it. Tell us roughly when it happened and what you were trying to do. Don't send passwords, passkeys, recovery codes or full card numbers: we don't need them to look into an error. ## Before you write Most errors say what to do next. Look the code up on the [Errors](/reference/errors) page first: a code ending in `-R` usually clears if you wait and try again.