# Generating an asset

This guide creates a board, generates an image, waits for the result and places it on the board. Every call takes the workspace id from [`GetWorkspace`](https://app.plentylabs.com/api/playground?op=GetWorkspace) and a key from that workspace; see [Authentication](https://plentylabs.com/developers/authentication). Each step shows the published operation document, which you can run as is from the playground or your own code.

## 1. Create a board

Create a board to hold the result, or pick one from [`ListBoards`](https://app.plentylabs.com/api/playground?op=ListBoards). Keep the id of its first page: card operations take a page `id`, not the board `id`.

```graphql
mutation CreateBoard(
  $workspaceId: ID!
  $title: String
  $visibility: BoardVisibility
) {
  createBoard(input: { workspaceId: $workspaceId, title: $title, visibility: $visibility }) {
    success
    board {
      id
      title
      visibility
      createdAt
      pages(first: 1) {
        edges {
          node {
            id
            title
          }
        }
      }
    }
  }
}
```

## 2. Generate an image

Generation returns at once, with each image in status `QUEUED`. Keep the image ids. Credits are charged when the mutation is accepted and refunded if the generation fails.

```graphql
mutation GenerateImage(
  $workspaceId: ID!
  $prompt: String!
  $aspectRatio: String!
  $count: Int = 1
  $model: String
  $quality: String
  $resolution: String
  $referenceImages: [ReferenceImageInput!]
  $camera: ImageCameraInput
  $parentImageId: ID
) {
  generateImage(
    workspaceId: $workspaceId
    input: {
      prompt: $prompt
      aspectRatio: $aspectRatio
      count: $count
      model: $model
      quality: $quality
      resolution: $resolution
      referenceImages: $referenceImages
      camera: $camera
      parentImageId: $parentImageId
    }
  ) {
    success
    images {
      id
      status
      url
      aspectRatio
      model
      prompt
    }
  }
}
```

## 3. Get the result

Poll each id until `status` is `COMPLETED` or `FAILED`. Wait 5 seconds before the first poll, then 10, 15 and 20 seconds between polls. A `FAILED` image has an `errorMessage` that says why.

```graphql
query GetAsset(
  $id: ID!
) {
  image: asset(id: $id) {
    ... on Image {
      id
      displayName
      status
      progress
      url
      downloadUrl
      errorMessage
      aspectRatio
      prompt
      width
      height
    }
  }
  video: asset(id: $id) {
    ... on Video {
      id
      displayName
      name
      status
      progress
      videoUrl
      thumbnailUrl
      downloadUrl
      thumbnailDownloadUrl
      errorMessage
      aspectRatio
      duration
      prompt
      model
      draftExpiresAt
    }
  }
  audio: asset(id: $id) {
    ... on Audio {
      id
      displayName
      name
      source
      status
      progress
      url
      downloadUrl
      errorMessage
      durationMs
      model
      musicProvider
      createdAt
    }
  }
}
```

`downloadUrl` is a signed link that works for one hour without signing in. Fetch the asset again for a fresh link.

## 4. Place it on the board

A generated image lands in the workspace library, not on a board. Place it on the page from step 1. Without coordinates, the server places it on clear canvas.

```graphql
mutation PlaceCards(
  $pageId: ID!
  $workspaceId: ID!
  $cards: [CreateCanvasCardsEntryInput!]!
) {
  createCanvasCards(input: { pageId: $pageId, workspaceId: $workspaceId, cards: $cards }) {
    success
    ids
  }
}
```

## Video and audio

[`GenerateVideo`](https://app.plentylabs.com/api/playground?op=GenerateVideo), [`GenerateMusic`](https://app.plentylabs.com/api/playground?op=GenerateMusic), [`GenerateVoiceover`](https://app.plentylabs.com/api/playground?op=GenerateVoiceover) and [`GenerateVideoSfx`](https://app.plentylabs.com/api/playground?op=GenerateVideoSfx) work the same way: the result starts `QUEUED`, and you poll it with [`GetAsset`](https://app.plentylabs.com/api/playground?op=GetAsset) until it is `COMPLETED` or `FAILED`. Video takes longer than images, so widen the polling interval.
