Skip to content

Deals API

Read any deal, make an offer on a registration, and answer the offers on yours. What each deal type means, and every rule an offer is held to, is in Ownership Deals.

Endpoints

MethodPathAuthDescription
GET/api/v2/deals/{dealId}Optional sessionGet one deal, with its events
GET/api/v2/deals/{dealId}/eventsOptional sessionGet a deal's event history
GET/api/v2/deals/mineSessionYour deals, with their agreed terms
GET/api/v2/deals/symbol/{symbol}API keyDeals on a ticker
GET/api/v2/deals/address/{address}API keyDeals a wallet is a party to
GET/api/v2/registration/{id}/dealsAPI keyDeals on one registration
GET/api/v2/deals/group/{groupId}API keyA set of offers that take effect together
GET/api/v2/deals/limitsAPI keyThe numeric deal rules in force
GET/api/v2/deals/fee-previewAPI keyCheck an amount against the minimum offer
GET/api/v2/deals/pricesAPI keyUSD prices for deal currencies
POST/api/v2/deals/verify-fundsSessionProve you hold what you are about to offer
POST/api/v2/deals/offerSessionMake an offer
POST/api/v2/deals/{dealId}/acceptSessionAccept an offer on your registration
POST/api/v2/deals/{dealId}/rejectSessionReject an offer on your registration
POST/api/v2/deals/{dealId}/cancelSessionCancel a deal you are a party to
POST/api/v2/deals/{dealId}/reverify-fundsSessionRe-check a party's funds against an existing deal
GET/api/v2/deals/offer-floorSessionYour offer settings
PUT/api/v2/deals/offer-floorSessionSet a floor, or stop offers

Settlement (payment received, burn consent, the Solana settlement signatures and transactions) runs from the deal page in the app. It is not covered here.

Authentication

Every request carries your X-API-Key. See Authentication.

Session routes also need a wallet session: Authorization: Bearer <JWT>. An API key is not accepted as the bearer on any deal route. Every write acts as the signed-in wallet, and a wallet named in the body must be one that session controls, or the request is refused with 403.

To get a session without a browser:

  1. GET /api/v2/auth/nonce returns { "nonce": "…" }
  2. Sign a Sign-In with Ethereum message with domain chaindaddy.io and that nonce, from the wallet you will act as
  3. POST /api/v2/auth/login/siwe with { "message", "signature" } returns { "accessToken": "…" }

A Solana wallet uses POST /api/v2/auth/login/siws. Send the token as the bearer, alongside your API key.

Optional session routes answer anyone. With a session they also say what you may do, and a party sees what an outsider does not.


Get a Deal

GET /api/v2/deals/{dealId}

One deal, its event history, its attestations and its recorded payments.

What a party sees

FieldOutsiderParty (with a session)
A collab's agreed terms in eventsRemovedIncluded
attestations[].signature, message_hash, domain_separatorEmptyIncluded
actionsnullWhat you may do now, possibly []

Response Format

json
{
  "success": true,
  "deal": {
    "id": "7b1e5c2a-3f0d-4a51-9c7e-2d8f6a1b4c90",
    "deal_type": "buyout",
    "status": "draft",
    "stage": "awaiting_response",
    "seller_address": "0x1234567890abcdef1234567890abcdef12345678",
    "crown_holder": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "symbol": "PEPE",
    "chain_id": 8453,
    "agreed_amount": "25000",
    "agreed_currency": "USDC",
    "message": "Happy to talk terms.",
    "fund_verification_pct": 100,
    "burn_consent_recorded": false,
    "migration_window_end": "2026-11-15T18:00:00Z",
    "deadline": "2026-11-15T18:00:00Z",
    "deadline_kind": "migration_window",
    "created_at": "2026-09-16T18:00:00Z",
    "updated_at": "2026-09-16T18:00:00Z",
    "actions": ["cancel"],
    "events": [
      {
        "id": "c0a8f1d2-…",
        "deal_id": "7b1e5c2a-3f0d-4a51-9c7e-2d8f6a1b4c90",
        "event_type": "deal_created",
        "event_data": {},
        "actor_address": "0x1234567890abcdef1234567890abcdef12345678",
        "created_at": "2026-09-16T18:00:00Z"
      }
    ]
  }
}

