Cancel Offer

There are two ways to cancel an offer: Gasless (Off-chain) and Secure (On-chain).

  • Gasless Cancel (Off-chain): Removes the offer from our database using an EIP-191 signature. This is free and fast, but the signed offer remains technically valid on-chain if a seller possesses the original signature and calls the exchange contract.
  • Secure Cancel (On-chain): Submits a transaction calling the exchange contract directly to cryptographically invalidate the order nonce. This requires a gas fee but guarantees the offer can never be fulfilled on-chain.

To completely invalidate the order on-chain, the buyer submits a transaction to the MintpadExchange contract.

Step 1 — Obtain the offer's nonce

Query GET /v1/offers (requires x-api-key) to retrieve the offer's nonce string.

Step 2 — Submit the contract transaction

Call the cancelMultipleMakerOrders function on the MintpadExchange contract from the user's wallet:

  • Exchange Address: 0xdFbE43b2c154B6a790158fa2696cDb32A86Efc78
  • Function: cancelMultipleMakerOrders(uint256[] nonces)
TypeScript
// ethers.js v6
const exchange = new Contract(EXCHANGE_ADDRESS, MINTPAD_EXCHANGE_ABI, signer)
const tx = await exchange.cancelMultipleMakerOrders([BigInt(nonce)])
await tx.wait()

Step 3 — Sync with the Database

After the transaction is confirmed on-chain, call the off-chain DELETE request (see below) to remove the offer from the database index.


Gasless Cancel (Off-chain)

To remove the offer from the marketplace without paying gas, have the buyer sign a cancellation message and send it to the partner API.

Step 1 — Obtain the orderHash

The orderHash is the unique identifier for an offer. You need it to identify which offer to cancel.

Option A — Store it at creation time. The POST /v1/offers response always includes it:

JSON
{
"success": true,
"orderHash": "0xabcde12345...",
"status": "active"
}

Option B — Look it up by querying the active offer. Use GET /v1/offers (requires x-api-key) filtered by collection and buyer:

Text
GET /v1/offers?collectionAddress=0x29ef...&buyer=0x9876...

The orderHash field is present on every offer object in the response:

JSON
{
"offers": [
{
"orderHash": "0xabcde12345...",
"tokenId": null,
"buyer": "0x9876543210abcdef9876543210abcdef98765432",
"priceWei": "100000000000000000000",
"nonce": "1718274092"
}
]
}

Step 2 — Sign the Cancellation Message

The buyer must sign an EIP-191 personal_sign message — not a typed data signature. The message is a plain string:

Text
Cancel Mintpad Offer: <orderHash>

Where <orderHash> is the full lowercase hex string (e.g. 0xabcde12345...).

TypeScript
// ethers.js v6
const message = `Cancel Mintpad Offer: ${orderHash}`
const signature = await signer.signMessage(message)
// viem
const signature = await walletClient.signMessage({
account: buyerAddress,
message: `Cancel Mintpad Offer: ${orderHash}`
})

The message format must be exact — including the colon and space before the hash. The API will reject signatures with any variation in the string.


Step 3 — Send the Cancel Request

DELETE /v1/offers/:orderHash

Headers:

  • x-api-key: mp_part_yourkey
JSON
{
"signature": "0xsignaturehex..."
}

Offer Ownership Requirement

A partner can only cancel offers that were created using their own API key. If the offer was created by another partner or directly on the Mintpad website, the API will reject the request with 403 Forbidden.

The API recovers the signer from the signature and verifies:

  1. The signature matches the original offer's signer address.
  2. The offer was originally created by the requesting partner (partnerId matches the authenticated API key).

If all checks pass, the offer is marked as cancelled immediately.

Error Responses

If the offer was created by another partner:

  • Status: 403 Forbidden
  • Body:
JSON
{
"error": "FORBIDDEN",
"message": "This offer was not created by your partner account."
}

Response

JSON
{
"success": true,
"orderHash": "0xabcde12345...",
"status": "cancelled"
}

Full Example (Gasless)

TypeScript
async function cancelOffer(
orderHash: string,
buyerAddress: string,
signer: Signer, // ethers.js v6
apiKey: string
) {
// 1. Sign the cancellation message
const message = `Cancel Mintpad Offer: ${orderHash}`
const signature = await signer.signMessage(message)
// 2. Submit the cancel request
const res = await fetch(
`https://partners-api.mintpad.app/v1/offers/${orderHash}`,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({ signature })
}
)
const data = await res.json()
if (!data.success) throw new Error(`Cancel failed: ${data.error}`)
return data
}