# Getting started with the Go SDK

Install the SDK, submit your first job, and poll it to completion — the submit-and-poll loop every VEED model shares.

Every VEED model works the same way: you submit a job, the API accepts it
immediately, and you poll until it is done. This guide walks that loop end to
end in Go, using Fabric 1.0 as the example —
swap the client method and the inputs and the shape is identical for every other
model.

## Install

```bash
go get github.com/veedstudio/veed-sdk-go
```

The client reads `VEED_API_KEY` from the environment, so export the workspace key
you created in the dashboard:

```bash
export VEED_API_KEY="vp_..."
```

## The whole loop

```go
package main

import (
	"context"
	"fmt"
	"log"

	veed "github.com/veedstudio/veed-sdk-go"
)

func main() {
	client, err := veed.NewClient() // reads VEED_API_KEY
	if err != nil {
		log.Fatal(err)
	}

	job, err := client.Fabric.Generate(context.Background(), veed.FabricInput{
		AudioURL:   "https://static-assets.veed.io/api-examples/fabric-input.mp3",
		ImageURL:   "https://static-assets.veed.io/api-examples/fabric-input.png",
		Resolution: "720p",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", job.Result)
}
```

`Generate` submits the job and polls for you, honouring the interval the API
advertises (`10` seconds for
this model), so you do not write a retry loop by hand. It takes a
`context.Context`, so a timeout or a cancelled request stops the polling too.

## What this model takes

- `image_url` · url · required — URL of the source image to animate.
- `audio_url` · url · required — URL of the audio track to lip-sync to.
- `resolution` · enum · required — Output video resolution. Accepts `720p`, `480p`.

Both URLs must be publicly reachable over http(s) — the renderer fetches them
itself, so a signed URL is fine but a localhost address is not.

`resolution` accepts `720p, 480p`.
It is required, and the reference and playground both show `720p` as the
example, which is the resolution most callers want.

## Submitting and polling by hand

If you would rather drive the two calls yourself — a worker that persists the job
id across restarts, say — they are the two endpoints `Generate` wraps:

`POST /v1/fabric-1.0` — [reference](https://api.veed.io/docs/api/post-v1-fabric-1-0.md)

```go
package main

import (
	"context"
	"fmt"
	"log"

	veed "github.com/veedstudio/veed-sdk-go"
)

func main() {
	client, err := veed.NewClient() // reads VEED_API_KEY
	if err != nil {
		log.Fatal(err)
	}

	job, err := client.Fabric.Submit(context.Background(), veed.FabricInput{
		AudioURL:   "https://static-assets.veed.io/api-examples/fabric-input.mp3",
		ImageURL:   "https://static-assets.veed.io/api-examples/fabric-input.png",
		Resolution: "720p",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(job.Status)
}
```

`GET /v1/fabric-1.0/{job_id}` — [reference](https://api.veed.io/docs/api/get-v1-fabric-1-0-job-id.md)

```go
package main

import (
	"context"
	"fmt"
	"log"

	veed "github.com/veedstudio/veed-sdk-go"
)

func main() {
	client, err := veed.NewClient() // reads VEED_API_KEY
	if err != nil {
		log.Fatal(err)
	}

	job, err := client.Fabric.Get(context.Background(), "<job_id>")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(job.Status)
}
```

The job envelope is the same either way:

- `credits_charged` · integer · optional — Credits charged for the job. Present once the job is COMPLETED and the final charge is known.
- `credits_estimated` · integer · optional — Credits quoted before the job ran. Present only on the response that created the job. This is an estimate, not the price: the charged amount can be higher or lower.
- `error` · object · optional — Failure information. Present once the job has FAILED.
- `job_id` · uuid · required — Stable identifier of the job and of the resource it produces.
- `result` · object · optional — The produced resource. Present once the job is COMPLETED.
- `status` · enum · required — Current lifecycle state of the job. Accepts `PROCESSING`, `COMPLETED`, `FAILED`, `CANCELLED`.

`Status` moves through `PROCESSING, COMPLETED, FAILED, CANCELLED`. Only
`COMPLETED` carries a `Result`; only `FAILED` carries an `Error`.

## When a job fails

An accepted job can still fail while rendering, and the failure is reported on
the poll response rather than as a transport error — so `err` will be `nil` and
`job.Status` will be `FAILED`. Check both. The codes this model can return are `input_validation, content_moderation, invalid_file, audio_too_long, transload_failed, generation_failed, timeout`.

Treat anything other than `COMPLETED` and `PROCESSING` as terminal: a
`CANCELLED` or `FAILED` job will not change state again, and polling it further
only burns rate limit.

## What it costs

It costs $0.08–$0.15 per second of the generated video, billed on the output rather
than on the source image. The [pricing page](https://api.veed.io/pricing) breaks that down per
resolution.

## Next

- Try the same inputs in the playground before you write any code
- Every other model follows this submit-and-poll shape — the reference pages
list the inputs each one takes