Deal Fields

FieldTypeDescription
idstringDeal ID
deal_typestringbuyout, project_sale, merge (a consolidation) or collab
statusstringdraft, pending, announced, paused, payment_pending, executing, migrating, completed, failed, cancelled or closed
stagestringWhere the deal is, in one word. Read this rather than status: awaiting_response, announcement, swap_window, awaiting_consent, awaiting_dispatch, settling, awaiting_launch, completed, closed
deadlinestringThe one clock that matters at this stage, if one is running
deadline_kindstringWhat deadline counts down: offer, announcement, migration_window, burn_consent or settlement_window
seller_addressstringThe wallet that made the offer. The name reads backwards: it is the acquirer
buyer_addressstringThe registration's holder, written when they accept
crown_holderstringThe wallet holding the registration now. Set on single-deal reads, and on list rows waiting on you
symbolstringTicker
chain_idintegerChain the registration is on. Solana is 900900
token_addressstringThe token the deal names, when a ticker has more than one on a chain
group_idstringSet when the offer is one of a group
agreed_amountstringOffer amount, in agreed_currency
agreed_currencystringUSDC, USDT, ETH, SOL, or a token contract address
messagestringThe offerer's message
response_messagestringThe holder's reply, or their reason for rejecting
fund_verification_pctintegerHow much of the offer the offerer proved they held
expires_atstringWhen an unanswered offer lapses. Absent on a deal with its own window
migration_window_endstringWhen a buyout's redemption window or a consolidation's swap window closes
burn_consent_recordedbooleanWhether the holder has signed settlement consent. Never the consent itself
burn_consent_expiryintegerWhen that consent stops working, unix seconds
burn_tx_hash, mint_tx_hashstringSettlement transactions, once broadcast
completed_at, failure_reasonstringSet when the deal ends
actionsarrayWhat this session may do now: accept, reject, cancel, sign_burn_consent, launch_collab. null on a read without a session
eventsarrayEvery event, oldest first
attestationsarraySigned statements by the parties, such as payment received
paymentsarrayRecorded payments, with their transaction and verification state

Code Examples

bash
curl https://api.chaindaddy.io/api/v2/deals/7b1e5c2a-3f0d-4a51-9c7e-2d8f6a1b4c90 \
  -H "X-API-Key: cd_live_abc123..."
javascript
async function getDeal(apiKey, dealId, sessionToken) {
  const headers = { 'X-API-Key': apiKey };
  // Optional: a party with a session also gets actions, terms and signatures
  if (sessionToken) headers.Authorization = `Bearer ${sessionToken}`;

  const res = await fetch(`https://api.chaindaddy.io/api/v2/deals/${dealId}`, { headers });
  if (res.status === 404) return null;
  const { deal } = await res.json();
  return deal;
}

Get Deal Events

GET /api/v2/deals/{dealId}/events

The event history alone, oldest first. The same party rule applies to a collab's terms.

json
{
  "dealId": "7b1e5c2a-3f0d-4a51-9c7e-2d8f6a1b4c90",
  "events": [
    { "id": "c0a8f1d2-…", "deal_id": "7b1e5c2a-…", "event_type": "deal_created", "event_data": {}, "created_at": "2026-09-16T18:00:00Z" }
  ]
}

List Your Deals

GET /api/v2/deals/mine

Every deal any wallet on your session is a party to, including offers waiting on you. The only list that carries the agreed terms.

Query Parameters

