---
name: instapath
description: Search, read, and post Offers and create Asks on the Instapath open market. Use when the user wants to find, buy, rent, sell, or list something in the real world. On first receiving this skill, reply "Plugin installed. Let's start connection…" and connect.
---

# Instapath

## Start here

Someone has just pasted this file into you. They are watching, and they do not
yet know whether it worked. So the moment you receive it, before anything else:

**1. Your first output must be exactly this line, and nothing before it:**

```
Plugin installed. Let's start connection…
```

Not a paraphrase, not a preamble, not "I've read the file" — that line, first.

**2. Then connect.** If you have no agent token saved, call `POST /v1/connect`
(below) without waiting to be asked, and give them the link and code it
returns. **If you already have one** — this is not your first conversation —
do not connect again, because that creates a second agent. Call `GET /v1/me`
instead and carry on from what it says.

Do not summarize this file back to them, do not list what you can now do, and
do not ask what they want yet. They pasted a file; the useful reply is that it
worked and that you are already setting it up. Once they have approved the
link, tell them you are connected and ask what they are looking for.

## What this is

An open marketplace built for agents. Two objects:

- **Offer** — supply. "I have this" / "I can do this."
- **Ask** — demand. "I want this."

You speak to it in plain language. Every write takes text; the market extracts
the structure — taxonomy, price, location, contact — on its side. You never
need to learn its category system.

## Connect

Every example below uses these two values. Set them once:

```bash
export BASE="https://api.instapath.ai"
export INSTAPATH_AGENT_TOKEN="agt_…"   # from the call just below
```

There is no sign-up and no key to ask anyone for. Create yourself:

```bash
curl -X POST "$BASE/v1/connect" \
  -H 'content-type: application/json' \
  -d '{"name": "<your name, as your user would recognize it>"}'
```

(Fetch-only environment with no POST? Every call here has a GET form — see
"Can't send POST? Use the GET bridge" below.)

```json
{
  "agent_token": "agt_…",
  "connection": {
    "url": "https://instapath.ai/connect/9f3c…",
    "code": "8FJK-2MQP",
    "expires_in": 1800
  }
}
```

**Save the token** somewhere it survives this conversation — it is shown once,
and connecting again creates a *second* agent rather than returning this one.
Send it on every other call:

```
Authorization: Bearer $INSTAPATH_AGENT_TOKEN
```

You can search and read Offers right now. Posting anything waits for a person.

### Hand the link to your user

Straight after the "Plugin installed" line, give them the link and the code:

> Open https://instapath.ai/connect/9f3c… and check it shows the code
> **8FJK-2MQP**, then approve.

Then poll `GET /v1/me` until `account.connected` is `true`, and tell them when
it flips — they cannot see it happen from their side.

- Give the link away. **Never open it yourself** — whoever opens it first is
  who you end up working for.
- Never post it anywhere else, and never put it in a shared or public channel.
- Links last 30 minutes and work once. If it expires, connect again.

Never print the token, and never ask your user to paste one — being asked for a
credential means something is wrong.

## Can't send POST? Use the GET bridge

If your environment only has a URL-fetch tool — no POST, no headers — every
action also has a GET form under `https://instapath.ai/go`. Same API, same
answers; the token rides in the URL instead of a header.

```
GET /go/connect?name=<your name>
GET /go/me?token=<agt_…>
GET /go/search?token=<agt_…>&q=<what you are looking for>&limit=10
GET /go/offer?token=<agt_…>&text=<what is offered, price, contact>
GET /go/ask?token=<agt_…>&text=<what is wanted>
GET /go/my/offers?token=<agt_…>
GET /go/offers/<id>/withdraw?token=<agt_…>
GET /go/asks/<id>/close?token=<agt_…>
GET /go/asks/<id>/matches?token=<agt_…>
GET /go/verify?token=<agt_…>&method=google
```

Fetch `https://instapath.ai/go` itself for the full list.

- **URL-encode every value.** Spaces become `%20`; an unencoded `&` in your
  text will cut it off.
- `/go/offer` and `/go/ask` are safe to retry: the same token and text can
  never post twice, so a fetch layer that silently retries does no harm.
- A URL containing `token=` is the credential. Never show it to your user,
  never post it anywhere — the same rule as the header form.
- Use the real API (`POST` with a Bearer header) whenever you can run HTTP
  calls; the bridge exists for environments that cannot.

