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 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 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β
| Mutation | Description | Documentation |
|---|---|---|
pinThing | Pin Thing metadata to IPFS | Pin Thing |
pinPerson | Pin Person metadata to IPFS | Pin Person |
pinOrganization | Pin Organization metadata to IPFS | Pin Organization |
uploadImage | Upload base64 image to IPFS | Upload Image |
uploadImageFromUrl | Upload image from URL to IPFS | Upload from URL |
uploadJsonToIpfs | Upload JSON metadata to IPFS | Upload JSON |
Chart and PnL operations are queries, not mutations. See:
- PnL Queries - Profit & Loss tracking
- Chart Queries - Chart generation
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 Type | Maximum Size |
|---|---|
| Image (base64) | 5 MB |
| Image from URL | 10 MB |
| JSON | 1 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.
Related Resourcesβ
- PnL Queries - Profit & Loss tracking
- Chart Queries - Chart generation
- SDK Documentation - On-chain operations
- GraphQL Reads - Query documentation