ParameterTypeRequiredDescription
deal_typestringNobuyout, project_sale, merge or collab. An unknown value is a 400
statusstringNoAny deal status. An unknown value is a 400
limitintegerNoPage size (default: 20)
offsetintegerNoRows to skip (default: 0)
json
{
  "deals": [ { "id": "7b1e5c2a-…", "deal_type": "buyout", "terms": { "redemptionWindow": 60 }, "actions": ["cancel"] } ],
  "total": 1,
  "limit": 20,
  "offset": 0,
  "deal_type": "",
  "status": ""
}

List Deals

GET /api/v2/deals/symbol/{symbol}
GET /api/v2/deals/address/{address}
GET /api/v2/registration/{id}/deals

Public lists. None carries agreed terms: use your own list for those. On the registration route, {id} is the registration's token ID.

ParameterApplies toDescription
chainIdsymbolLimit to one chain
roleaddressseller (offers the wallet made) or buyer (deals it accepted). Omit for both, plus offers waiting on it
limitallPage size (default: 20)
offsetallRows to skip (default: 0)

Each answers { "deals": [...], "total", "limit", "offset" }, plus what was asked: symbol, address and role, or tokenId, symbol and chainId.

bash
curl "https://api.chaindaddy.io/api/v2/deals/symbol/PEPE?chainId=8453" \
  -H "X-API-Key: cd_live_abc123..."

Get a Deal Group

GET /api/v2/deals/group/{groupId}

Offers made as one set take effect only when every member is accepted. A deal's group_id names its set.

json
{
  "group": { "id": "…" },
  "deals": [ { "id": "…", "symbol": "PEPE", "chain_id": 8453, "status": "draft" } ],
  "total": 3,
  "accepted": 2,
  "complete": false,
  "pending": [ { "deal_id": "…", "symbol": "PEPE", "chain_id": 8453, "status": "draft" } ]
}

pending names the members still waiting on their holder.


Get Deal Limits

GET /api/v2/deals/limits

The numeric rules this environment enforces, in whole dollars.

json
{
  "collabMinLiquidityUsd": 1000,
  "minOfferUsd": 500
}

Preview an Offer

GET /api/v2/deals/fee-preview

Checks an amount against the minimum offer before you make it.

Query Parameters

ParameterTypeRequiredDescription
dealValueintegerYesAmount times 1,000,000, in currency. 1000000000 is 1,000 USDC
currencystringNoUSDC (default), USDT, ETH, SOL, or a token contract address
chainIdintegerNoChain, for pricing a token contract address
mcapEstimateintegerNoMarket cap in USD times 1,000,000. Sizes the minimum as a share of it

Response Format

json
{
  "facilitationFee": 50000000,
  "minimumOffer": 500000000,
  "mcapEstimate": 0,
  "effectiveRate": 5,
  "dealValueUsd": 1000000000,
  "currency": "USDC"
}
FieldTypeDescription
minimumOfferintegerThe smallest offer allowed, USD times 1,000,000
dealValueUsdintegerYour amount in USD, times 1,000,000
currencystringThe currency measured
priceUsdnumberThe price used to convert it. Absent for dollar stablecoins
facilitationFee, effectiveRatenumberLegacy figures. No fee is charged on any deal

An amount below the minimum is a 400 naming the minimum. So is a currency with no USD price: an offer that cannot be measured is refused, not guessed.


Get Deal Prices

GET /api/v2/deals/prices

USD prices for the deal currencies, refreshed every five minutes.

json
{ "ETH": 3120.55, "SOL": 162.4, "USDC": 1, "USDT": 1 }

Verify Funds

POST /api/v2/deals/verify-funds

Reads your balance and, when it covers the offer, signs an attestation. A buyout, a project acquisition or a collab is refused without a passing check from the last hour, on the same currency and chain, from a wallet on your session.

A balance read, not a lock. Nothing is escrowed.

Request Body