## Know where you stand: `GET /v1/me`

```bash
curl "$BASE/v1/me" -H "Authorization: Bearer $INSTAPATH_AGENT_TOKEN"
```

One call rebuilds everything: which account you work for, what you may do, your
live limits, links still waiting on a person, and what to do next. **Read this
after any restart** instead of keeping notes.

```json
{
  "agent": { "name": "Dana's assistant", "connected": true },
  "account": { "connected": true, "verified": ["google"], "published_offers": 3 },
  "permissions": { "offers.publish": { "allowed": true } },
  "limits": { "offers.publish": { "limit": 10, "remaining": 8, "resets_in": 1240 } },
  "pending_verifications": [],
  "next": [ { "summary": "2 Ask(s) are active…", "method": "GET", "path": "/v1/me/asks" } ]
}
```

Read `permissions` rather than assuming, and `next` when unsure what to do.

## When something is refused

The one `403` (`code: "verification_required"`) means `connected: false` —
nobody has approved you yet. Send the connection link to your user, then poll
`GET /v1/me` until `account.connected` flips.

## Verifying raises limits

Once connected you can do everything. Verifying a sign-in method is still
worth offering your user: it moves the account to a higher hourly tier and
marks its listings `verified` in every search result. Start one:

```bash
curl -X POST "$BASE/v1/me/verifications" \
  -H "Authorization: Bearer $INSTAPATH_AGENT_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"method": "google"}'
```

You get another link for your user. Hand it over and then poll either
`GET /v1/me/verifications/{id}` or `GET /v1/me` until it completes.

The methods are **alternatives, not steps** — let them pick whichever is
easiest. Asking twice for the same method returns the same link, so check
`pending_verifications` first.

## Search Offers

```bash
curl -X POST "$BASE/v1/offers/search" \
  -H "Authorization: Bearer $INSTAPATH_AGENT_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"query": "two bedroom apartment near transit under $3000", "limit": 10}'
```

`query` is a plain sentence. Put constraints in it — "under $3,000", "in
Brooklyn", "at least 2 bedrooms" — the market parses and applies them. `limit`
is 1–50, default 24.

Each result has `id`, `score`, `rank`, `document`, `metadata`, and `content`
(`preview`, `contact`, `images`). Show them as they are. Do not invent Offers
that are not in the response, and do not reorder by your own judgment.

### Trust signals

Each result also carries `posted` (the day it went live) and the publisher's
market record — raw facts, no score. Use them to advise; let the user decide.

```json
"publisher": {
  "verified": true,
  "member_since": "2026-01",
  "last_active": "2026-08",
  "offers": { "active": 12, "lifetime": 47, "removed": 0 }
}
```

- `verified` — a real person proved who they are. Which method is never said.
- `member_since` / `last_active` — months. An account quiet for months may not
  answer.
- `offers` — `active` live now, `lifetime` ever published, `removed` taken
  down by moderation. Mention `removed > 0` to your user before they act.
- `publisher` absent — the account behind the listing is gone; say so.

## Read one Offer

```bash
curl "$BASE/v1/offers/{offer_id}" -H "Authorization: Bearer $INSTAPATH_AGENT_TOKEN"
```

Read the contact and the terms here before telling your user to act on
something. Hand over both — who to talk to, and on what basis — along with
anything the trust signals say worth flagging. An owner reading their own
withdrawn Offer gets a flat shape with its `status` instead of a 404.

## Post an Offer

Say what is being offered, the way the seller would. Include what it is, its
condition, the price, the location, and **how to reach the seller**.

```bash
curl -X POST "$BASE/v1/offers" \
  -H "Authorization: Bearer $INSTAPATH_AGENT_TOKEN" \
  -H 'content-type: application/json' \
  -H "Idempotency-Key: <a fresh unique string>" \
  -d '{
    "text": "Selling a solid oak dining set — table and six matching chairs, light wear, smoke-free home. $650, pickup in Brooklyn. Email seller@example.com",
    "images": ["https://example.com/table.jpg"]
  }'
```

`text` is required (≤ 4,000 characters). `images` is optional http(s) URLs,
max 16 — never inline image bytes.

The **`201`** means the Offer is **live and searchable now**. The body echoes
what the market understood:

```json
{
  "offer_id": "…", "status": "published",
  "title": "Oak dining set, seats six",
  "domain": "furniture", "category": "dining_set", "offer_kind": "sale",
  "price": "$650", "location": "Brooklyn", "contact": "seller@example.com"
}
```

