Flap IPFS Gateway

Token metadata, token images and Vault UI assets are stored on IPFS. Flap serves them through its own gateway:

https://flap.mypinata.cloud/ipfs/<CID>

Flap's indexer and many terminals fetch files only through this gateway, so a file must be pinned by Flap before it can be used: if it is not, the indexer cannot read your token's metadata and terminals cannot show its image. Flap also warms the CDN on upload, so pinned files load quickly.

There are two ways to get content onto the Flap gateway:

You haveUseResult
An image and token details that are not on IPFS yetUpload token metadata and imageOne call uploads both and returns the metadata CID
A file or directory already on public IPFSPin existing IPFS contentFlap pins the existing CID

Upload token metadata and image

Upload the token image and its metadata together in one call. The API pins the image, writes a metadata JSON that points to it, pins that JSON, and returns the metadata CID. Pass that CID as the meta field when you launch the token.

POST https://funcs.flap.sh/api/upload
Content-Type: multipart/form-data

The endpoint is a GraphQL API that follows the GraphQL multipart request format. The form has three parts:

PartContent
operationsThe create mutation and its variables, as JSON. variables.file is null; it is filled in from part 0.
map{"0": ["variables.file"]}: maps the file part to variables.file.
0The image file.
mutation Create($file: Upload!, $meta: MetadataInput!) {
  create(file: $file, meta: $meta)
}

meta holds the token's details: description, website, twitter, telegram and creator (pass null for fields you don't use). The token name and symbol are not part of it; they are set on-chain when the token is launched.

Example with cURL:

curl --request POST "https://funcs.flap.sh/api/upload" \
  -F 'operations={"query":"mutation Create($file: Upload!, $meta: MetadataInput!) { create(file: $file, meta: $meta) }","variables":{"file":null,"meta":{"description":"My token","website":"https://example.com","twitter":null,"telegram":null,"creator":"0x0000000000000000000000000000000000000000"}}}' \
  -F 'map={"0":["variables.file"]}' \
  -F '0=@./image.png;type=image/png'

Example (TypeScript):

async function uploadTokenMeta(cfg: {
    buy: string | null;
    creator: string;
    description: string;
    sell: string | null;
    telegram: string | null;
    twitter: string | null;
    website: string | null;
    image_path: string;
}) {
    const form = new FormData();

    const MUTATION_CREATE = `
    mutation Create($file: Upload!, $meta: MetadataInput!) {
      create(file: $file, meta: $meta)
    }
    `;

    form.append(
        "operations",
        JSON.stringify({
            query: MUTATION_CREATE,
            variables: {
                file: null, meta: {
                    website: cfg.website,
                    twitter: cfg.twitter,
                    telegram: cfg.telegram,
                    description: cfg.description,
                    creator: "0x0000000000000000000000000000000000000000",
                }
            },
        })
    );

    form.append(
        "map",
        JSON.stringify({
            "0": ["variables.file"],
        })
    );

    const file = new File([fs.readFileSync(cfg.image_path)], "image.png", {
        type: "image/png",
    });
    form.append("0", file);

    const res = await axios.postForm("https://funcs.flap.sh/api/upload", form, {
        headers: {
            "Content-Type": "multipart/form-data",
        },
    });

    if (res.status !== 200) {
        throw new Error(`failed to upload the token meta: ${res.statusText}`);
    }

    const cid = res.data.data.create;
    return cid;
}

The response contains the metadata CID:

{ "data": { "create": "bafkrei..." } }

The metadata JSON stored at that CID references the image by its own CID, for example:

{
  "name": "",
  "symbol": "",
  "description": "My token",
  "image": "bafkrei...",
  "website": "https://example.com",
  "twitter": "",
  "telegram": "",
  "github": "",
  "youtube": "",
  "debox": "",
  "buy": "",
  "sell": "",
  "creator": "0x0000000000000000000000000000000000000000"
}

Both the metadata and the image load through the Flap gateway right away: https://flap.mypinata.cloud/ipfs/<metadata CID> and https://flap.mypinata.cloud/ipfs/<image CID>.

Always upload through this API, or pin through Flap (below). A file pinned only on another IPFS provider is not available to Flap's indexer and gateway.

Pin existing IPFS content

Use the Flap Pin By CID API when a file or directory is already available on Public IPFS but is not yet retained by the Flap Pinata account. After the pin finishes, Flap applications and approved Vault UIs can load the content through the Flap IPFS gateway.

