{"id":31027191,"url":"https://github.com/rizome-dev/go-upwork","last_synced_at":"2026-06-30T05:31:30.168Z","repository":{"id":301280343,"uuid":"1008707017","full_name":"rizome-dev/go-upwork","owner":"rizome-dev","description":"pure go upwork.com sdk","archived":false,"fork":false,"pushed_at":"2025-07-01T21:03:47.000Z","size":204,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-09T02:17:31.869Z","etag":null,"topics":["golang","sdk","upwork"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/rizome-dev/go-upwork","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rizome-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-26T01:17:34.000Z","updated_at":"2025-07-16T16:05:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"5f292e30-35c3-4271-9fd8-582e0a29a168","html_url":"https://github.com/rizome-dev/go-upwork","commit_stats":null,"previous_names":["rizome-dev/go-upwork"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rizome-dev/go-upwork","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizome-dev%2Fgo-upwork","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizome-dev%2Fgo-upwork/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizome-dev%2Fgo-upwork/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizome-dev%2Fgo-upwork/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rizome-dev","download_url":"https://codeload.github.com/rizome-dev/go-upwork/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizome-dev%2Fgo-upwork/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34954283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","sdk","upwork"],"created_at":"2025-09-13T18:57:15.401Z","updated_at":"2026-06-30T05:31:30.161Z","avatar_url":"https://github.com/rizome-dev.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Upwork Go SDK\n\n[![GoDoc](https://pkg.go.dev/badge/github.com/rizome-dev/go-upwork)](https://pkg.go.dev/github.com/rizome-dev/go-upwork)\n[![Go Report Card](https://goreportcard.com/badge/github.com/rizome-dev/go-upwork)](https://goreportcard.com/report/github.com/rizome-dev/go-upwork)\n\n```shell\ngo get github.com/rizome-dev/go-upwork\n```\n\nbuilt by: [rizome labs](https://rizome.dev)\n\ncontact us: [hi (at) rizome.dev](mailto:hi@rizome.dev)\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \n    \"github.com/rizome-dev/go-upwork/pkg\"\n)\n\nfunc main() {\n    // Create client configuration\n    config := \u0026pkg.Config{\n        ClientID:     \"your-client-id\",\n        ClientSecret: \"your-client-secret\",\n        RedirectURL:  \"your-redirect-url\",\n    }\n    \n    // Create client\n    ctx := context.Background()\n    client, err := pkg.NewClient(ctx, config)\n    if err != nil {\n        log.Fatal(err)\n    }\n    \n    // Get authorization URL\n    authURL := client.GetAuthURL(\"state\")\n    fmt.Println(\"Visit:\", authURL)\n    \n    // Exchange authorization code for token\n    token, err := client.ExchangeCode(ctx, \"auth-code\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    \n    // Use the authenticated client\n    user, err := client.Users.GetCurrentUser(ctx)\n    if err != nil {\n        log.Fatal(err)\n    }\n    \n    fmt.Printf(\"Hello, %s!\\n\", user.Name)\n}\n```\n\n## Core Services\n\n### Authentication\n\n```go\n// OAuth2 Authorization Code Flow\nauthURL := client.GetAuthURL(\"state\")\ntoken, err := client.ExchangeCode(ctx, \"code\")\n\n// Refresh token\nnewToken, err := client.RefreshToken(ctx)\n\n// Service Account (Enterprise)\nconfig.ServiceAccount = true\n```\n\n### Users \u0026 Organizations\n\n```go\n// Get current user\nuser, err := client.Users.GetCurrentUser(ctx)\n\n// Get user by ID\nuser, err := client.Users.GetUserByID(ctx, \"user-id\")\n\n// Get organization\norg, err := client.Users.GetOrganization(ctx)\n\n// List companies\ncompanies, err := client.Users.GetCompanySelector(ctx)\n```\n\n### Contracts \u0026 Milestones\n\n```go\n// List contracts\ncontracts, err := client.Contracts.ListContracts(ctx, api.ListContractsInput{\n    Filter: \u0026api.ContractFilter{\n        Status: []api.ContractStatus{api.ContractStatusActive},\n    },\n})\n\n// Create milestone\nmilestone, err := client.Contracts.CreateMilestone(ctx, api.CreateMilestoneInput{\n    ContractID:    \"contract-id\",\n    Description:   \"Milestone 1\",\n    DepositAmount: \"1000.00\",\n    DueDate:       \"2024-12-31\",\n})\n\n// End contract\nerr = client.Contracts.EndContractAsClient(ctx, api.EndContractInput{\n    ContractID: \"contract-id\",\n    Reason:     \"Work completed\",\n})\n```\n\n### Job Postings\n\n```go\n// Search jobs\njobs, err := client.Jobs.SearchJobs(ctx, api.MarketplaceJobFilter{\n    SearchExpression: \"golang developer\",\n    JobType:         api.ContractTypeHourly,\n    DaysPosted:      7,\n})\n\n// Create job posting\njob, err := client.Jobs.CreateJobPosting(ctx, api.CreateJobPostingInput{\n    Title:        \"Go Developer Needed\",\n    Description:  \"Looking for experienced Go developer\",\n    CategoryID:   \"category-id\",\n    Skills:       []string{\"golang\", \"api\"},\n    ContractType: api.ContractTypeHourly,\n})\n```\n\n### Messaging\n\n```go\n// List rooms\nrooms, err := client.Messages.ListRooms(ctx, \u0026api.RoomFilter{\n    UnreadRoomsOnly: true,\n}, nil, api.SortOrderDesc)\n\n// Send message\nstory, err := client.Messages.SendMessage(ctx, api.CreateStoryInput{\n    RoomID:  \"room-id\",\n    Message: \"Hello!\",\n})\n\n// Create room\nroom, err := client.Messages.CreateRoom(ctx, api.CreateRoomInput{\n    RoomName: \"Project Discussion\",\n    RoomType: api.RoomTypeGroup,\n    Users: []api.RoomUserInput{\n        {UserID: \"user1\", OrganizationID: \"org1\"},\n        {UserID: \"user2\", OrganizationID: \"org1\"},\n    },\n})\n```\n\n### Reports \u0026 Analytics\n\n```go\n// Get time reports\nreports, err := client.Reports.GetTimeReport(ctx, api.TimeReportInput{\n    OrganizationID: \"org-id\",\n    DateRange: api.DateRange{\n        Start: time.Now().AddDate(0, -1, 0),\n        End:   time.Now(),\n    },\n})\n\n// Get work diary\ndiary, err := client.Reports.GetWorkDiaryByCompany(ctx, \"company-id\", \"2024-01-15\")\n```\n\n### Freelancer Profiles\n\n```go\n// Search freelancers\nresults, err := client.Freelancers.SearchFreelancers(ctx, api.SearchFreelancersInput{\n    Skills:     []string{\"golang\", \"python\"},\n    Countries:  []string{\"US\", \"CA\"},\n    TopRated:   true,\n    HourlyRate: \u0026api.RangeFilter{Min: 50, Max: 150},\n})\n\n// Get profile\nprofile, err := client.Freelancers.GetFreelancerProfile(ctx, \"profile-key\")\n```\n\n## Advanced Features\n\n### Concurrent Operations\n\n```go\n// Batch operations using goroutines\nvar wg sync.WaitGroup\nerrors := make(chan error, 3)\n\nwg.Add(3)\ngo func() {\n    defer wg.Done()\n    if _, err := client.Users.GetCurrentUser(ctx); err != nil {\n        errors \u003c- err\n    }\n}()\n\ngo func() {\n    defer wg.Done()\n    if _, err := client.Contracts.ListContracts(ctx, input); err != nil {\n        errors \u003c- err\n    }\n}()\n\ngo func() {\n    defer wg.Done()\n    if _, err := client.Messages.ListRooms(ctx, nil, nil, \"\"); err != nil {\n        errors \u003c- err\n    }\n}()\n\nwg.Wait()\nclose(errors)\n```\n\n### Error Handling\n\n```go\n// Check for specific error types\nif err != nil {\n    var apiErr *errors.APIError\n    if errors.As(err, \u0026apiErr) {\n        if apiErr.IsRateLimited() {\n            // Handle rate limiting\n        } else if apiErr.IsUnauthorized() {\n            // Refresh token\n        }\n    }\n}\n```\n\n### Custom HTTP Client\n\n```go\n// Use custom HTTP client with proxy\nhttpClient := \u0026http.Client{\n    Timeout: 60 * time.Second,\n    Transport: \u0026http.Transport{\n        Proxy: http.ProxyURL(proxyURL),\n    },\n}\n\nconfig := \u0026pkg.Config{\n    HTTPClient: httpClient,\n    // ... other config\n}\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\nexport UPWORK_CLIENT_ID=your-client-id\nexport UPWORK_CLIENT_SECRET=your-client-secret\nexport UPWORK_REDIRECT_URL=http://localhost:8080/callback\n```\n\n### Organization Context\n\n```go\n// Set default organization\nclient.SetOrganizationID(\"org-id\")\n\n// Or use per-request context\nctx = context.WithValue(ctx, \"org-id\", \"different-org-id\")\n```\n\n## Project Structure\n\n```\ngo-upwork/\n├── pkg/                  # Public API package\n│   ├── client.go         # Main client implementation\n│   ├── auth/             # OAuth2 authentication\n│   ├── errors/           # Error types and handling\n│   ├── models/           # Shared data models\n│   └── services/         # API service implementations\n├── internal/             # Internal packages\n│   ├── graphql/          # GraphQL client internals\n│   └── ratelimit/        # Rate limiting implementation\n├── cmd/upwork-cli/       # CLI tool\n├── examples/             # Usage examples\n└── docs/                 # Additional documentation\n```\n\n## Testing\n\nThe SDK includes a comprehensive test suite with unit tests, integration tests, and benchmarks.\n\n### Quick Testing\n\n```bash\n# Run all tests\nmake test\n\n# Run tests with coverage\nmake test-coverage\n\n# Run unit tests only\nmake test-unit\n\n# Run integration tests\nmake test-integration\n\n# Run with race detector\nmake test-race\n\n# Run benchmarks\nmake test-bench\n```\n\n### Test Categories\n\n1. **Unit Tests** - Test individual components in isolation using mocks\n2. **Integration Tests** - Test against the real Upwork API (requires credentials)\n3. **Race Tests** - Detect concurrent access issues\n4. **Benchmarks** - Performance testing\n\n### Coverage Goals\n\n- Overall Coverage: \u003e80%\n- Critical Paths: 100% (authentication, error handling)\n- Service Layer: \u003e90%\n\n### Running Specific Tests\n\n```bash\n# Run specific test\nmake test-specific TEST=TestOAuth2\n\n# Test specific package\nmake test-package PKG=./pkg/services\n\n# With verbose output\ngo test -v ./pkg/auth/...\n\n# Integration tests (requires API credentials)\ngo test -tags=integration ./tests/integration/...\n```\n\n### Test Environment Setup\n\nFor integration tests, set these environment variables:\n\n```bash\nexport UPWORK_CLIENT_ID=your-client-id\nexport UPWORK_CLIENT_SECRET=your-client-secret\nexport UPWORK_ACCESS_TOKEN=your-access-token\nexport UPWORK_REFRESH_TOKEN=your-refresh-token\nexport UPWORK_ORGANIZATION_ID=your-org-id\n```\n\n### Continuous Integration\n\nTests run automatically on:\n- Pull requests\n- Pushes to main branch\n- Daily schedule\n\nSee [TESTING.md](TESTING.md) for detailed testing documentation.\n\n## Examples\n\nSee the [examples](examples/) directory for more detailed usage examples:\n\n- [Basic Usage](examples/basic_usage.go) - Authentication and basic operations\n- [Concurrent Operations](examples/concurrent.go) - Parallel API calls\n- [Job Management](examples/jobs.go) - Creating and managing job postings\n- [Messaging](examples/messaging.go) - Room and message management\n- [Reports](examples/reports.go) - Analytics and reporting\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Support\n\n- 📖 [API Documentation](https://www.upwork.com/developer/documentation/graphql/api/docs/index.html)\n- 💬 [Stack Overflow](https://stackoverflow.com/questions/tagged/upwork-api)\n- 🐛 [Issue Tracker](https://github.com/rizome-dev/go-upwork/issues)\n\n## Acknowledgments\n\n- Built with concurrent design patterns for optimal performance\n- Follows Go best practices and idioms\n- Comprehensive GraphQL support for modern API interactions\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frizome-dev%2Fgo-upwork","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frizome-dev%2Fgo-upwork","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frizome-dev%2Fgo-upwork/lists"}