Skip to main content

Writes

Understanding Mutations vs Smart Contract Operations​

The Intuition GraphQL API provides mutations for off-chain operations like uploading metadata to IPFS. For on-chain operations like creating atoms, triples, and positions, you must use the Intuition SDK or interact directly with the smart contracts.

Pinning endpoint and API key

Pinning mutations are served from the public gated endpoint, https://pin.intuition.systems/v1/graphql, not the read endpoint. Send your Intuition pin API key in an apikey request header from a trusted server runtime.

Authenticated Pinning Client​

With graphql-request, create a client with the apikey header:

import { GraphQLClient } from 'graphql-request';
import { PIN_API_URL } from '@0xintuition/graphql';

const pinClient = new GraphQLClient(PIN_API_URL, {
headers: {
apikey: process.env.INTUITION_PIN_API_KEY!,
},
});

Without a GraphQL client, send the same header with fetch:

import { PIN_API_URL } from '@0xintuition/graphql';

const response = await fetch(PIN_API_URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
apikey: process.env.INTUITION_PIN_API_KEY!,
},
body: JSON.stringify({
query: `
mutation PinThing($thing: PinThingInput!) {
pinThing(thing: $thing) {
uri
}
}
`,
variables: {
thing: {
name: 'My Project',
description: 'Description of my project',
image: 'ipfs://...',
url: 'https://example.com',
},
},
}),
});
GraphQL vs Smart Contracts

GraphQL mutations handle:

  • Uploading metadata to IPFS (pinThing, pinPerson, pinOrganization)

Smart contract operations handle:

  • Creating atoms
  • Creating triples
  • Taking positions (depositing/redeeming)
  • All on-chain state changes

Use the SDK for smart contract interactions.

Available Mutations​

IPFS & Metadata Mutations​

MutationDescriptionDocumentation
pinThingPin Thing metadata to IPFSPin Thing
pinPersonPin Person metadata to IPFSPin Person
pinOrganizationPin Organization metadata to IPFSPin Organization
uploadImageUpload base64 image to IPFSUpload Image
uploadImageFromUrlUpload image from URL to IPFSUpload from URL
uploadJsonToIpfsUpload JSON metadata to IPFSUpload JSON
Read-Only Operations

Chart and PnL operations are queries, not mutations. See:

Pin Mutations​

pinThing Mutation​

Pin a Thing entity to IPFS:

mutation PinThing($thing: PinThingInput!) {
pinThing(thing: $thing) {
uri
}
}

Variables:

{
"thing": {
"name": "Ethereum",
"description": "A decentralized blockchain platform",
"image": "ipfs://QmXnnyufdzAWL5CqZ2RnSNgPbvCc1ALT73s6epPrRnZ1Xy",
"url": "https://ethereum.org"
}
}

pinPerson Mutation​

Pin a Person entity to IPFS:

mutation PinPerson($person: PinPersonInput!) {
pinPerson(person: $person) {
uri
}
}

Variables:

{
"person": {
"name": "Vitalik Buterin",
"description": "Co-founder of Ethereum",
"email": "vitalik@ethereum.org",
"identifier": "vitalik.eth",
"image": "ipfs://Qm...",
"url": "https://vitalik.ca"
}
}

pinOrganization Mutation​

Pin an Organization entity to IPFS:

mutation PinOrganization($organization: PinOrganizationInput!) {
pinOrganization(organization: $organization) {
uri
}
}

Variables:

{
"organization": {
"name": "Ethereum Foundation",
"description": "Non-profit supporting Ethereum",
"email": "info@ethereum.org",
"image": "ipfs://Qm...",
"url": "https://ethereum.foundation"
}
}

Image Upload Mutations​

uploadImage​

Upload a base64-encoded image:

mutation UploadImage($image: UploadImageInput!) {
uploadImage(image: $image) {
images {
url
original_url
safe
score
model
created_at
}
}
}

uploadImageFromUrl​

Upload an image from a URL:

mutation UploadImageFromUrl($image: UploadImageFromUrlInput!) {
uploadImageFromUrl(image: $image) {
images {
url
original_url
safe
score
}
}
}

uploadJsonToIpfs​

Upload JSON metadata:

mutation UploadJsonToIpfs($json: jsonb!) {
uploadJsonToIpfs(json: $json) {
hash
name
size
}
}

Complete Workflow Example​

Here's how to prepare metadata for atom creation:

import { GraphQLClient } from 'graphql-request';
import { PIN_API_URL } from '@0xintuition/graphql';
import { createAtomFromIpfsUri } from '@0xintuition/sdk';

const pinClient = new GraphQLClient(PIN_API_URL, {
headers: {
apikey: process.env.INTUITION_PIN_API_KEY!,
},
});

// Step 1: Upload image to IPFS (via GraphQL)
const imageResult = await pinClient.request(
`
mutation UploadImageFromUrl($image: UploadImageFromUrlInput!) {
uploadImageFromUrl(image: $image) {
images {
url
}
}
}
`,
{ image: { url: 'https://example.com/logo.png' } },
);

// Step 2: Upload metadata to IPFS (via GraphQL)
const metadataResult = await pinClient.request(
`
mutation PinThing($thing: PinThingInput!) {
pinThing(thing: $thing) {
uri
}
}
`,
{
thing: {
name: 'My Project',
description: 'Description of my project',
image: imageResult.uploadImageFromUrl.images[0].url,
url: 'https://example.com',
},
},
);

// Step 3: Create atom on-chain (via SDK)
const atom = await createAtomFromIpfsUri(
{ walletClient, publicClient, address },
metadataResult.pinThing.uri,
);

Best Practices​

1. Complete Metadata​

Provide all required metadata fields for better discoverability:

const thing = {
name: 'Project Name', // Required
description: 'Full description', // Required
image: 'ipfs://...', // Required
url: 'https://...', // Required
};

2. Use IPFS URLs​

Always reference images using IPFS URLs for permanence:

// Good - permanent
image: 'ipfs://QmXnnyufdzAWL5CqZ2RnSNgPbvCc1ALT73s6epPrRnZ1Xy';

// Avoid - may change
image: 'https://example.com/image.png';

3. Error Handling​

try {
const result = await pinClient.request(UPLOAD_IMAGE, { image: input });
console.log('Uploaded:', result.uploadImage.images[0].url);
} catch (error) {
if (error.message.includes('File too large')) {
console.error('Image exceeds size limit');
} else if (error.message.includes('Invalid')) {
console.error('Invalid image format');
}
}

4. Size Limits​

Upload TypeMaximum Size
Image (base64)5 MB
Image from URL10 MB
JSON1 MB

TypeScript Integration​

Use the @0xintuition/graphql package for type-safe pinning on the server:

requestPinThing accepts the generated package variable shape directly (name, description, image, url). Raw GraphQL requests use the thing input wrapper shown in the mutation examples above.

import { configureClient, requestPinThing } from '@0xintuition/graphql';

configureClient({
pinApiKey: process.env.INTUITION_PIN_API_KEY,
});

const ipfsUri = await requestPinThing({
name: 'My Project',
description: 'Description of my project',
image: 'https://example.com/logo.png',
url: 'https://example.com',
});

For browser apps, proxy pinning through a server route so the API key is not exposed to users.