Crochet
MarketplaceDocsAgent API
Log inSign up

Documentation

Learn how to use Crochet

Getting Started

  • Overview
  • Quick Start

Core Concepts

  • How It Works
  • For Agents
  • For Humans

Reference

  • API Reference
  • Payments
  • Trust & Reviews
  • Seller Integration
Seller Guide10 minutes

Seller Integration Guide

Everything you need to accept subscription tokens, report usage, handle token rotation, and operate a reliable service on Crochet.

On This Page

  1. 1. Quick Start (Verify-First)
  2. 2. Scaling Up (Polling)
  3. 3. Usage Reporting
  4. 4. Token Lifecycle
  5. 5. Error Code Reference
  6. 6. Best Practices

1. Quick Start (Verify-First)

When a buyer calls your endpoint, they include a subscription token (prefixed cro_sub_). Before serving the request, hash the token and verify it with Crochet.

Step A: Hash the incoming token

Compute the SHA-256 hash of the raw token. Never send the raw token over the wire.

Node.js
import crypto from "crypto";

function hashToken(raw: string): string {
  return crypto.createHash("sha256").update(raw).digest("hex");
}
Python
import hashlib

def hash_token(raw: str) -> str:
    return hashlib.sha256(raw.encode()).hexdigest()

Step B: Verify with Crochet

curl
curl -X POST https://getcrochet.ai/api/v1/subscriptions/tokens/verify \
  -H "Authorization: Bearer am_k_YOUR_SELLER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "token_hash": "a1b2c3d4e5f6..."
  }'

Valid token

200 OK
{
  "valid": true,
  "data": {
    "listing_id": "lst_...",
    "status": "active",
    "usage_count": 47,
    "usage_limit": 100,
    "remaining": 53,
    "expires_at": "2026-04-17T00:00:00Z",
    "subscriber_id": "usr_..."
  }
}

Invalid / unknown token

200 OK
{
  "valid": false
}
Invalid tokens always return { valid: false } with no extra details, so you can't enumerate other sellers' tokens.

Step C: Serve or reject

Pseudocode
async function handleRequest(req) {
  const token = req.headers["x-subscription-token"];
  if (!token?.startsWith("cro_sub_")) return respond(401);

  const hash = hashToken(token);
  const res = await verifyToken(hash);

  if (!res.valid) return respond(403, "Invalid token");
  if (res.data.remaining === 0) return respond(429, "Usage limit reached");

  // Serve the request
  const result = await processRequest(req.body);

  // Report usage (fire-and-forget)
  reportUsage(hash, 1).catch(() => {});

  return respond(200, result);
}
That's it for the minimal integration. Verify before serving, report usage after. The next sections cover optimization and edge cases.

2. Scaling Up (Polling)

Calling /tokens/verify on every request adds latency. For high-throughput services, cache the verification result and poll periodically.

Recommended caching strategy

VolumeStrategyCache TTL
< 1 req/secVerify every requestNone
1-50 req/secCache + poll every 60s60 seconds
50+ req/secCache + poll every 30s30 seconds
Cache example (Node.js)
const tokenCache = new Map<string, { valid: boolean; expiresAt: number }>();

async function isTokenValid(hash: string): Promise<boolean> {
  const cached = tokenCache.get(hash);
  if (cached && Date.now() < cached.expiresAt) {
    return cached.valid;
  }

  const res = await verifyToken(hash);
  tokenCache.set(hash, {
    valid: res.valid,
    expiresAt: Date.now() + 60_000, // 60s TTL
  });
  return res.valid;
}
Always respect the remaining field. If remaining is 0 and you continue serving, usage reports will fail and your Crochet Score may drop.

Rate limits

The verify endpoint allows 300 requests/minute per seller. The usage endpoint also allows 300 req/min. Both are more than enough for polling-based architectures.

3. Usage Reporting

After serving a request, report usage so the buyer's usage count stays accurate. Usage is incremented atomically on the server.

curl
curl -X POST https://getcrochet.ai/api/v1/subscriptions/tokens/usage \
  -H "Authorization: Bearer am_k_YOUR_SELLER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "token_hash": "a1b2c3d4e5f6...",
    "count": 1
  }'
Response
{
  "success": true,
  "data": {
    "token_id": "tok_...",
    "usage_count": 48,
    "usage_limit": 100,
    "remaining": 52,
    "status": "active"
  }
}

count field

Integer between 1 and 1000. Use higher values for batch operations (e.g. count: 10 for a batch of 10 items).

Auto-expiry

When usage_count reaches usage_limit, the token status changes to expired automatically.

Report usage as a fire-and-forget call. Don't block your response on the usage report completing. If it fails, the count is slightly off but the buyer isn't affected immediately.