This API imports an existing CID. It does not upload local files or create a CID for you. To upload a new token image and metadata, use Upload token metadata and image instead.

The production endpoint is available only after the corresponding Flap Edge Functions release has been deployed. If the endpoint returns an HTML 404 page, contact Flap; that response is not a CID validation result.

When to use this API

Use it when:

  • You already have a public IPFS CID.
  • The content works through its original IPFS provider but the Flap gateway reports that it is not pinned by the gateway owner.
  • A custom Vault UI needs an immutable image that must be available through the Flap gateway.

Requirements

Before submitting a request:

  • Confirm that the content is available on Public IPFS.
  • Copy the complete raw CID exactly as returned by the original provider.
  • Keep the original provider pin active until Flap reports pinned and the content works through the Flap gateway.
  • Submit only a raw CIDv0 or base32 CIDv1 value.

Do not submit an ipfs:// URI, a gateway URL, or a path below the CID.

# Valid
bafy...
Qm...

# Invalid
ipfs://bafy...
https://example-gateway.com/ipfs/bafy...
bafy.../image.webp

Submit a CID

POST https://funcs.flap.sh/api/v1/ipfs/pins
Content-Type: application/json

The public endpoint does not require a caller API key. Flap's Pinata credential remains on the server and must never be included in a request.

Request body:

{
  "cid": "bafy...wejvfy",
  "name": "vault-ui-hero-image"
}

The CID above is intentionally shortened for documentation. Replace it with the complete raw CID returned by your IPFS provider when making a request.

  • cid is required.
  • name is optional and is used only as an operator-friendly Pinata label.

Example with cURL:

curl --request POST \
  --url "https://funcs.flap.sh/api/v1/ipfs/pins" \
  --header "Content-Type: application/json" \
  --data '{
    "cid": "YOUR_CID_HERE",
    "name": "vault-ui-hero-image"
  }'

The API returns 202 Accepted while Pinata is processing a new request. If the CID is already pinned or already being processed, the API returns the existing result instead of creating a duplicate job. A CID that is already pinned returns 200 OK.

Example response:

{
  "data": {
    "cid": "bafy...wejvfy",
    "status": "queued",
    "providerStatus": "prechecking",
    "jobId": "00000000-0000-0000-0000-000000000000",
    "name": "vault-ui-hero-image"
  },
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Check the pin status

GET https://funcs.flap.sh/api/v1/ipfs/pins?cid=<CID>

Example:

curl --get \
  --url "https://funcs.flap.sh/api/v1/ipfs/pins" \
  --data-urlencode "cid=YOUR_CID_HERE"

The stable Flap statuses are:

StatusMeaning
queuedPinata is prechecking the CID.
retrievingPinata found the content and is retrieving it.
processingPinata is still processing the request.
pinnedThe content is retained by the Flap Pinata account.
failedPinata could not complete the request. Check errorCode.
not_foundFlap has no active or completed Pinata record for the CID.

Pinning is asynchronous. Poll at a reasonable interval and do not treat the initial 202 response as completion.

Verify through the Flap gateway

After the status becomes pinned, verify the content through the Flap gateway:

# Single file
https://flap.mypinata.cloud/ipfs/<CID>

# File inside a pinned directory
https://flap.mypinata.cloud/ipfs/<DIRECTORY_CID>/<FILE_PATH>

Only remove the original provider pin after at least one real file has loaded successfully through the Flap gateway.

Files and directories

  • For one existing image, submit its image CID once.
  • For an existing IPFS directory, submit the directory CID once. Do not submit every file path below it.
  • If every image has a separate CID, each CID is a separate Pin request; this API does not combine them into a directory.

Browser and server usage

The endpoint is public but does not enable wildcard browser CORS. Call it from a command-line client or your server, not directly from arbitrary browser JavaScript.

Troubleshooting

ResultAction
400 INVALID_REQUESTCopy the complete raw CID again. Remove any gateway URL, ipfs:// prefix, or file path.
413 REQUEST_TOO_LARGESend only the small JSON body containing cid and optional name. Do not upload file bytes to this endpoint.
status: failedInspect errorCode and confirm the original provider still serves the content on Public IPFS.
502, 503, or 504The upstream Pinata service rejected, rate-limited, or timed out. Retry later.
The endpoint itself returns an HTML 404 pageThe deployed Flap Edge Functions release does not include this API yet. Contact Flap before retrying.
The Flap gateway still cannot load the contentWait until the API reports pinned, then verify the exact CID and optional directory path again.