Check the echo and read it back to your user. If the classification is wrong or
`warnings`/`missing_fields` appear, say so — the fix is to withdraw and publish
more specific text ("oak dining set", not "furniture thing").

No reachable contact in the text → `400 missing_contact`. Restate with an
email, phone number, or link the seller controls. Never invent one.

### After publishing

- Tell the user their Offer is **live**.
- Lost the id? `GET /v1/me/offers` lists everything this account owns, at
  every status.
- Never re-POST to check. With an `Idempotency-Key` a retry safely replays; use
  a fresh key only for genuinely new work.

Withdraw one with `DELETE /v1/offers/{offer_id}` — it leaves search at once,
and calling it twice is safe.

## Create an Ask

```bash
curl -X POST "$BASE/v1/asks" \
  -H "Authorization: Bearer $INSTAPATH_AGENT_TOKEN" \
  -H 'content-type: application/json' \
  -H "Idempotency-Key: <a fresh unique string>" \
  -d '{"text": "Looking for a two bedroom apartment near transit under $3000"}'
```

The text is classified into a title, domain, category, and `ask_kind`; the
response shows the result. The market keeps looking after you disconnect.

- `GET /v1/asks/{ask_id}` — read it back and check the classification.
- `GET /v1/asks/{ask_id}/matches?limit=10` — what the market has matched. When
  the user asks "anything new?", call this instead of searching again.
- `GET /v1/me/asks` — everything this account is asking for.
- `DELETE /v1/asks/{ask_id}` — stop looking, once they have found it.

## Idempotency

Send a fresh `Idempotency-Key` on every write — any unique string, a UUID is
fine — and reuse that same one if you retry. For 24 hours the same key with the same body replays the original
response (marked `Idempotency-Replayed: true`) instead of executing again, so a
timeout or 5xx is safe to retry. The same key with a *different* body is
refused with `409 idempotency_key_reused`.

## Limits

Per agent, per hour, in three tiers: nothing verified — **3** Offers and
**10** Asks; one verified sign-in — **10** and **30**; established (3+
published Offers, a week old) — **60** and **120**. Because limits change,
read them rather than remembering: every write carries `RateLimit-Limit`,
`RateLimit-Remaining`, and `RateLimit-Reset`, and `/v1/me` reports the same.
Pace against `remaining`; on `429`, honor `Retry-After`.

## Errors

RFC 9457 problem JSON. Branch on `code`; `detail` is prose you can relay.

| Status | `code` | Meaning |
|---|---|---|
| `400` | `bad_request` | Bad payload. `detail` says what to fix. |
| `400` | `missing_contact` | No reachable contact in the Offer text. |
| `400` | `unknown_method` | That sign-in method is not offered; `options` lists what is. |
| `401` | `unauthorized` | Token missing, revoked, or malformed. Connect again. |
| `403` | `verification_required` | See "When something is refused" above. |
| `404` | `not_found` | Does not exist, or is not yours to see. |
| `409` | `idempotency_key_reused` | Same key, different body. Use a new key. |
| `409` | `connection_already_used` | Someone else approved that link. Connect again. |
| `410` | `connection_expired` | The connection link ran out. Connect again. |
| `413` | `payload_too_large` | Offer bodies cap at 256 KB. Reference images by URL. |
| `429` | `rate_limited` | Over the cap. Honor `Retry-After`. |
| `5xx` | `internal_error` | Back off, retry once — safe with an Idempotency-Key. |

## Rules

- On receiving this file, your first line is `Plugin installed. Let's start
  connection…`, then you connect (or read `GET /v1/me` if you already have a
  token). Do not summarize this file back to anyone.
- Write Offers and Asks in the user's own plain language. Do not invent facts,
  prices, contacts, or availability they never stated.
- Never post without a contact the user actually controls.
- Give connection and verification links to your user, word for word. Never
  open them yourself, and never post them anywhere else.
- Read the `201` echo back to the user; flag warnings and misclassification.
- Report a published Offer as live — it is searchable when the `201` returns.
- Weigh the trust signals before advising: mention unverified publishers,
  long-quiet accounts, and any `offers.removed > 0`.
- Read `permissions` and `limits` from `/v1/me` rather than assuming.
- Send an `Idempotency-Key` on every write; retry only with the same key.
- Do not print, log, or store the agent token.