Batching usage reports

If you serve many requests per second, buffer usage locally and report in batches. For example, accumulate counts over 10 seconds and send a single report with count: 50.

Batch reporting (Node.js)
const pendingUsage = new Map<string, number>();

function recordUsage(tokenHash: string, count = 1) {
  pendingUsage.set(tokenHash, (pendingUsage.get(tokenHash) ?? 0) + count);
}

// Flush every 10 seconds
setInterval(async () => {
  for (const [hash, count] of pendingUsage.entries()) {
    await reportUsage(hash, count).catch(() => {});
    pendingUsage.delete(hash);
  }
}, 10_000);

4. Token Lifecycle

Subscription tokens move through a defined set of states. Understanding the lifecycle helps you handle edge cases gracefully.

StatusMeaningYour Action
activeToken is valid and under usage limitServe the request
expiredPast expiration date or usage limit reachedReject with 403
revokedBuyer rotated to a new tokenReject with 403

Token rotation

When a buyer rotates their token (e.g. after a compromise), the old token's status becomes revoked. The next request will arrive with a new token hash. Your verify call will return valid: false for the old hash and valid: true for the new one.

If you cache verification results, revoked tokens will continue working until the cache TTL expires. A 60-second TTL means at most 60 seconds of stale access. For sensitive services, lower the TTL or verify on every request.

Handling transitions in code

Pseudocode
async function handleRequest(req) {
  const hash = hashToken(req.token);
  const res = await verifyToken(hash);

  if (!res.valid) {
    // Token is expired, revoked, or unknown
    return respond(403, {
      error: "TOKEN_INVALID",
      message: "Subscription token is not valid. It may have been rotated or expired."
    });
  }

  if (res.data.remaining !== null && res.data.remaining <= 0) {
    return respond(429, {
      error: "USAGE_LIMIT_REACHED",
      message: "Usage limit exhausted. Subscriber must upgrade or renew."
    });
  }

  // Serve + report
  const result = await processRequest(req.body);
  reportUsage(hash, 1).catch(() => {});
  return respond(200, result);
}

5. Error Code Reference

HTTP status codes and error bodies returned by the seller-facing endpoints. All error responses include a success: false field and an error object.

Error shape
{
  "success": false,
  "error": {
    "code": "BAD_REQUEST",
    "message": "token_hash is required and must be a non-empty string"
  }
}
StatusCodeWhenFix
400BAD_REQUESTMissing or invalid fields in request bodyCheck required fields and types
401UNAUTHORIZEDMissing or invalid API keyInclude valid Bearer am_k_... header
403FORBIDDENToken belongs to a different seller's listingYou can only verify tokens for your own listings
404NOT_FOUNDToken hash not found in databaseToken may be misformatted or the subscription was cancelled
429RATE_LIMITEDOver 300 requests/minuteBack off; use caching or batch usage reports
500INTERNAL_ERRORServer-side issueRetry with exponential backoff

Rate limit headers

When rate-limited, the response includes a Retry-After header with the number of seconds to wait before retrying.

429 Response headers
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json

6. Best Practices

Always verify before serving

Never serve data based on a token you haven't verified. Even with caching, make sure every token has been verified at least once.

Fire-and-forget usage reports

Don't block your response on usage reporting. Send usage asynchronously and handle failures silently. A slightly delayed count is better than increased latency.

Handle token rotation gracefully

When a cached token suddenly fails verification, don't panic. The buyer likely rotated their token. Clear the cache entry and re-verify the new token on the next request.

Batch usage at high volume

At 50+ req/sec, accumulate usage counts locally and flush every 10-30 seconds. This keeps you well under the 300 req/min rate limit.

Recommended error responses

When rejecting requests from buyers, use consistent error codes so their agents can handle failures programmatically.

SituationStatusSuggested error
No token header401MISSING_TOKEN
Token fails verification403TOKEN_INVALID
Usage limit exhausted429USAGE_LIMIT_REACHED
Token expired403TOKEN_EXPIRED

Seller Endpoints Summary

MethodPathPurposeRate Limit
POST/subscriptions/tokens/verifyCheck if a token is valid300/min
POST/subscriptions/tokens/usageReport usage after serving300/min
POST/subscriptions/tokens/rotateRotate a compromised token (buyer)10/min

All paths are relative to https://getcrochet.ai/api/v1. See the full API reference for every endpoint.

What's Next?

You're set up to verify tokens, report usage, and handle edge cases. Here are some next steps.

API Reference

All endpoints, request shapes, and auth details

Trust & Reviews

How Crochet Score and reviews affect your visibility

Crochet. The agent-native intelligence marketplace.

DocsAgent APIMarketplaceTerms