FieldTypeRequiredDescription
walletAddressstringYesThe wallet to check. Must be on your session
currencystringYesOffer currency. On Solana, USDC only. For a collab, USDC
offerAmountnumberYesThe offer in currency, as a person would type it: 25000 is 25,000 USDC. For a collab, the liquidity it commits in dollars
chainIdintegerYesChain the offer is on
symbolstringNoTicker

Response Format

json
{
  "verified": true,
  "balance": "31000000000",
  "requiredAmount": "25000000000",
  "requiredPct": 100,
  "attestation": {
    "hash": "0x…",
    "signature": "0x…",
    "blockNumber": 19876543,
    "timestamp": 1789581600
  }
}
FieldTypeDescription
verifiedbooleanWhether the balance covers the required amount
balancestringBalance read, in the token's base units
requiredAmountstringWhat the offer needs, in base units
requiredPctintegerShare of the offer your plan must hold: 100, or 80 for a paying Partner or Enterprise account
shortfallstringHow much more you need, in base units. Only when not verified
attestationobjectThe signed attestation. Only when verified

POST /api/v2/deals/{dealId}/reverify-funds takes the same body and re-checks against an existing deal. Only a party to that deal may file one.


Make an Offer

POST /api/v2/deals/offer

Makes the offer and notifies the registration's holder. Checks run in this order, and the first to fail answers:

  1. The minimum offer (400)
  2. The holder's own settings: offers off, or below their floor (403)
  3. Verified funds (402)
  4. Your weekly offer count and the value you have standing (429)

Every limit is in Rules and limits.

Making an offer, making a group and cancelling share a budget of 10 requests a minute per account.

Request Body

FieldTypeRequiredDescription
deal_typestringYesbuyout, project_sale, merge or collab. Required: a missing type is refused, never assumed
symbolstringYesTicker
chain_idinteger or stringYesChain ID, or a chain key such as "base"
token_addressstringNoWhich token, when a ticker has more than one on the chain
buyer_addressstringNoThe wallet you offer from. Defaults to your session's wallet
agreed_amountstringPriced typesOffer amount, e.g. "25000". Required for buyout and project_sale
agreed_currencystringPriced typesUSDC, USDT, ETH, a token contract address, or on Solana USDC
payment_methodstringNoHow you will pay. escrow is refused
messagestringNoA note to the holder
offer_window_daysintegerNo7, 14, 30, 60 or 90 (default 30). Refused on a deal with its own window: a buyout's redemption window or a consolidation's swap window
buyout_termsobjectNoredemptionWindow: the days holders have to redeem, 30 to 730
migration_termsobjectMergeswapWindow: the days holders have to swap, 1 to 730. Required
acquisition_termsobjectNoTerms of a project acquisition
collab_termsobjectCollabproposedSymbol (up to 16 characters), partnerShareBps (1 to 9999, the partner's share of the creator fee), liquidityCommitmentUsd (at least collabMinLiquidityUsd)

Response Format

json
{
  "success": true,
  "dealId": "7b1e5c2a-3f0d-4a51-9c7e-2d8f6a1b4c90",
  "status": "draft",
  "deal": { "id": "7b1e5c2a-…", "deal_type": "buyout", "status": "draft" },
  "message": "Offer created. The token owner will be notified."
}

Code Examples

bash
# 1. Verify funds
curl -X POST https://api.chaindaddy.io/api/v2/deals/verify-funds \
  -H "X-API-Key: cd_live_abc123..." \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{ "walletAddress": "0x1234...5678", "currency": "USDC", "offerAmount": 25000, "chainId": 8453 }'

# 2. Make the offer within the hour
curl -X POST https://api.chaindaddy.io/api/v2/deals/offer \
  -H "X-API-Key: cd_live_abc123..." \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{
    "deal_type": "buyout",
    "symbol": "PEPE",
    "chain_id": 8453,
    "agreed_amount": "25000",
    "agreed_currency": "USDC",
    "buyout_terms": { "redemptionWindow": 60 },
    "message": "Happy to talk terms."
  }'
javascript
const BASE_URL = 'https://api.chaindaddy.io';

async function makeBuyoutOffer({ apiKey, sessionToken, wallet, symbol, chainId, amount }) {
  const headers = {
    'X-API-Key': apiKey,
    Authorization: `Bearer ${sessionToken}`,
    'Content-Type': 'application/json',
  };

  // 1. Prove the funds. The check lasts one hour.
  const check = await fetch(`${BASE_URL}/api/v2/deals/verify-funds`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ walletAddress: wallet, currency: 'USDC', offerAmount: amount, chainId }),
  }).then(r => r.json());
  if (!check.verified) throw new Error(`Short by ${check.shortfall} base units`);

  // 2. Make the offer
  const res = await fetch(`${BASE_URL}/api/v2/deals/offer`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      deal_type: 'buyout',
      symbol,
      chain_id: chainId,
      agreed_amount: String(amount),
      agreed_currency: 'USDC',
      buyout_terms: { redemptionWindow: 60 },
    }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error);
  return data.dealId;
}

Accept or Reject an Offer

POST /api/v2/deals/{dealId}/accept
POST /api/v2/deals/{dealId}/reject

Only the wallet holding the registration may answer. Accepting moves nothing on chain and costs no gas.

Request Body

FieldTypeRequiredDescription
wallet_addressstringNoThe holding wallet. Defaults to your session's wallet
response_messagestringNoYour reply, or your reason for rejecting

Response Format

json
{
  "success": true,
  "dealId": "7b1e5c2a-3f0d-4a51-9c7e-2d8f6a1b4c90",
  "status": "announced",
  "deal": { "id": "7b1e5c2a-…", "status": "announced" },
  "message": "Deal accepted. Both parties must confirm settlement before the registration transfers."
}

The message says what accepting did: a consolidation opens its swap window, and a collab waits for its launch.

POST /api/v2/deals/{dealId}/respond does the same in one route: { "action": "accept" | "reject", "message": "…" }. Its response carries no deal.


Cancel a Deal

POST /api/v2/deals/{dealId}/cancel

Either party may cancel until the burn lands. A cancelled deal cannot be reopened.

FieldTypeRequiredDescription
wallet_addressstringNoThe wallet you are a party as. Defaults to your session's wallet
json
{
  "success": true,
  "dealId": "7b1e5c2a-3f0d-4a51-9c7e-2d8f6a1b4c90",
  "status": "cancelled",
  "message": "Deal cancelled successfully."
}

Offer Settings

GET /api/v2/deals/offer-floor
PUT /api/v2/deals/offer-floor

What you are willing to be offered, across every registration you hold.

FieldTypeDescription
floorUsdintegerSmallest priced offer you will see, in whole dollars, up to 100,000,000. 0 or null clears it
offersDisabledbooleanRefuse every offer, of every type

GET answers { "offerFloorUsd", "offersDisabled" }, and so does PUT with what it saved.


Webhooks

Deal events can be pushed to you instead of polled: deal.created, deal.accepted, deal.rejected, deal.cancelled, deal.completed, deal.failed. Each payload names the deal and carries no terms. See Webhooks.


Error Responses

Most errors answer { "error": "…", "code": "…" }.

StatusCodeDescription
400VALIDATION_INVALID_INPUTA missing or invalid field, an amount below the minimum, or an unpriceable currency
400DEAL_INVALID_STATEThe deal cannot move that way from where it is
401No session, or the session expired
402VALIDATION_INVALID_INPUTNo passing funds check covers the offer
403A wallet not on your session, a holder who is not taking offers, or not a party to the deal
404VALIDATION_INVALID_INPUTDeal not found
409DEAL_CONFLICTA swap window is already open on that registration
429VALIDATION_INVALID_INPUTOver your weekly offers or your standing offer value, or over the request rate
503PROVIDER_UNAVAILABLEDeals, your plan, or the offer lock could not be read. Try again